C语言 分段错误,但无法推理如何,内存分配对我来说看起来不错



我有一个节点,我正在定义它的全局指针变量,如下所示:

typedef struct node
{
    char* word;
    struct node* next;
} node;
node* HashTable =  NULL;
node* HeadOfHashTable = NULL;

现在,我按如下方式分配内存:

void allocateMemory(int numOfElements, bool isRealloc, const char* word)
{
    if(!isRealloc)
    {
        printf("Allocating %d blocksn", numOfElements);
        HashTable = malloc(sizeof(node*) * numOfElements);
    } else {
        printf("Reallocating %d blocks for %s", numOfElements, word);
        HashTable = realloc(HashTable, sizeof(node*) * numOfElements);
    }
    if(HashTable == NULL)
    {
        printf("### Out Of Memory ###n");
        exit(0);
    }
    HeadOfHashTable = HashTable;
}

现在,我正在传递一个 HASH 值和单词以放入哈希表中,在下面的方法中。我已经评论了我在哪里得到赛格错误。

void putInHashTable(char* ch, unsigned int hashValue)
{
    HashTable += hashValue;
    printf("Processing at address: %p and has value was %dn", HashTable, hashValue);
    if(HashTable == NULL || HashTable == '' || HashTable == 0)
    {
        printf("Hash table is NULL");
    }
    if(HashTable->word == NULL)
    {
        HashTable->word = malloc(sizeof(char) * (LENGTH + 1));
        strcpy(HashTable->word, ch);
        printf("New word: %sn", HashTable->word);
    } else {
        printf("### Collision detected ###n"); // ***** BELOW LINE GIVES SEG FAULT ******
        printf("    Earlier value is %s, new value is %s and its pointer is %pn", HashTable->word, ch, HashTable->next);
        putInLinkedList(ch);
    }
    HashTable = HeadOfHashTable;
}

以下是控制台日志:

Allocating 65336 blocks
Processing at address: 0xb7568c28 and has value was 388
New word: a
Processing at address: 0xb756b9a0 and has value was 1843
New word: aaa
Processing at address: 0xb7570c08 and has value was 4480
New word: aaas
Processing at address: 0xb75ae608 and has value was 36032
### Collision detected ###
Segmentation fault (core dumped)

我的疑问:

  • 正在分配 65336 个内存块,而我遇到 seg 错误的点的哈希值为 36032,因此我确定指针变量 HashTable 具有有效的内存地址。那为什么是赛格的错呢?
  • 如果它不是有效的地址,那么为什么它没有被捕获在此 IF 条件中 if(HashTable == NULL || HashTable == '' || HashTable == 0) .我什至使用了calloc然后我也得到了 seg 错误,并且高于 IF 条件没有捕获。
  • 我在这条线上遇到了赛格错误printf(" Earlier value is %s, new value is %s and its pointer is %pn", HashTable->word, ch, HashTable->next);.这意味着在取消引用指针时会出现一些问题,那么为什么我在那之前没有遇到 seg 错误,这意味着我应该只在这里遇到 seg 错误 - if(HashTable->word == NULL)

数星星。

 FOO * foo_ptr = malloc (sizeof (FOO) * n_foos);
 //  ^                                ^             
 //  |                                |
 //  one star to the left of `=`      one star to the right of `=`

经验法则:任务两侧的星星数量必须相同。为什么?

      sizeof(FOO)    sizeof(FOO)    sizeof(FOO)   
     _____________  _____________  ______________
    /             /             /              
     _____________  _____________  ______________
    [_____FOO_____][_____FOO_____][______FOO_____]
    ^
    |
    FOO* foo_ptr; // a FOO* points to a FOO
                  // pointer arithmetic works by incrementing the address
                  // by sizeof(FOO)
                  // and so on

其他良好代码示例:

 FOO ** foo_ptr = malloc (sizeof (FOO*) * n_foos); // same number of stars
 FOO *** foo_ptr = malloc (sizeof (FOO**) * n_foos); // still same

错误代码:

 FOO ** foo_ptr = malloc (sizeof (FOO) * n_foos); // numbers don't match
 FOO * foo_ptr = malloc (sizeof (FOO*) * n_foos); // numbers don't match

您的生产线

HashTable = malloc(sizeof(node*) * numOfElements);

(替换node*HashTable类型后)直接落入错误代码箱,因此请尝试修复它。

如果需要节点数组:

HashTable = malloc(sizeof(node) * numOfElements);

如果你想要一个节点的pouner数组,你也可以拥有它。实际上不建议这样做,因为节省的空间很小,性能下降可能会很大,并且代码不太优雅。但你可以拥有它:

node** HashTable = malloc(sizeof(node*) * numOfElements); // count! the! stars!

祝贺!现在,您有一个numOfElements初始化指针的数组。现在您需要将它们初始化为某个值,通常为 NULL:

for (i = 0; i < numOfElements; ++i) HashTable[i] = NULL;

每次要向表输入值时,都需要分配一个新的node

if (HashTable[hashValue] == NULL) 
{
  HashTable[hashValue] = malloc(sizeof(node));
  if (HashTable[hashValue] == NULL) 
  {
    panic ("Out of memory!");
  }
  HashTable[hashValue]->word = ...
  HashTable[hashValue]->next = ...
} 
else 
{
  // collision etc
}

当我们在这里时,请注意这些与主要问题无关的时刻:如何正确检查 NULL,如何检查 malloc 的返回值,以及如何使用数组索引而不是来回改变全局指针变量。(如果要使用指针算法,请在 putInHashTable 中有一个局部指针变量)。

(当然,如果你不使用n_foos,或者使用calloc,则需要对星星的数量进行心理调整)。

最新更新