Вызов free () иногда вызывает сбой программы - PullRequest
0 голосов
/ 18 января 2020

Приведенный ниже код просит пользователя ввести 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 %-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);
    }
}

Ответы [ 2 ]

2 голосов
/ 18 января 2020

Это не free() вызов, который является недействительным, это malloc.

Если вы распечатаете sizeof(Artist) + 1, вы, скорее всего, получите либо 5, либо 9 (в зависимости от архитектура вашего компьютера). И то же самое для Title. Вы проверяете размер указателя на вашем компьютере, который является постоянным, а не размер полученного вами массива.

Неопределенный Behvaiour означает, что ваш код может делать все что угодно, в том числе «работает на данный момент, но позже сломается с правильным место". Вы вызываете UB, вызывая strcpy, который пытается скопировать данные в буфер, слишком короткий, чтобы содержать всю строку.

Вы должны передать размер массива для функции или вычислить его, используя 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);
}
0 голосов
/ 18 января 2020

Используйте 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::string и интеллектуальных указателей, таких как std::unique_ptr и std::shared_ptr избавит вас от множества проблем с памятью. В целом, использование современного c++ поможет вам более эффективно писать безопасный код.

...