簡體   English   中英

為什么結構的 free() 會導致段錯誤(指針的錯誤使用)?

[英]Why does free() of a struct result in segfault (wrong usage of pointers)?

當我嘗試釋放我的結構時,程序由於段錯誤而崩潰。 valgrind檢查程序我發現:

==9761== Invalid free() / delete / delete[] / realloc()
==9761==    at 0x484827F: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9761==    by 0x109242: destroyHashTable (hashtable.c:38)
==9761==    by 0x10942E: main (hashtable_main.c:17)
==9761==  Address 0x1ffefffa70 is on thread 1's stack
==9761==  in frame #2, created by main (hashtable_main.c:7)

我真的不能說什么比不知道如何解決更有用的了。 崩潰發生在hashtable.cdestroyHashTable(ht)free(ht)期間。 我究竟做錯了什么?

下面的代碼hashTable_main.c

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


#include "hashtable.h"

int main() {

    hashTable* ht = NULL;

    initHashTable(&ht);

    int totalColCount = 0;

    totalColCount += addHashTableEntry(&ht, "PRPR2");

    destroyHashTable(&ht);

    return EXIT_SUCCESS;
}

hashtable.c

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


#include "hashtable.h"

/* private internal API */
int hash_funktion(char *string);
hashtableEntry* createTableEntry(char* newKey) ;
/* end of private internal API */


int hash_funktion(char *string) {
    unsigned int hash_adresse;
    unsigned char *pointer;
    hash_adresse = 0;
    pointer = (unsigned char *) string;
    while(*pointer != '\0') {
        hash_adresse = 19 * hash_adresse + *pointer;
        pointer++;
    }
    return hash_adresse % MAX_HASH;
}

hashtableEntry* createTableEntry(char* newKey) {
     hashtableEntry* e = (hashtableEntry*) malloc (sizeof(hashtableEntry));
     e->hashKey = newKey;
     return e;
}

void initHashTable(hashTable* ht) {
    ht = (hashTable*) malloc (sizeof (struct hashTable));
    ht->table = (hashtableEntry*) malloc (MAX_HASH * sizeof (hashtableEntry));
}

void destroyHashTable(hashTable* ht) {
    if (ht) {
        free(ht);
        ht = NULL;
    }
}

int  addHashTableEntry(hashtableEntry* ht, char* keyValue) {
    hashtableEntry *e = createTableEntry(keyValue);

    int colCounter = 0;

    int hashValue = hash_funktion(keyValue);

    if (ht[hashValue].hashKey == NULL) {
        ht[hashValue] = *e;
        return 0;
    } else {
        int newVal = (hashValue + 1) % MAX_HASH;
        colCounter++;
        while (ht[newVal].hashKey != NULL && newVal != hashValue ) {
            newVal = (newVal + 1) % MAX_HASH;
            colCounter++;
        }
        if (newVal != hashValue) {
            ht[newVal] = *e;  
            return colCounter;      
        } else {
            return -1;
        }
    }
}

bool searchValue(hashtableEntry* ht, char* searchValue) {    
    for (int i = 0; i < MAX_HASH; i++)
    {
        if(ht[i].hashKey == searchValue) {
            return true;
        }
    }
    return false;
}

hashtable.h

#pragma once

#define MAX_HASH 20
#include <stdbool.h>

typedef struct hashtableEntry {
    char* hashKey;
} hashtableEntry;

typedef struct hashTable {
    hashtableEntry* table;
    int elemCount;
} hashTable;

void initHashTable(hashTable* ht);

void destroyHashTable(hashTable* ht);

int  addHashTableEntry(hashtableEntry* ht, char* keyValue);

bool searchValue(hashtableEntry* ht, char* searchValue);

一開始就沒有哈希表。 問題在於initHashTable 它應該接受一個雙指針,因為它被賦予了一個指向它應該初始化的指針的指針。 盡管在destroyHashTable中進行了檢查,它仍可能出現段錯誤的原因是指針未初始化並且在程序執行開始時可能為非零。

void initHashTable(hashTable** ht) {
    *ht = (hashTable*) malloc (sizeof (struct hashTable));
    (*ht)->table = (hashtableEntry*) malloc (MAX_HASH * sizeof (hashtableEntry));
}

您可能會發現返回新創建的 hash 表更容易。 這更好地表達了initHashTable為您提供了一個新的hashTable *值。

hashTable *initHashTable() {
    hashTable *ht = (hashTable *) malloc (sizeof (struct hashTable));
    ht.table = (hashtableEntry *) malloc (MAX_HASH * sizeof (hashtableEntry));
    return ht;
}

還有很多其他地方沒有正確處理指針。

void doThing(Foo *foo) {
    // This changes foo, but not the data foo points to.
    foo = something;
    // This changes the data foo points to
    *foo = someOtherThing;
}

void doStuff() {
    Foo *foo;

    // This is incorrect since it creates a double pointer. doThing would need to
    // be defined as "void doThing(Foo **foo)" to be correct.
    doThing(&foo);

    // Instead we can just pass the existing pointer
    doThing(foo);


    // We only need to create a reference if the value does not start out as a pointer
    Foo bar;
    doThing(&bar);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM