【问题标题】:What is the difference between char *var= NULL; and char var[LENGTH + 1];?char *var= NULL; 有什么区别?和 char var[LENGTH + 1];?
【发布时间】:2023-03-03 00:40:01
【问题描述】:

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

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”只是说“我想要一个可以指向字符的名为 'line' 的变量”,但它实际上并没有指向任何字符。
  • 谁说它们是等价的?显然char line[LENGTH + 1] 正在谈论一些字节数——特别是其中的LENGTH + 1。但同样清楚地char *line = NULL 涉及一个指针,该指针绝对不指向任何地方,当然也不指向任何明确定义的正确分配的字节数!
  • char line[LENGTH + 1]; 表示line 是一个数组,char *line = NULL; 表示line 是一个指针。这是完全不同的东西,但数组变量在使用时通常会衰减为指针。

标签: c segmentation-fault


【解决方案1】:

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

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

请注意,如果文件中的某个单词长于LENGTH,您的程序将超出范围。始终使用边界检查操作。

例子:

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

【讨论】:

    【解决方案2】:

    它们等价。

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

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

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

    【讨论】:

      【解决方案3】:
      char *line = NULL;
      

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

      char line[10];
      

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

      【讨论】:

        【解决方案4】:

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

            char* line = malloc(LEN + 1);
        

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-02-19
          • 1970-01-01
          • 1970-01-01
          • 2019-09-21
          • 2018-12-07
          • 1970-01-01
          • 1970-01-01
          • 2013-06-28
          相关资源
          最近更新 更多