c - 即使我释放了每个 malloc,动态结构数组和链表中的内存泄漏

标签 c arrays memory valgrind

当我在项目上运行 valgrind 时,5 个分配中的 4 个没有被释放,我无法理解为什么。

我尝试取消引用并释放似乎有问题的变量。

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

    #define MAX_LINE 1000
    #define INPUT_NUM 9

    enum hobbies{BASEBALL=1, BASKETBALL, BICYCLE, BOOKS,
        DRAWING, GYM, MOVIES, POETRY};
    typedef struct User{
        char *ID, *firstName, *lastName, *userName, *password, *description;
        char sex, hobbies;
        int age;
    }User;

    typedef struct UserItem UserItem;
    struct UserItem{
        User* data;
        UserItem* next;
    };
    typedef struct{
        UserItem *head, *last;
    }UserList;

    typedef struct DynamicArray{
        int size;
        int capacity;
        User** array;
    }DynamicArray;

    typedef int(*Comparator)(User*, User);

    typedef enum {false, true} bool;


    void updateData(char *info[9], DynamicArray *dynamicArray, UserList **userList){
        //Male-Array
        if(info[4][0]=='M')
        {
            incrementArray(dynamicArray);
            dynamicArray->array[dynamicArray->size]=realloc(dynamicArray->array[dynamicArray->size],sizeof(User));
            newUser(info,dynamicArray->array[dynamicArray->size]);
            dynamicArray->size++;
        }
        //Female -Linked List
        else {
            User *user=malloc(sizeof(User));
            newUser(info,user);
            add(*userList,user);
        }
    }

    User* newUser(char* info[INPUT_NUM],User* user){
        user->ID=strdup(info[0]);
        if((user->firstName =(char*)malloc(strlen(info[1])+1))==NULL)
        {
            printf("error\n");
            exit(1);
        }
        strcpy(user->firstName,info[1]);
        if((user->lastName =(char*)malloc(strlen(info[2])+1))==NULL)
        {
            printf("error\n");
            exit(1);
        }
        strcpy(user->lastName,info[2]);
        user->age=atoi(info[3]);
        user->sex=*info[4];
        if((user->userName =(char*)malloc(strlen(info[5])+1))==NULL)
        {
            printf("error\n");
            exit(1);
        }
        strcpy(user->userName,info[5]);
        if((user->password =(char*)malloc(strlen(info[6])+1))==NULL)
        {
            printf("error\n");
            exit(1);
        }
        strcpy(user->password,info[6]);
        user->hobbies|=1<<(8-(*(info[7])-'0'));
        user->hobbies|=1<<(8-(*((info[7])+2)-'0'));
        user->hobbies|=1<<(8-(*((info[7])+4)-'0'));
        user->hobbies|=1<<(8-(*((info[7])+6)-'0'));
        if((user->description =(char*)malloc(strlen(info[8])+1))==NULL)
        {
            printf("error\n");
            exit(1);
        }
        strcpy(user->description,info[8]);
        return user;
    }

    void newUserList(UserList** list){
        *list=(UserList*)malloc(sizeof(UserList));
        if(*list==NULL){
            printf("error\n");
            exit(1);
        }
        (*list)->head=(UserItem*)malloc(sizeof(UserItem));
        (*list)->head->data=NULL;
        (*list)->head->next=NULL;
        (*list)->last=((*list)->head);
    }

    void newDynamicArray(DynamicArray *array){
        array->size=0;
        array->capacity=5;
        array->array=(User**)calloc((array->capacity),sizeof(User*));
    }


    void freeUser(User* user){
        if(user!=NULL){
            free(user->ID);
            free(user->firstName);
            free(user->lastName);
            free(user->userName);
            free(user->password);
            free(user->description);
        }
    }

    void freeUserItem(UserItem* item){
        if(item!=NULL){
            freeUser(item->data);
            freeUserItem(item->next);
            free(item);
            item=NULL;
        }
    }

    void freeUserList(UserList* list){
        freeUserItem(list->head);
    }

    void freeArray(DynamicArray *dynamicArray){
        int i;
        for (i=0;i<dynamicArray->capacity;i++){
            freeUser(dynamicArray->array[i]);
            free(dynamicArray->array[i]);
        }
        free(dynamicArray->array);
        dynamicArray->array=NULL;
    }

    void start(DynamicArray* dynamicArray, UserList* userList){
        FILE *input;
        int c,index;
        char line[MAX_LINE];
        char* info[INPUT_NUM];
        input = fopen("input.txt","rt");
        if(input) {
            while (EOF != (c = fgetc(input))) {
                ungetc(c, input);
                fgets(line, MAX_LINE, input);
                info[0] = strtok(line, ";");
                index = 1;
                while (index < INPUT_NUM) {
                    info[index] = strtok(NULL, ";");
                    index++;
                }
                updateData(info, dynamicArray, &userList);
            }
        }
        else
            exit(1);
        fclose(input);
    }

    int main() {
        int choice;
        DynamicArray dynamicArray;
        newDynamicArray(&dynamicArray);
        UserList* userList;
        newUserList(&userList);
        start(&dynamicArray, userList);
        bubbleSort(&userList, (Comparator) lastNameComparator);
        do{
            printf("Welcome! please choose an option\n"
                   "1 - Log in\n"
                   "2 - New member\n"
                   "3 – Exit\n");
            scanf("%d",&choice);
            switch(choice){
                case 1:
                    login(&dynamicArray, &userList);
                    break;
                case 2:
                    addNewMember(&dynamicArray, &userList);
                    break;
                case 3:
                    end(&dynamicArray,userList);
                    break;
                default:
                    printf("Bad choice, please try again\n");
                    break;
            }
        }while(choice!=3);
        return 0;
    }

    void end(DynamicArray* dynamicArray, UserList* userList){
       // FILE *output;
        //output=fopen("output.txt","w");
        //fclose(output);
        freeAllMemory(dynamicArray, userList);
    }

    void add(UserList *userList, User *newUser) {
        UserItem* item=(UserItem*)malloc(sizeof(UserItem));
        item->data=newUser;
        item->next=NULL;
        userList->last->next=item;
        userList->last=item;
        if(userList->head->data==NULL)
            userList->head=userList->last;
    }

    void login(DynamicArray* dynamicArray, UserList** userList){
        User* user;
        char username[10],password[15];
        printf("Please enter your username: \n");
        scanf("%s",username);
        user=usernameExists(username,*userList,dynamicArray);
        if(user==NULL){
            printf("User do not exist in the system, please try again \n");
            //Another try
            printf("Please enter your username: \n");
            scanf("%s",username);
            user=usernameExists(username,*userList,dynamicArray);
            if(user==NULL)
                return;
        }
        printf("Please enter your password: \n");
        scanf("%s",password);
        //Wrong password
        if(strcmp(password,user->password)!=0){
            printf("Wrong password\n");
            return;
        }
        //Login successful
        printf("Hello %s!\n", user->firstName);
        mainMenu(dynamicArray, userList, user);
    }

    void addNewMember(DynamicArray* dynamicArray, UserList** userList){
        char* info[INPUT_NUM];
        char id[9], tmp1[15], tmp2[10], age[3], sex, description[211];
        int i;
        //Prevent NULL
        for(i=0;i<INPUT_NUM;i++)//Prevent NULL
            info[i]="";
        printf("Please enter your ID: \n");
        //ID
        scanf("%s",id);
        if(idExists(id,dynamicArray,*userList)) {
            printf("Error: User already exists");
            return;
        }
        strcpy(id,info[0]);
        //First name
        printf("Please enter your first name:\n");
        scanf("%s",tmp1);
        if(strlen(tmp1)<3||(!containsOnlyLetters(tmp1)))
            return;
        strcpy(tmp1,info[1]);
        //Last name
        printf("Please enter your last name:\n");
        scanf("%s",tmp1);
        if(strlen(tmp1)<3||(!containsOnlyLetters(tmp1)))
            return;
        strcpy(tmp1,info[2]);
        //Age
        printf("Please enter your age (18 to 100):\n");
        scanf("%s",age);
        if (atoi(age)<18||atoi(age)>100)
            return;
        strcpy(age,info[3]);
        //Sex
        printf("Please enter your gender (F-female, M-male):\n");
        scanf("%c", &sex);//Dummy
        scanf("%c", &sex);
        if (sex!='M'&&sex!='F')
            return;
        info[4]=&sex;
        //Username
        printf("Choose a username (3-10 characters):\n");
        scanf("%s", tmp2);
        if(strlen(tmp2)<3||tmp2[0]<65||tmp2[0]>122||(tmp2[0]>=91&&tmp2[0]<=96))
            return;
        strcpy(tmp2,info[5]);
        printf("please choose 4 hobbies: Baseball=1, Basketball=2, Bicycle=3, Books=4,"
               " Drawing=5, Gym=6, Movies=7, Poetry=8\n");
        scanf(" %8[^\n]",tmp2);
        strcpy(tmp2,info[7]);
        printf("Choose a password (attention-minimum 3 characters):\n");
        scanf("%s",tmp1);
        if(strlen(tmp1)<3)
            return;
        strcpy(tmp1,info[6]);
        printf("Some words about yourself:\n");
        scanf(" %s",description);
        strcpy(description,info[8]);
        updateData(info,dynamicArray,userList);
        printf("Hi %s, lets find love!\n", info[1]);
        mainMenu(dynamicArray,userList,usernameExists(info[5],*userList,dynamicArray));
    }

    User* usernameExists(char *username, UserList *userList, DynamicArray *dynamicArray){
        int i;
        for (i=0;i<dynamicArray->size;i++)
            if(strcmp(dynamicArray->array[i]->userName,username)==0)
                return dynamicArray->array[i];
        UserItem* iterator = newIterator(userList);
        while(iterator!=NULL&&iterator->data!=NULL){
            if(strcmp(iterator->data->userName,username)==0)
                return iterator->data;
            iterator=iterator->next;
        }
        return NULL;
    }

    UserItem* newIterator (UserList* userList){
        return userList->head;
    }

    int idExists(char *ID, DynamicArray *dynamicArray, UserList *userList){
        int i=0;
        for (i=0;i<dynamicArray->size;i++)
            if(strcmp(dynamicArray->array[i]->ID,ID)==0)
                return 1;
        UserItem* iterator = newIterator(userList);
        while(iterator!=NULL&&iterator->data!=NULL){
            if(strcmp(iterator->data->ID,ID)==0)
                return 1;
            iterator=iterator->next;
        }
        return 0;
    }


    int containsOnlyLetters(char str[]){
        int i;
        for(i=0;i<strlen(str);i++)
            if(str[i]<65||str[i]>122||(str[i]>=91&&str[i]<=96))
                return 0;
        return 1;
    }

    void freeAllMemory(DynamicArray* dynamicArray, UserList* userList){
        freeArray(dynamicArray);
        freeUserList(userList);
    }

    void removeUserFromList(UserList* list, User* user){
        UserItem* iterator=newIterator(list);
        UserItem* previous=list->head;

        while(iterator!=NULL && iterator->data!=NULL && equal(iterator->data,user)== false){
            previous=iterator;
            iterator=iterator->next;
        }
        if(iterator!=NULL && iterator->data!=NULL && equal(iterator->data,user)== true){
            previous->next=iterator->next;
            iterator->next=NULL;
            freeUserItem(iterator);
            if(iterator==list->head) {
                list->head = NULL;
                list->last = NULL;
            }
            if(iterator==list->last)
                list->last=previous;
        }
    }

    bool equal(User* u1, User* u2){
        if(u1->ID==u2->ID)
            return true;
        return false;
    }

    void removeUserFromArray(DynamicArray* dynamicArray, User* user){
        int i,j,found=0;
        User  *tmp;
        //Find index
        for (i=0;i<dynamicArray->size;i++)
            if(strcmp(dynamicArray->array[i]->ID,user->ID)==0) {
                found = 1;
                break;
            }
        if(found) {
            tmp = dynamicArray->array[i];
            for (j = i; j + 1 < dynamicArray->size; j++) {
                dynamicArray->array[j] = dynamicArray->array[j+1];
            }
            freeUser(tmp);
            dynamicArray->size--;
        }
    }

    void deleteMe(DynamicArray* dynamicArray, UserList* list, User *user){
        removeUserFromArray(dynamicArray,user);
        removeUserFromList(list,user);
    }


    void incrementArray(DynamicArray *array){
        if(array->size>=array->capacity){
            array->capacity*=2;
           array->array=realloc(array->array, sizeof(User*)*array->capacity);
        }
    }

我无法找到泄漏及其原因,valgrind 显示我在 newDynamicArray 函数和 newUserList 中仍然可以访问 72 个字节。

最佳答案

I have 72 bytes still reachable

这些字节不是内存泄漏,仍然可以通过例如main中的变量dynamicArray来访问

Valgrind 明确指出内存泄漏

关于c - 即使我释放了每个 malloc,动态结构数组和链表中的内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54105727/

相关文章:

c - 在 Linux 设备和 Mac 之间共享文件的情况下,mac os x lion 中的 fwrite() 和 fread() 需要很长时间

c - 使用一维结构数组中的信息填充二维结构数组

python展平数组数组

Java 进程内存远大于指定的限制

optimization - 如何提高 GPU 的内存访问速度? (CUDA)

C中int数组和char数组的串联

c - C语言中这个指向指针的指针语句是什么意思?

c - 函数调用中的 UTHash 迭代一次但不是第二次

c - 变量超出范围并且内存保留值

java - JVM 和内存使用 - JRun 服务器未使用完整的 PSPermGen 分配?