调用 free() 有时会导致程序崩溃

Calling free() sometimes causes program to crash

下面的代码要求用户输入 10 对艺术家和标题,最长可达 30 个字符。分配 space 并重新打印数据似乎一切正常。仅当我尝试在结束时释放内存并且仅当其中一个元素的长度为 4 个或更多字符时,才会出现此问题。我怀疑我没有正确分配内存,但我看不到它。

// Songs.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
// Experimenting with pointers, structures and dynamic allocation of memory
//
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif


#include <iostream>
#include <stdio.h>

struct songInfo
{
    char* pArtist;      // char pointer for Artist data
    char* pTitle;       // char pointer for Title data
};

// function prototype declarations
void getSongInfo(struct songInfo *songData, char *Artist, char *Title);
void printSongInfo(songInfo *songData);


int main()
{
    struct  songInfo songData[10];      // setup array of 10 elements of the structure SongInfo
    char    sArtist[31];
    char    sTitle[31];

    // prompt user for the artist and title 10 times once for each array element
    for (int i = 0; i < 10; i++) {
        printf("Artist %i: ", i + 1);
        fgets(sArtist, 31, stdin);
        strtok(sArtist, "\n");          // trim out return character
        printf("Title  %i: ", i + 1);
        fgets(sTitle, 31, stdin);
        strtok(sTitle, "\n");           // trim out return character
        getSongInfo(&songData[i], sArtist, sTitle); // allocates the memory and stores the data into the pointer location
    }

    printSongInfo(songData);    // printout the song data stored in the array

    // free up the allocated memory space
    for (int i = 0; i < 10; ++i) {
        free(songData[i].pArtist);
        free(songData[i].pTitle);
}
    return 0;
}

void getSongInfo(struct songInfo *songData, char *Artist, char *Title) {
    songData->pArtist = (char*)malloc(sizeof(Artist) + 1);  // Allocate enough memory to hold the string and the null terminator
    songData->pTitle = (char*)malloc(sizeof(Title) + 1);
    strcpy(songData->pArtist, Artist);                                  // Copy the data into the allocated memory location
    strcpy(songData->pTitle, Title);
}

void printSongInfo(songInfo *songData) {
    printf("\n%-35s %-35s\n", "Artist", "Title");
    printf("%-35s %-35s\n", "-----------------------------------", "-----------------------------------");
        for (int i = 0; i < 10; i++) {      // iterate through the array of elements
        printf("%-35s %-35s\n", songData[i].pArtist, songData[i].pTitle);
    }
}

无效的不是free()调用,而是malloc

如果您打印出 sizeof(Artist) + 1,您可能会得到 59(取决于您的计算机体系结构)。 Title 也是如此。你在你的机器上检查指针的大小,它是常量,而不是你收到的数组的大小。

Undefined Behvaiour 意味着您的代码可以做任何事情,包括“暂时工作,但稍后会在正确的地方中断”。您通过调用 strcpy 来调用 UB,它会尝试将数据复制到太短而无法包含整个字符串的缓冲区中。

您必须将数组的大小传递给函数或使用函数内部的 strlen 计算它(并祈祷该字符串实际上以 null 结尾)。

void getSongInfo(struct songInfo *songData, char *Artist, char *Title) {
    songData->pArtist = (char*)malloc(strlen(Artist) + 1);  // Allocate enough memory to hold the string and the null terminator
    songData->pTitle = (char*)malloc(strlen(Title) + 1);
    strcpy(songData->pArtist, Artist);                                  // Copy the data into the allocated memory location
    strcpy(songData->pTitle, Title);
}

使用std::char_traits::length or strlensizeof(Artist) 给出的不是数组的长度,而是 char * 指针占用的字节数。

songData->pArtist =
    (char*)malloc(std::char_traits<char>::length(Artist) +
                  1);  // Allocate enough memory to hold the string and the null terminator
songData->pTitle =
    (char*)malloc(std::char_traits<char>::length(Title) +
                  1);  // Allocate enough memory to hold the string and the null terminator

附带说明:使用 std::stringstd::unique_ptrstd::shared_ptr 等智能指针可以为您省去很多处理内存问题的麻烦。总体而言,使用现代 c++ 将帮助您更高效地编写更安全的代码。