简体   繁体   English

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

[英]Calling free() sometimes causes program to crash

The code below ask the user to input 10 pairs of artist and titles which can be up to 30 characters long.下面的代码要求用户输入 10 对艺术家和标题,最长可达 30 个字符。 Everything seems to work fine with allocating the space and printing the data back out.分配空间和打印数据似乎一切正常。 The problem only occurs when I try to free the memory at then end and then only if one of the elements is 4 or more characters long.仅当我尝试在结束时释放内存时才会出现问题,然后仅当元素之一的长度为 4 个或更多字符时才会出现。 I suspect I am not allocating the memory correctly but I just can't see it.我怀疑我没有正确分配内存,但我看不到它。

// 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);
    }
}

It's not free() call that is invalid, it's malloc .无效的不是free()调用,而是malloc

If you'd print out sizeof(Artist) + 1 , you'd likely get either 5 or 9 (depending on your computer architecture).如果您打印sizeof(Artist) + 1 ,您可能会得到59 (取决于您的计算机架构)。 And the same for Title .Title You check the size of pointer on your machine, which is constant, not the size of array you received.您检查机器上指针的大小,它是常数,而不是您收到的数组的大小。

Undefined Behvaiour means your code may do anything, including "working for now, but will break later at a correct place". Undefined Behvaiour 意味着您的代码可以做任何事情,包括“现在可以工作,但稍后会在正确的地方中断”。 You invoke UB by calling strcpy , which tries to copy data into buffer too short to contain the whole string.您可以通过调用strcpy调用 UB,它会尝试将数据复制到太短而无法包含整个字符串的缓冲区中。

You have to pass the size of array to function or calculate it using strlen inside function (and pray that the string is actually null-terminated).您必须将数组的大小传递给函数或使用函数内部的strlen计算它(并祈祷该字符串实际上以空值结尾)。

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);
}

Use std::char_traits::length or strlen .使用std::char_traits::lengthstrlen Instead of length of the array, sizeof(Artist) gives you how many bytes a char * pointer occupies. 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

Just a side note: using std::string and smart pointers such as std::unique_ptr and std::shared_ptr would save you lots of troubles dealing with memory issues.只是一个旁注:使用std::string和智能指针,例如std::unique_ptrstd::shared_ptr可以为您节省很多处理内存问题的麻烦。 Overall, using modern c++ will help you write safer code more efficiently.总体而言,使用现代c++将帮助您更有效地编写更安全的代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM