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

Calling free() sometimes causes program to crash

本文关键字:程序 崩溃 free 调用      更新时间:2023-10-16

下面的代码要求用户输入 10 对艺术家和标题,最长可达 30 个字符。分配空间并将数据打印回去似乎一切正常。仅当我尝试在结束时释放内存时,仅当其中一个元素长度为 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 %-35sn", "Artist", "Title");
printf("%-35s %-35sn", "-----------------------------------", "-----------------------------------");
for (int i = 0; i < 10; i++) {      // iterate through the array of elements
printf("%-35s %-35sn", songData[i].pArtist, songData[i].pTitle);
}
}

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

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

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

你必须传递数组的大小来函数或使用strleninside 函数来计算它(并祈祷字符串实际上是以 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 或 strlen。sizeof(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::unique_ptrstd::shared_ptrstd::string和智能指针将为您节省很多处理内存问题的麻烦。总体而言,使用新式c++将帮助您更有效地编写更安全的代码。