char *var= NULL; 和有什么区别?和 char var[LENGTH + 1];?

What is the difference between char *var= NULL; and char var[LENGTH + 1];?

我正在创建一个函数来加载哈希 Table,如果我的代码如下所示,我会遇到分段错误

bool load(const char *dictionary)
{
    // initialize vars
    char *line = NULL;
    size_t len = 0;
    unsigned int hashed;

    //open file and check it
    FILE *fp = fopen(dictionary, "r");
    if (fp == NULL)
    {
        return false;
    }

    while (fscanf(fp, "%s", line) != EOF)
    {
        //create node
        node *data = malloc(sizeof(node));
        //clear memory if things go south
        if (data == NULL)
        {
            fclose(fp);
            unload();
            return false;
        }

        //put data in node
        //data->word = *line;
        strcpy(data->word, line);

        hashed = hash(line);
        hashed = hashed % N;

        data->next = table[hashed];
        table[hashed] = data;
        dictionary_size++;
    }

    fclose(fp);
    return true;
}

但是如果我替换

char *line = NULL; by char line[LENGTH + 1];(长度为 45)

有效。怎么回事他们不是“等价”的吗?

它们等价。

在第一种情况下 char *line = NULL; 你有一个指向 char 的指针,它被初始化为 NULL。当您调用 fscanf() 时,它会尝试向其写入数据,这将导致它取消引用 NULL 指针。因此出现段错误。

修复的一个选项是先分配(malloc() 和朋友)所需的内存,在使用它之前检查指针不是 NULL(分配失败)。然后,一旦您不再需要数据,您就需要 free() 资源。

在第二种情况下 char line[LENGTH +1] 你有一个大小为 LENGTH + 1char 数组。该内存已在堆栈上为您分配(编译器确保为数组自动发生这种情况),并且内存仅 'valid' 供函数生命周期使用:一旦您 return 就不能不再使用它。现在,当您将指针传递给 fscanf()(在本例中为数组的第一个元素)时,fscanf() 有一个要写入的内存缓冲区。只要缓冲区足够大以容纳正在写入的数据,它就可以正常工作。

当您执行 fscanf(fp, "%s", line) 时,它会尝试将数据读入 line 指向的内存 - 但 char *line = NULL; 不会分配任何内存。

当您执行 char line[LENGTH + 1]; 时,您分配了一个 LENGTH + 1 char 数组。

请注意,如果文件中的单词长度超过 LENGTH,您的程序将越界写入。始终使用边界检查操作。

示例:

while (fscanf(fp, "%*s", LENGTH, line) != EOF)
char *line = NULL;

说“我想要一个名为 'line' 的变量,它可以指向字符,但目前没有指向任何东西。”编译器将分配可以容纳内存地址的内存,并将其填充为零(或“指向无”的其他一些内部表示)。

char line[10];

说“为 10 个字符分配内存,我想使用名称 'line' 作为第一个字符的地址”。它不分配 space 来保存内存地址,因为这是一个常量,但它确实为字符分配 space (并且不初始化它们)。

将指针声明为 NULL 不会为数组分配内存。当您访问指针时,执行的是读取/写入空指针,这不是您想要的。 fscanf 的工作原理是它写入您发送的缓冲区,因此意味着必须事先分配缓冲区。如果你想使用指针,那么你应该这样做:

    char* line = malloc(LEN + 1);

声明为数组时,编译器会为其分配内存,而不是您。这样更好,以防您忘记释放内存,而编译器不会这样做。请注意,如果您确实使用了一个数组(在本例中是一个局部变量),它就不能被调用堆栈上更高层的函数使用,因为正如我上面所说的,内存在 return 从函数。