使用 free() 释放内存会使整个 C 程序不打印任何分配的数据?

Deallocating the Memory Using free() makes the entire C program not print any allocated data?

C 中的指针对我来说是一个非常难的科目。这是我作业中代码的一部分,它重现了我遇到的问题。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <crtdbg.h>

#define MAX_SONGS_PER_USER   10
#define MAX_USERS             5
#define MAX_ARTISTS         100


#define NUM_TEST_USERS      7


// This struct represents a song in the system
typedef struct {
    char      *title;
    char      *artist;
    short int  duration;
    char        downloaded;
} Song;

// This struct represents a user in the system
typedef struct {
    char       *name;
    char        online;                    // 1 = YES, 0 = NO
    Song       *songs[MAX_SONGS_PER_USER]; // songs this user has
    short int   numSongs;                  // number of songs this user has
} User;

// This structure represents the Tune Share system
typedef struct {
    User        *users[MAX_USERS];     // An array of all registered users
    short int    numUsers;
} TuneShare;

int registerUser(TuneShare *t, char *name)
{
    short int numUsers = t->numUsers;

    if (numUsers == MAX_USERS)
    {
        return 0;
    }
    else
    {
        if(numUsers >= 1)
            //printf("%s \n", t->users[0]->name);
        for (int i = 0; i < numUsers; i++)
        {
            User *u = t->users[i];
            char *uName = u->name;
            if (uName == name)
            {
                return 0;
            }
            //free(u);
        }
        User *temp;
        if ((temp = malloc(sizeof *temp)) != NULL)
        {
            temp->name = name;
            temp->numSongs = 0;
            temp->online = '0';
        }
        
        t->users[numUsers] = temp;

        t->numUsers = numUsers + 1;

        return 1;
    }
}

int addSong(User *u, char *title, char *artist, short int duration)
{
    short int numSongs = u->numSongs;
    if (numSongs == MAX_SONGS_PER_USER)
    {
        return 0;
    }
    else
    {
        if (numSongs >= 1)
            for (int i = 0; i < numSongs; i++)
            {
                if (u->songs[i]->title == title)
                {
                    return 0;
                }
            }
        Song *temp;
        if ((temp = malloc(sizeof *temp)) != NULL)
        {
            temp->title = title;
            temp->artist = artist;
            temp->duration = duration;
        }
        u->songs[numSongs] = temp;
        u->numSongs = numSongs + 1;
        //free(temp);
        return 1;
    }
}

void logon(TuneShare *t, char *name)
{
    User *u = userWithName(t, name);
    
    if (u != NULL)
    {
        u->online = '1';
    }
}

void displayStats(TuneShare *t)
{
    printf("\nTune Share Center (%d registered users)\n", t->numUsers);
    short int numOnline = 0, numSongs = 0;
    User **u = onlineUsers(t, &numOnline);
    Song **s = allAvailableSongs(t, &numSongs);


    printf("\n%d Online Users:\n", numOnline);
    if (numOnline == 0)
    {
        printf("\tNONE\n\n");
    }
    else
    {
        for (int i = 0; i < numOnline; i++)
        {
            printf("\t%s with %d songs as follows:\n", u[i]->name, u[i]->numSongs);
            for (int j = 0; j < u[i]->numSongs; j++)
            {
                printf("\t\t\"%s\" by %s\n", u[i]->songs[j]->title, u[i]->songs[j]->artist);
            }
        }
    }

    printf("\n%d Available Songs:\n", numSongs);
    if (numSongs == 0)
    {
        printf("\tNONE\n\n");
    }
    else
    {
        for (int i = 0; i < numSongs; i++)
        {           
            int min = s[i]->duration / 60;
            int sec = s[i]->duration % 60;
            if(sec > 10)
                printf("\t\"%s\" by %s (%d:%d)\n", s[i]->title, s[i]->artist, min, sec);
            else
                printf("\t\"%s\" by %s (%d:0%d)\n", s[i]->title, s[i]->artist, min, sec);
        }
    }
    printf("\n");
}


int main() {
    // This is test data
    static char *TITLES[] = { "Back 2 Life", "Loneliness For Love", "Desire 126", "Perfect", "In My Head",
                             "Old Skool Love", "Let's Go", "No Place", "We Gotta Go", "How You Get the Girl",
                             "Catch", "Here Tonight", "Details", "Dangerous", "Brighter Than the Sun",
                             "Photograph", "Thinking Out Loud", "If Heaven Were to Fall", "I Just Wanna Be With You",
                             "Song Sung Blue", "Outta Style", "Why", };

    static char *ARTISTS[] = { "E-Type", "Lovely the Band", "Hollerado", "Ed Sheeran", "Ryland James",
                              "Divine Brown", "Group 1 Crew", "Backstreet Boys", "E-Type", "Taylor Swift",
                              "Brett Young", "Brett Young", "Billy Currington", "Kardinal Offichall",
                              "Colbie Caillat", "Ed Sheeran", "Ed Sheeran", "E-Type", "E-Type", "Neil Diamond",
                              "Aaron Watson", "Frankie Avalon", };

    static int   DURATIONS[] = { 217, 237, 187, 263, 205, 204, 256, 179, 213, 247, 196,
                                216, 201, 251, 231, 202, 281, 223, 230, 185, 222, 161 };


    static char *TEST_USER_NAMES[NUM_TEST_USERS] = { "Disco Stew", "Peter Punk", "Country Candy", "Ronnie Rocker",
                                                    "Sleeping Sam", "Disco Stew", "Mellow Marvin" };

    static int  LIST_SIZES[NUM_TEST_USERS] = { 7, 9, 9, 5, 1, 0, 0 };
    static int  SONGNUMS[NUM_TEST_USERS][MAX_SONGS_PER_USER] = {
                                   {1, 2, 4, 5, 12, 15, 21}, {0, 1, 3, 8, 9, 13, 14, 17, 20},
                                   {6, 7, 8, 10, 11, 12, 13, 20, 21}, {0, 8, 16, 17, 18}, {19}, {0}, {0} };


    // Create the TuneShare Center
    TuneShare   tuneShareCenter;
    tuneShareCenter.numUsers = 0;

    // Attempt to register all test users
    for (int i = 0; i < NUM_TEST_USERS; i++) {
        if (!registerUser(&tuneShareCenter, TEST_USER_NAMES[i]))
            printf("Error adding User: \"%s\"\n", TEST_USER_NAMES[i]);
        else
            printf("User: \"%s\" has been registered\n", TEST_USER_NAMES[i]);
    }
    
    // Display some stats
    displayStats(&tuneShareCenter);

    // Log on a user
    printf("\nLogging on a user...\n");
    logon(&tuneShareCenter, "Disco Stew");
    // Display some stats
    displayStats(&tuneShareCenter);

    // Now add all the test songs for these test users
    for (int i = 0; i < tuneShareCenter.numUsers; i++) {
        for (int j = 0; j < LIST_SIZES[i]; j++)
            addSong(tuneShareCenter.users[i], TITLES[SONGNUMS[i][j]], ARTISTS[SONGNUMS[i][j]], DURATIONS[SONGNUMS[i][j]]);
    }
    
    // Display some stats
    displayStats(&tuneShareCenter);

}

这给出了我需要的正确输出。像这样。

但是,当我使用 free() 函数从堆中释放分配的内存时,函数 **int registerUser(TuneShare t, char name) 它根本不给出输出,

int registerUser(TuneShare *t, char *name)
{
    short int numUsers = t->numUsers;

    if (numUsers == MAX_USERS)
    {
        return 0;
    }
    else
    {
        if(numUsers >= 1)
            //printf("%s \n", t->users[0]->name);
        for (int i = 0; i < numUsers; i++)
        {
            User *u = t->users[i];
            char *uName = u->name;
            if (uName == name)
            {
                return 0;
            }
            //free(u);
        }
        User *temp;
        if ((temp = malloc(sizeof *temp)) != NULL)
        {
            temp->name = name;
            temp->numSongs = 0;
            temp->online = '0';
        }
        
        t->users[numUsers] = temp;

        t->numUsers = numUsers + 1;
        free(temp);
        return 1;
    }

}

这是我使用 free() 时的输出。

我不明白这是什么问题。如果有人能帮助我,那就太好了。

您可能会误解的问题是,调用 free(temp) 会释放 temp 指向的内存中的对象 - 它实际上与 temp 没有任何关系变量本身。 temp 将在函数 returns 后被释放。事实上,声明 temp 本身甚至可能是不必要的。

int registerUser(TuneShare *t, char *name)
{
    int i;

    if (t->numUsers >= MAX_USERS)
        return 0;

    for (i = 0; i < t->numUsers; i++)
        if (strcmp(t->users[i]->name, name) == 0)
            return 0;

    if ((t->users[t->numUsers] = malloc(sizeof User)) == NULL)
        return 0;

    t->users[t->numUsers]->name = name;
    t->users[t->numUsers]->numSongs = 0;
    t->users[t->numUsers]->online = '0';    

    t->numUsers++;
    
    return 1;
}

释放一个指针就像从内存中擦除它的内容,所以当你释放 temp 时,你正在删除新的用户,所以 t->users(又名 tuneShareCenter.users)将充满无用的“空”用户指点。

您应该在主函数结束时释放用户,释放 tuneShareCenter 和歌曲,例如:

for (int i = 0; i < tuneShareCenter.numUsers; i++) {
    User* tUser = tuneShareCenter.users[i];
    for(int j = 0; j < tUser->numSongs; j++){
        free(tUser->songs[j]);
    }
    free(tUser);
}
free(tuneShareCenter);

(希望我写对了)