分段错误但无法解释如何,内存分配看起来很好

hag*_*wal 0 c pointers segmentation-fault

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

typedef struct node
{
    char* word;
    struct node* next;
} node;

node* HashTable =  NULL;
node* HeadOfHashTable = NULL;
Run Code Online (Sandbox Code Playgroud)

现在,我分配了如下内存:

void allocateMemory(int numOfElements, bool isRealloc, const char* word)
{
    if(!isRealloc)
    {
        printf("Allocating %d blocks\n", 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;
}
Run Code Online (Sandbox Code Playgroud)

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

void putInHashTable(char* ch, unsigned int hashValue)
{
    HashTable += hashValue;

    printf("Processing at address: %p and has value was %d\n", HashTable, hashValue);

    if(HashTable == NULL || HashTable == '\0' || 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: %s\n", 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 %p\n", HashTable->word, ch, HashTable->next);
        putInLinkedList(ch);
    }

    HashTable = HeadOfHashTable;
}
Run Code Online (Sandbox Code Playgroud)

以下是控制台日志:

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)
Run Code Online (Sandbox Code Playgroud)

我的疑惑:

  • 我正在分配65336块内存,而我得到段错误的点的哈希值为36032,所以我确信指针变量HashTable具有有效的内存地址.然后为什么seg故障?
  • 如果它不是有效地址,那么为什么它不会陷入此IF状态if(HashTable == NULL || HashTable == '\0' || HashTable == 0).我甚至使用了calloc然后我也得到了seg故障和上面IF条件没有捕获.
  • 我在这条线上遇到了段错误printf(" Earlier value is %s, new value is %s and its pointer is %p\n", HashTable->word, ch, HashTable->next);.这意味着在解除指针时出现一些问题,那么为什么我之前没有得到seg故障,这意味着我应该只在这里遇到段故障 - if(HashTable->word == NULL)

n. *_* m. 5

数着星星.

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

经验法则:在任务的任何一方,星星的数量必须相同.为什么?

      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
Run Code Online (Sandbox Code Playgroud)

好代码的其他例子:

 FOO ** foo_ptr = malloc (sizeof (FOO*) * n_foos); // same number of stars
 FOO *** foo_ptr = malloc (sizeof (FOO**) * n_foos); // still same
Run Code Online (Sandbox Code Playgroud)

不好的代码:

 FOO ** foo_ptr = malloc (sizeof (FOO) * n_foos); // numbers don't match
 FOO * foo_ptr = malloc (sizeof (FOO*) * n_foos); // numbers don't match
Run Code Online (Sandbox Code Playgroud)

你的路线

HashTable = malloc(sizeof(node*) * numOfElements);
Run Code Online (Sandbox Code Playgroud)

(取代型之后HashTablenode*)完全属于成坏码仓,所以要尽量解决这个问题.

如果你想要一个节点数组:

HashTable = malloc(sizeof(node) * numOfElements);
Run Code Online (Sandbox Code Playgroud)

如果你想要一组pouners到节点,你也可以拥有它.这不是真正推荐的,因为节省的空间很小,性能下降可能很大,并且代码不那么优雅.但你可以拥有它:

node** HashTable = malloc(sizeof(node*) * numOfElements); // count! the! stars!
Run Code Online (Sandbox Code Playgroud)

恭喜!你现在有一个numOfElements 未初始化的指针数组.现在您需要将它们初始化为某个值,通常为NULL:

for (i = 0; i < numOfElements; ++i) HashTable[i] = NULL;
Run Code Online (Sandbox Code Playgroud)

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
}
Run Code Online (Sandbox Code Playgroud)

虽然我们正在讨论它,但请注意这些与主要问题相关的时刻:如何正确检查NULL,如何检查返回值malloc,以及如何使用数组索引而不是改变全局指针变量和向前.(如果要使用指针运算,请在本地指针变量中使用putInHashTable).

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