调整哈希表大小 - 帮助我 Valgrind 调试我的程序

发布于 2025-01-18 15:25:53 字数 11762 浏览 1 评论 0原文

我正在尝试创建一个包含联系电话和名称的哈希表,当我的联系人太多时,我需要调整哈希表的大小。当我这样做时,我的内存泄漏 +阀门错误。我尝试了很多事情,您能帮我理解或解决问题吗?

我的哈希表结构:

struct dir {
    uint32_t len;
    uint32_t contactsNumber;
    struct contact *contactList;
};

我的联系结构:

struct contact *contact_create(char *name, char *num) {
    struct contact *init_contact = malloc(sizeof(struct contact));
    init_contact->name = name;
    init_contact->num = num;
    init_contact->next = NULL;
    return (init_contact);
}

我的ressize函数:

void dir_resize(struct dir *dir, uint32_t new_size) {
    uint32_t old_size = dir->len;
    struct dir *new_dir = dir_create(new_size);

    for (uint32_t i = 0; i < old_size; i++) {
        struct contact *current_contact = dir[i].contactList;
        while (current_contact->next != NULL) {
            dir_insert(new_dir, current_contact->next->name, current_contact->next->num);
            // contact_removeTop(current_contact->next);
            current_contact->next = current_contact->next->next;
        }
        free(current_contact);
    }

    // dir_free(dir);
    // dir = realloc(dir, sizeof(struct dir)*new_size);
    dir->contactsNumber = new_dir->contactsNumber;
    dir->len = new_size;
    for (uint32_t i = 0; i < new_size; i++) {
        dir[i].contactList = new_dir[i].contactList;
    }
    //dir_free(new_dir);
    //dir_print(dir);
}

我的dir_free函数:

void dir_free(struct dir *dir) {
    uint32_t size = dir->len;
    for (uint32_t i = 0; i < size; i++) {
        contact_free(dir[i].contactList);
    }
    free(dir);
    return;
}

我的contact_free函数:

void contact_free(struct contact *contact) {
    if (contact == NULL) {
        return;
    }

    while (contact->next != NULL) {
        contact_removeTop(contact);
    }
    free(contact);
}

我的dir_create函数:

struct dir *dir_create(uint32_t len) {
    struct dir *directory = malloc(sizeof(struct dir) * len);
    //struct dir *directory = malloc(sizeof(struct dir) * len);
    directory->contactsNumber = 0;

    for (uint32_t i = 0; i < len; i++) {
        directory[i].contactList = contact_sentinel();
    }

    directory->len = len;
    return (directory);
}

调整

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

int main(void) {
    struct dir *dir = dir_create(10);
    dir_insert(dir, "A", "06789435351");
    dir_insert(dir, "B", "0678346533");
    dir_print(dir);
    dir_insert(dir, "C", "06723236533");
    dir_print(dir);
    dir_insert(dir, "D", "06723236533");
    dir_print(dir);
    dir_resize(dir, 11);
    dir_print(dir);
    dir_free(dir);

    return EXIT_SUCCESS;
}

==80271== Memcheck, a memory error detector
==80271== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==80271== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==80271== Command: ./tests/resizing-test
==80271== 
------------------------ANNUAIRE-----------------------
Nombre de contacts :2
Taille de l'annuaire :10
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Name -> A, Number -> 06789435351
END.
Name -> B, Number -> 0678346533
END.
--------------------------------------------------------
------------------------ANNUAIRE-----------------------
Nombre de contacts :3
Taille de l'annuaire :10
Name -> C, Number -> 06723236533
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Name -> A, Number -> 06789435351
END.
Name -> B, Number -> 0678346533
END.
--------------------------------------------------------
------------------------ANNUAIRE-----------------------
Nombre de contacts :4
Taille de l'annuaire :10
Name -> C, Number -> 06723236533
END.
Name -> D, Number -> 06723236533
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Name -> A, Number -> 06789435351
END.
Name -> B, Number -> 0678346533
END.
--------------------------------------------------------
==80271== Invalid write of size 8
==80271==    at 0x484B57C: dir_resize (directory.c:162)
==80271==    by 0x10916E: main (resizing.c:16)
==80271==  Address 0x4a5a0e8 is 8 bytes after a block of size 160 alloc'd
==80271==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==80271==    by 0x484B33B: dir_create (directory.c:24)
==80271==    by 0x1090EE: main (resizing.c:8)
==80271== 
------------------------ANNUAIRE-----------------------
Nombre de contacts :4
Taille de l'annuaire :11
Name -> B, Number -> 0678346533
END.
Name -> C, Number -> 06723236533
END.
Name -> D, Number -> 06723236533
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
==80271== Invalid read of size 8
==80271==    at 0x484B498: dir_print (directory.c:133)
==80271==    by 0x109176: main (resizing.c:17)
==80271==  Address 0x4a5a0e8 is 8 bytes after a block of size 160 alloc'd
==80271==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==80271==    by 0x484B33B: dir_create (directory.c:24)
==80271==    by 0x1090EE: main (resizing.c:8)
==80271== 
Name -> A, Number -> 06789435351
END.
--------------------------------------------------------
==80271== Invalid read of size 8
==80271==    at 0x484B408: dir_free (directory.c:110)
==80271==    by 0x10917E: main (resizing.c:18)
==80271==  Address 0x4a5a0e8 is 8 bytes after a block of size 160 alloc'd
==80271==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==80271==    by 0x484B33B: dir_create (directory.c:24)
==80271==    by 0x1090EE: main (resizing.c:8)
==80271== 
==80271== 
==80271== HEAP SUMMARY:
==80271==     in use at exit: 272 bytes in 5 blocks
==80271==   total heap usage: 32 allocs, 27 frees, 2,056 bytes allocated
==80271== 
==80271== 24 bytes in 1 blocks are definitely lost in loss record 1 of 5
==80271==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==80271==    by 0x484B752: contact_insert (contact.c:37)
==80271==    by 0x484B5D8: dir_insert (directory.c:47)
==80271==    by 0x109107: main (resizing.c:9)
==80271== 
==80271== 24 bytes in 1 blocks are definitely lost in loss record 2 of 5
==80271==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==80271==    by 0x484B752: contact_insert (contact.c:37)
==80271==    by 0x484B5D8: dir_insert (directory.c:47)
==80271==    by 0x10911D: main (resizing.c:10)
==80271== 
==80271== 24 bytes in 1 blocks are definitely lost in loss record 3 of 5
==80271==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==80271==    by 0x484B752: contact_insert (contact.c:37)
==80271==    by 0x484B5D8: dir_insert (directory.c:47)
==80271==    by 0x10913B: main (resizing.c:12)
==80271== 
==80271== 24 bytes in 1 blocks are definitely lost in loss record 4 of 5
==80271==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==80271==    by 0x484B752: contact_insert (contact.c:37)
==80271==    by 0x484B5D8: dir_insert (directory.c:47)
==80271==    by 0x109159: main (resizing.c:14)
==80271== 
==80271== 176 bytes in 1 blocks are definitely lost in loss record 5 of 5
==80271==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==80271==    by 0x484B33B: dir_create (directory.c:24)
==80271==    by 0x484B4F1: dir_resize (directory.c:145)
==80271==    by 0x10916E: main (resizing.c:16)
==80271== 
==80271== LEAK SUMMARY:
==80271==    definitely lost: 272 bytes in 5 blocks
==80271==    indirectly lost: 0 bytes in 0 blocks
==80271==      possibly lost: 0 bytes in 0 blocks
==80271==    still reachable: 0 bytes in 0 blocks
==80271==         suppressed: 0 bytes in 0 blocks
==80271== 
==80271== For lists of detected and suppressed errors, rerun with: -s
==80271== ERROR SUMMARY: 8 errors from 8 contexts (suppressed: 0 from 0)

最后,我 首先,我没有释放ressize函数中的空间,您可以查看我的评论行,看看我已经尝试过释放new_dirdir,但这只会导致更多错误,因此我放弃了。我不知道该怎么做,而没有弹出一百万个错误! 其次,当我使哈希表更大时,分配给DIR的内存空间不再与其新尺寸相对应,从而导致错误。正如您在评论的行中看到的那样,我尝试重新分配循环内部和外部,但错误仍然存​​在。我该怎么办?

感谢您的帮助!

edit

这是我的contact_sentinel函数:

struct contact *contact_sentinel() {
    struct contact *sentinel = malloc(sizeof(struct contact));
    sentinel->name = NULL;
    sentinel->num = NULL;
    sentinel->next = NULL;
    return (sentinel);
}

我的dir_insert

char *dir_insert(struct dir *dir, const char *name, const char *num) {
    uint32_t size = dir->len;
    uint32_t index = hash_modulo(name, size);

    char *number = contact_insert(dir[index].contactList, name, num);

    if (number == NULL) {
        dir->contactsNumber++;
    }

    if (dir->contactsNumber > 0.75 * size) {
        dir_resize(dir, size * 2);
    }

    return number;
}

我的contact insert

char *contact_insert(struct contact *contact, const char *name, const char *num) {
    while (contact->next != NULL) {
        if (contact->name == name) {
            const char *old_num = contact->num;
            contact->num = (char *)num;
            return (char *)old_num;
        }
        contact = contact->next;
    }

    if (contact->name == name) {
        const char *old_num = contact->num;
        contact->num = (char *)num;
        return (char *)old_num;
    }

    contact->next = malloc(sizeof(struct contact));
    assert(contact->next != NULL);
    
    contact->next->name = (char *)name;
    contact->next->num = (char *)num;
    contact->next->next = NULL;

    return (NULL);
}

function hash 代码>:

#include <stdlib.h>
#include <stdint.h>

uint32_t hash(const char *str) {
    uint32_t hash = 5381;
    uint32_t c;
    
    while ((c = *str++)) {
        hash = ((hash << 5) + hash) + c;
    }

    return hash;
}

uint32_t hash_modulo(const char *name, uint32_t size) {
    return hash(name) % size;
}

函数dir_print

void dir_print(struct dir *dir) {
    if (dir == NULL) {
        printf("Annuaire vide.\n");
        return;
    }

    printf("------------------------ANNUAIRE-----------------------\n");
    printf("Nombre de contacts :%d\n", dir->contactsNumber);
    printf("Taille de l'annuaire :%d\n", dir->len);
    uint32_t len = dir->len;

    for (uint32_t i = 0; i < len; i++) {
        contact_print(dir[i].contactList);
    }
    printf("--------------------------------------------------------\n");
}

功能contact_print

void contact_print(struct contact *contact) {
    contact = contact->next;
    if (contact == NULL) {
        printf("Liste vide.\n");
    }
    while (contact != NULL) {
        printf("Name -> %s, Number -> %s\n", contact->name, contact->num);
        contact = contact->next;
    }
    printf("END.\n");
}

I'm trying to create a hash table that contains contact numbers and names, when I have too many contacts, I need to resize my hash table. When I do that, I'm having memory leaks + valgrind errors. I've tried many things, can you help me understand or solve the issues?

My hash table structure:

struct dir {
    uint32_t len;
    uint32_t contactsNumber;
    struct contact *contactList;
};

My contact structure:

struct contact *contact_create(char *name, char *num) {
    struct contact *init_contact = malloc(sizeof(struct contact));
    init_contact->name = name;
    init_contact->num = num;
    init_contact->next = NULL;
    return (init_contact);
}

My resize function:

void dir_resize(struct dir *dir, uint32_t new_size) {
    uint32_t old_size = dir->len;
    struct dir *new_dir = dir_create(new_size);

    for (uint32_t i = 0; i < old_size; i++) {
        struct contact *current_contact = dir[i].contactList;
        while (current_contact->next != NULL) {
            dir_insert(new_dir, current_contact->next->name, current_contact->next->num);
            // contact_removeTop(current_contact->next);
            current_contact->next = current_contact->next->next;
        }
        free(current_contact);
    }

    // dir_free(dir);
    // dir = realloc(dir, sizeof(struct dir)*new_size);
    dir->contactsNumber = new_dir->contactsNumber;
    dir->len = new_size;
    for (uint32_t i = 0; i < new_size; i++) {
        dir[i].contactList = new_dir[i].contactList;
    }
    //dir_free(new_dir);
    //dir_print(dir);
}

My dir_free function:

void dir_free(struct dir *dir) {
    uint32_t size = dir->len;
    for (uint32_t i = 0; i < size; i++) {
        contact_free(dir[i].contactList);
    }
    free(dir);
    return;
}

My contact_free function:

void contact_free(struct contact *contact) {
    if (contact == NULL) {
        return;
    }

    while (contact->next != NULL) {
        contact_removeTop(contact);
    }
    free(contact);
}

My dir_create function:

struct dir *dir_create(uint32_t len) {
    struct dir *directory = malloc(sizeof(struct dir) * len);
    //struct dir *directory = malloc(sizeof(struct dir) * len);
    directory->contactsNumber = 0;

    for (uint32_t i = 0; i < len; i++) {
        directory[i].contactList = contact_sentinel();
    }

    directory->len = len;
    return (directory);
}

Finally, my resizing.c test file:

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

int main(void) {
    struct dir *dir = dir_create(10);
    dir_insert(dir, "A", "06789435351");
    dir_insert(dir, "B", "0678346533");
    dir_print(dir);
    dir_insert(dir, "C", "06723236533");
    dir_print(dir);
    dir_insert(dir, "D", "06723236533");
    dir_print(dir);
    dir_resize(dir, 11);
    dir_print(dir);
    dir_free(dir);

    return EXIT_SUCCESS;
}

The Valgrind output:

==80271== Memcheck, a memory error detector
==80271== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==80271== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==80271== Command: ./tests/resizing-test
==80271== 
------------------------ANNUAIRE-----------------------
Nombre de contacts :2
Taille de l'annuaire :10
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Name -> A, Number -> 06789435351
END.
Name -> B, Number -> 0678346533
END.
--------------------------------------------------------
------------------------ANNUAIRE-----------------------
Nombre de contacts :3
Taille de l'annuaire :10
Name -> C, Number -> 06723236533
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Name -> A, Number -> 06789435351
END.
Name -> B, Number -> 0678346533
END.
--------------------------------------------------------
------------------------ANNUAIRE-----------------------
Nombre de contacts :4
Taille de l'annuaire :10
Name -> C, Number -> 06723236533
END.
Name -> D, Number -> 06723236533
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Name -> A, Number -> 06789435351
END.
Name -> B, Number -> 0678346533
END.
--------------------------------------------------------
==80271== Invalid write of size 8
==80271==    at 0x484B57C: dir_resize (directory.c:162)
==80271==    by 0x10916E: main (resizing.c:16)
==80271==  Address 0x4a5a0e8 is 8 bytes after a block of size 160 alloc'd
==80271==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==80271==    by 0x484B33B: dir_create (directory.c:24)
==80271==    by 0x1090EE: main (resizing.c:8)
==80271== 
------------------------ANNUAIRE-----------------------
Nombre de contacts :4
Taille de l'annuaire :11
Name -> B, Number -> 0678346533
END.
Name -> C, Number -> 06723236533
END.
Name -> D, Number -> 06723236533
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
==80271== Invalid read of size 8
==80271==    at 0x484B498: dir_print (directory.c:133)
==80271==    by 0x109176: main (resizing.c:17)
==80271==  Address 0x4a5a0e8 is 8 bytes after a block of size 160 alloc'd
==80271==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==80271==    by 0x484B33B: dir_create (directory.c:24)
==80271==    by 0x1090EE: main (resizing.c:8)
==80271== 
Name -> A, Number -> 06789435351
END.
--------------------------------------------------------
==80271== Invalid read of size 8
==80271==    at 0x484B408: dir_free (directory.c:110)
==80271==    by 0x10917E: main (resizing.c:18)
==80271==  Address 0x4a5a0e8 is 8 bytes after a block of size 160 alloc'd
==80271==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==80271==    by 0x484B33B: dir_create (directory.c:24)
==80271==    by 0x1090EE: main (resizing.c:8)
==80271== 
==80271== 
==80271== HEAP SUMMARY:
==80271==     in use at exit: 272 bytes in 5 blocks
==80271==   total heap usage: 32 allocs, 27 frees, 2,056 bytes allocated
==80271== 
==80271== 24 bytes in 1 blocks are definitely lost in loss record 1 of 5
==80271==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==80271==    by 0x484B752: contact_insert (contact.c:37)
==80271==    by 0x484B5D8: dir_insert (directory.c:47)
==80271==    by 0x109107: main (resizing.c:9)
==80271== 
==80271== 24 bytes in 1 blocks are definitely lost in loss record 2 of 5
==80271==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==80271==    by 0x484B752: contact_insert (contact.c:37)
==80271==    by 0x484B5D8: dir_insert (directory.c:47)
==80271==    by 0x10911D: main (resizing.c:10)
==80271== 
==80271== 24 bytes in 1 blocks are definitely lost in loss record 3 of 5
==80271==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==80271==    by 0x484B752: contact_insert (contact.c:37)
==80271==    by 0x484B5D8: dir_insert (directory.c:47)
==80271==    by 0x10913B: main (resizing.c:12)
==80271== 
==80271== 24 bytes in 1 blocks are definitely lost in loss record 4 of 5
==80271==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==80271==    by 0x484B752: contact_insert (contact.c:37)
==80271==    by 0x484B5D8: dir_insert (directory.c:47)
==80271==    by 0x109159: main (resizing.c:14)
==80271== 
==80271== 176 bytes in 1 blocks are definitely lost in loss record 5 of 5
==80271==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==80271==    by 0x484B33B: dir_create (directory.c:24)
==80271==    by 0x484B4F1: dir_resize (directory.c:145)
==80271==    by 0x10916E: main (resizing.c:16)
==80271== 
==80271== LEAK SUMMARY:
==80271==    definitely lost: 272 bytes in 5 blocks
==80271==    indirectly lost: 0 bytes in 0 blocks
==80271==      possibly lost: 0 bytes in 0 blocks
==80271==    still reachable: 0 bytes in 0 blocks
==80271==         suppressed: 0 bytes in 0 blocks
==80271== 
==80271== For lists of detected and suppressed errors, rerun with: -s
==80271== ERROR SUMMARY: 8 errors from 8 contexts (suppressed: 0 from 0)

As you can see I have two problems. First, I'm not freeing up the space within the resize function, you can look at my commented lines and see that I've already tried freeing up new_dir and dir but that only resulted in more errors so I gave that up. I don't know how to do it without having a million errors pop up!
Second, when I make my hash table bigger, the memory space allocated to dir no longer corresponds to its new size, which results in the errors. As you can see with my commented lines, I tried reallocating both within and outside the loop, but the error persists. What can I do about it?

Thanks for your help!

EDIT:

This is my contact_sentinel function:

struct contact *contact_sentinel() {
    struct contact *sentinel = malloc(sizeof(struct contact));
    sentinel->name = NULL;
    sentinel->num = NULL;
    sentinel->next = NULL;
    return (sentinel);
}

My dir_insert:

char *dir_insert(struct dir *dir, const char *name, const char *num) {
    uint32_t size = dir->len;
    uint32_t index = hash_modulo(name, size);

    char *number = contact_insert(dir[index].contactList, name, num);

    if (number == NULL) {
        dir->contactsNumber++;
    }

    if (dir->contactsNumber > 0.75 * size) {
        dir_resize(dir, size * 2);
    }

    return number;
}

My contact insert:

char *contact_insert(struct contact *contact, const char *name, const char *num) {
    while (contact->next != NULL) {
        if (contact->name == name) {
            const char *old_num = contact->num;
            contact->num = (char *)num;
            return (char *)old_num;
        }
        contact = contact->next;
    }

    if (contact->name == name) {
        const char *old_num = contact->num;
        contact->num = (char *)num;
        return (char *)old_num;
    }

    contact->next = malloc(sizeof(struct contact));
    assert(contact->next != NULL);
    
    contact->next->name = (char *)name;
    contact->next->num = (char *)num;
    contact->next->next = NULL;

    return (NULL);
}

Function hash:

#include <stdlib.h>
#include <stdint.h>

uint32_t hash(const char *str) {
    uint32_t hash = 5381;
    uint32_t c;
    
    while ((c = *str++)) {
        hash = ((hash << 5) + hash) + c;
    }

    return hash;
}

uint32_t hash_modulo(const char *name, uint32_t size) {
    return hash(name) % size;
}

Function dir_print:

void dir_print(struct dir *dir) {
    if (dir == NULL) {
        printf("Annuaire vide.\n");
        return;
    }

    printf("------------------------ANNUAIRE-----------------------\n");
    printf("Nombre de contacts :%d\n", dir->contactsNumber);
    printf("Taille de l'annuaire :%d\n", dir->len);
    uint32_t len = dir->len;

    for (uint32_t i = 0; i < len; i++) {
        contact_print(dir[i].contactList);
    }
    printf("--------------------------------------------------------\n");
}

Function contact_print:

void contact_print(struct contact *contact) {
    contact = contact->next;
    if (contact == NULL) {
        printf("Liste vide.\n");
    }
    while (contact != NULL) {
        printf("Name -> %s, Number -> %s\n", contact->name, contact->num);
        contact = contact->next;
    }
    printf("END.\n");
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

长途伴 2025-01-25 15:25:53

首先 - 你的大小调整。

您不需要释放联系人列表,只需重新分配目录数组。

新的 dir 结构保留了指向仍然有效的接触链的旧指针,

更重要的是,您没有返回新创建的目录。所有后续操作(主要)仍然尝试在旧目录(您可能已在此处释放)上工作。所以我让它返回新的目录,

struct dir* dir_resize(struct dir* dir, uint32_t new_size)
{
    uint32_t old_size = dir->len;
    struct dir* new_dir = realloc(dir, new_size * sizeof( * new_dir));
    // initialize the new dir entries
    for (size_t i = old_size; i < new_size; i++) {
        new_dir[i].contactList = contact_sentinel();
    }

    return new_dir;
   }

这样就不会泄漏

==8769==
==8769== HEAP SUMMARY:
==8769==     in use at exit: 24 bytes in 1 blocks
==8769==   total heap usage: 18 allocs, 17 frees, 1,720 bytes allocated
==8769==
==8769== LEAK SUMMARY:
==8769==    definitely lost: 24 bytes in 1 blocks
==8769==    indirectly lost: 0 bytes in 0 blocks
==8769==      possibly lost: 0 bytes in 0 blocks
==8769==    still reachable: 0 bytes in 0 blocks
==8769==         suppressed: 0 bytes in 0 blocks
==8769== Rerun with --leak-check=full to see details of leaked memory
==8769==
==8769== For lists of detected and suppressed errors, rerun with: -s
==8769== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

其他错误,

您只在联系人列表中存储文本指针。目前有效,因为它们是文字。但是尝试这个

struct dir* dir = dir_create(10);
char phone[] = "06789435351";
dir_insert(dir, "A", phone);
strcpy(phone, "0678346533");
dir_insert(dir, "B", phone);

输出

(使用我的打印功能),

=====
(null) (null)
(null) (null)
A 0678346533
(null) (null)
(null) (null)
(null) (null)
(null) (null)
(null) (null)
(null) (null)
B 0678346533
(null) (null)
(null) (null)

因为您将“电话”的地址存储在“contact.num”中,现在两个联系人都有相同的电话号码。

您需要执行

contact->next->num = stdup(num);

strdup 将为字符串分配空间并将其复制到新空间中。您需要记住最后释放内存。

而且你和你的哨兵非常不一致。您是否希望末尾始终有一个“空白”联系人?事实上你并没有这样做。实际上你根本不需要这些哨兵,只需在第一次创建它时将 dir.contactList 设置为 NULL 即可。目前,您无缘无故地分配了额外的内存块。


在这里,

while (contact->next != NULL) {
    if (contact->name == name) {
        const char* old_num = contact->num;
        contact->num = (char*)num;
        return(char*)old_num;
    }
    contact = contact->next;
}

if (contact->name == name) {
    const char* old_num = contact->num;
    contact->num = (char*)num;
    return(char*)old_num;
}

您显然是在查看该名称是否已在列表中。这

 if(contact->name == name)

只是有效的,因为您正在存储文字的地址,因此它是比较地址。应该可以

   if(strcmp(contact->name, name) == 0)

修复

将 strdup 放入 ,添加 strcmp ,修复调整大小。无泄漏

char* contact_insert(struct contact* contact, const char* name, const char* num) {
    
    while (contact->next != NULL) {
        if (strcmp(contact->name,name)==0) {
            const char* old_num = contact->num;
            contact->num = (char*)num;
            return(char*)old_num;
        }
        contact = contact->next;
    }

    contact->next = malloc(sizeof(struct contact));
    assert(contact->next != NULL);

    contact->next->name = strdup(name);
    contact->next->num = strdup(num);
    contact->next->next = NULL;

    return(NULL);

}

调整大小

struct dir* dir_resize(struct dir* dir, uint32_t new_size)
{
    uint32_t old_size = dir->len;
    struct dir* new_dir = dir_create(new_size);

    for (uint32_t i = 0; i < old_size; i++) {
        struct contact* current_contact = dir[i].contactList;
        while (current_contact->next != NULL) {
            dir_insert(new_dir, current_contact->next->name, current_contact->next->num);
            struct contact* temp = current_contact->next;
            current_contact->next = current_contact->next->next;
            free_contact(temp);

        }

    }
    dir_free(dir);
    
    return new_dir; <<<=== v important
}

清理触点

void free_contact(struct contact* contact) {
    free(contact->name);
    free(contact->num);
    free(contact);
}
void contact_free(struct contact* contact) {

    if (contact == NULL) {
        return;
    }

    while (contact != NULL) {
        struct contact *temp = contact;
        contact = temp->next;
        free_contact(temp);
    }
    
}

输出

------------------------ANNUAIRE-----------------------
Nombre de contacts :4
Taille de l'annuaire :11
Name -> B, Number -> 0678346533
END.
Name -> C, Number -> 06723236533
END.
Name -> D, Number -> 06723236533
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Name -> A, Number -> 06789435351
END.
--------------------------------------------------------
==14321==
==14321== HEAP SUMMARY:
==14321==     in use at exit: 0 bytes in 0 blocks
==14321==   total heap usage: 48 allocs, 48 frees, 2,166 bytes allocated
==14321==
==14321== All heap blocks were freed -- no leaks are possible
==14321==
==14321== For lists of detected and suppressed errors, rerun with: -s
==14321== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

First - your resize.

You do not need to free the contact lists, you just need to reallocate the dir array.

The new dir structure keeps the old pointers to still valid contact chains

More importantly you did not return the newly creeated directory. All you subsequent operations (in main) still tried to work on the old dir (that you might have freed here). So I made it return the new dir

struct dir* dir_resize(struct dir* dir, uint32_t new_size)
{
    uint32_t old_size = dir->len;
    struct dir* new_dir = realloc(dir, new_size * sizeof( * new_dir));
    // initialize the new dir entries
    for (size_t i = old_size; i < new_size; i++) {
        new_dir[i].contactList = contact_sentinel();
    }

    return new_dir;
   }

so no leaks now

==8769==
==8769== HEAP SUMMARY:
==8769==     in use at exit: 24 bytes in 1 blocks
==8769==   total heap usage: 18 allocs, 17 frees, 1,720 bytes allocated
==8769==
==8769== LEAK SUMMARY:
==8769==    definitely lost: 24 bytes in 1 blocks
==8769==    indirectly lost: 0 bytes in 0 blocks
==8769==      possibly lost: 0 bytes in 0 blocks
==8769==    still reachable: 0 bytes in 0 blocks
==8769==         suppressed: 0 bytes in 0 blocks
==8769== Rerun with --leak-check=full to see details of leaked memory
==8769==
==8769== For lists of detected and suppressed errors, rerun with: -s
==8769== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

other errors

you are only storing text pointers in you contact list. Works at the moment becuase they are literals. But try this

struct dir* dir = dir_create(10);
char phone[] = "06789435351";
dir_insert(dir, "A", phone);
strcpy(phone, "0678346533");
dir_insert(dir, "B", phone);

output is

(using my print function)

=====
(null) (null)
(null) (null)
A 0678346533
(null) (null)
(null) (null)
(null) (null)
(null) (null)
(null) (null)
(null) (null)
B 0678346533
(null) (null)
(null) (null)

because you stored the address of 'phone' in the 'contact.num' now both contacts have the same phone number.

you need to do

contact->next->num = stdup(num);

strdup will malloc space for the string and copy it into the new space for you. You will need to remeber to free the memory at the end.

Also you are very inconsistent with your sentinel. Do you intend that there is always a 'blank' contact at the end. You in fact do not do that. Really you dont need those sentinels at all , just set dir.contactList to NULL when first creating it. At the moment you are allocating an extra memory block for no reason.


here

while (contact->next != NULL) {
    if (contact->name == name) {
        const char* old_num = contact->num;
        contact->num = (char*)num;
        return(char*)old_num;
    }
    contact = contact->next;
}

if (contact->name == name) {
    const char* old_num = contact->num;
    contact->num = (char*)num;
    return(char*)old_num;
}

you are clearly looking to see if that name is already in the list. This

 if(contact->name == name)

is only working becuase you are stoing the address of literals, so its comparing addresses. It should be

   if(strcmp(contact->name, name) == 0)

OK refixed

put strdup in , added strcmp , fixed resize. No leaks

char* contact_insert(struct contact* contact, const char* name, const char* num) {
    
    while (contact->next != NULL) {
        if (strcmp(contact->name,name)==0) {
            const char* old_num = contact->num;
            contact->num = (char*)num;
            return(char*)old_num;
        }
        contact = contact->next;
    }

    contact->next = malloc(sizeof(struct contact));
    assert(contact->next != NULL);

    contact->next->name = strdup(name);
    contact->next->num = strdup(num);
    contact->next->next = NULL;

    return(NULL);

}

resize

struct dir* dir_resize(struct dir* dir, uint32_t new_size)
{
    uint32_t old_size = dir->len;
    struct dir* new_dir = dir_create(new_size);

    for (uint32_t i = 0; i < old_size; i++) {
        struct contact* current_contact = dir[i].contactList;
        while (current_contact->next != NULL) {
            dir_insert(new_dir, current_contact->next->name, current_contact->next->num);
            struct contact* temp = current_contact->next;
            current_contact->next = current_contact->next->next;
            free_contact(temp);

        }

    }
    dir_free(dir);
    
    return new_dir; <<<=== v important
}

clean up contacts

void free_contact(struct contact* contact) {
    free(contact->name);
    free(contact->num);
    free(contact);
}
void contact_free(struct contact* contact) {

    if (contact == NULL) {
        return;
    }

    while (contact != NULL) {
        struct contact *temp = contact;
        contact = temp->next;
        free_contact(temp);
    }
    
}

output

------------------------ANNUAIRE-----------------------
Nombre de contacts :4
Taille de l'annuaire :11
Name -> B, Number -> 0678346533
END.
Name -> C, Number -> 06723236533
END.
Name -> D, Number -> 06723236533
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Liste vide.
END.
Name -> A, Number -> 06789435351
END.
--------------------------------------------------------
==14321==
==14321== HEAP SUMMARY:
==14321==     in use at exit: 0 bytes in 0 blocks
==14321==   total heap usage: 48 allocs, 48 frees, 2,166 bytes allocated
==14321==
==14321== All heap blocks were freed -- no leaks are possible
==14321==
==14321== For lists of detected and suppressed errors, rerun with: -s
==14321== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文