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 + 1
的 char
数组。该内存已在堆栈上为您分配(编译器确保为数组自动发生这种情况),并且内存仅 '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 从函数。
我正在创建一个函数来加载哈希 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 + 1
的 char
数组。该内存已在堆栈上为您分配(编译器确保为数组自动发生这种情况),并且内存仅 '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 从函数。