char* 会导致段错误,但 char[] 不会
char* leads to segfault but char[] doesn't
我想我知道自己问题的答案,但我想确认我完全理解这个问题。
我写了一个函数,returns一个字符串。我传一个char*
作为参数,函数修改指针
它工作正常,这是代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void get_file_name(char* file_name_out)
{
char file_name[12+1];
char dir_name[50+12+1];
strcpy(file_name, "name.xml");
strcpy(dir_name, "/home/user/foo/bar/");
strcat(dir_name, file_name);
strcpy(file_name_out, dir_name); // Clarity - equivalent to a return
}
int main()
{
char file_name[100];
get_file_name(file_name);
printf(file_name);
return 0;
}
但是如果我将 char file_name[100];
替换为 char *filename;
或 char *filename = "";
,我会在 strcpy()
.
中遇到分段错误
我不知道为什么?
我的函数接受一个 char*
作为参数和 so does strcpy()
.
As far as I understand、char *filename = "";
创建只读字符串。 strcpy()
然后尝试写入一个只读变量,这是不允许的,因此错误是有道理的。
但是当我写 char *filename;
时会发生什么?我的猜测是在堆栈上分配了足够的 space 来容纳指向 char
的指针,因此我只能在 file_name_out
指向的位置写入一个字符。调用 strcpy()
会尝试写入至少 2,因此会出现错误。
这将解释为什么以下代码会编译并产生预期的输出:
void foo(char* a, char* b)
{
*a = *b;
}
int main()
{
char a = 'A', b = 'B';
printf("a = %c, b = %c\n", a, b);
foo(&a, &b);
printf("a = %c, b = %c\n", a, b);
return 0;
}
另一方面,如果我使用char file_name[100];
,我在堆栈上分配了足够的空间容纳100个字符,所以strcpy()
可以愉快地写入file_name_out
。
我说得对吗?
As far as I understand, char *filename = ""; creates a read-only
string. strcpy() is then trying to write into a read-only variable,
which is not allowed so the error makes sense.
是的,没错。它本质上不同于声明字符数组。初始化一个指向字符串文字的字符指针使其成为只读的;尝试更改字符串的内容会导致 UB。
But what happens when I write char *filename; ? My guess is that
enough space to fit a pointer to a char is allocated on the stack, so
I could write only one single character into my file_name_out
variable.
您分配足够的 space 来存储指向字符的指针,仅此而已。你不能写入*filename
,甚至不能写入一个字符,因为你没有分配space来存储*filename
指向的内容。如果你想改变filename
所指向的内容,首先你必须将它初始化为指向某个有效的地方。
char file_name[100];
创建一个包含 100 个字符的连续数组。在这种情况下,file_name
是一个 (char*) 类型的指针,它指向数组中的第一个元素。
char* file_name;
创建一个指针。但是,它没有被初始化为特定的内存地址。此外,此表达式不分配内存。
我认为这里的问题是
char string[100];
将内存分配给字符串 - 您可以使用字符串作为指针来访问它
但是
char * string;
不会为字符串分配任何内存,因此会出现段错误。
获取您可以使用的内存
string = calloc(100,sizeo(char));
例如,但您需要记住最后使用
释放内存
free(string);
否则你可能会发生内存泄漏。
另一种内存分配方法是使用 malloc
综上所述
char string[100];
等同于
char * string;
string = calloc(100,sizeo(char));
...
free(string);
虽然严格来说 calloc 将所有元素初始化为零,而在 string[100] 声明中数组元素是未定义的,除非你使用
字符串[100]={}
如果您使用 malloc 而不是对内存进行分级,则内容是未定义的。
@PaulRooney 提出的另一点是 char string[100] 在堆栈上分配内存,而 calloc 使用堆。 For more information about the heap and stack see this question and answers...
char *filename;
不分配任何内容。它只是一个指向未指定位置的指针(该值是之前该内存中的任何值)。使用此指针永远不会起作用,因为它可能指向您的程序允许使用的内存范围之外。
char *filename = "";
指向一段程序数据段。正如您已经说过的,它是只读的,因此尝试更改它会导致段错误。
在您的最后一个示例中,您正在处理单个 char
值,而不是 char 值的字符串,并且您的函数 foo
将它们视为这样。因此 char* 值指向的缓冲区长度没有问题。
我想我知道自己问题的答案,但我想确认我完全理解这个问题。
我写了一个函数,returns一个字符串。我传一个char*
作为参数,函数修改指针
它工作正常,这是代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void get_file_name(char* file_name_out)
{
char file_name[12+1];
char dir_name[50+12+1];
strcpy(file_name, "name.xml");
strcpy(dir_name, "/home/user/foo/bar/");
strcat(dir_name, file_name);
strcpy(file_name_out, dir_name); // Clarity - equivalent to a return
}
int main()
{
char file_name[100];
get_file_name(file_name);
printf(file_name);
return 0;
}
但是如果我将 char file_name[100];
替换为 char *filename;
或 char *filename = "";
,我会在 strcpy()
.
我不知道为什么?
我的函数接受一个 char*
作为参数和 so does strcpy()
.
As far as I understand、char *filename = "";
创建只读字符串。 strcpy()
然后尝试写入一个只读变量,这是不允许的,因此错误是有道理的。
但是当我写 char *filename;
时会发生什么?我的猜测是在堆栈上分配了足够的 space 来容纳指向 char
的指针,因此我只能在 file_name_out
指向的位置写入一个字符。调用 strcpy()
会尝试写入至少 2,因此会出现错误。
这将解释为什么以下代码会编译并产生预期的输出:
void foo(char* a, char* b)
{
*a = *b;
}
int main()
{
char a = 'A', b = 'B';
printf("a = %c, b = %c\n", a, b);
foo(&a, &b);
printf("a = %c, b = %c\n", a, b);
return 0;
}
另一方面,如果我使用char file_name[100];
,我在堆栈上分配了足够的空间容纳100个字符,所以strcpy()
可以愉快地写入file_name_out
。
我说得对吗?
As far as I understand, char *filename = ""; creates a read-only string. strcpy() is then trying to write into a read-only variable, which is not allowed so the error makes sense.
是的,没错。它本质上不同于声明字符数组。初始化一个指向字符串文字的字符指针使其成为只读的;尝试更改字符串的内容会导致 UB。
But what happens when I write char *filename; ? My guess is that enough space to fit a pointer to a char is allocated on the stack, so I could write only one single character into my file_name_out variable.
您分配足够的 space 来存储指向字符的指针,仅此而已。你不能写入*filename
,甚至不能写入一个字符,因为你没有分配space来存储*filename
指向的内容。如果你想改变filename
所指向的内容,首先你必须将它初始化为指向某个有效的地方。
char file_name[100];
创建一个包含 100 个字符的连续数组。在这种情况下,file_name
是一个 (char*) 类型的指针,它指向数组中的第一个元素。
char* file_name;
创建一个指针。但是,它没有被初始化为特定的内存地址。此外,此表达式不分配内存。
我认为这里的问题是
char string[100];
将内存分配给字符串 - 您可以使用字符串作为指针来访问它 但是
char * string;
不会为字符串分配任何内存,因此会出现段错误。
获取您可以使用的内存
string = calloc(100,sizeo(char));
例如,但您需要记住最后使用
释放内存free(string);
否则你可能会发生内存泄漏。
另一种内存分配方法是使用 malloc
综上所述
char string[100];
等同于
char * string;
string = calloc(100,sizeo(char));
...
free(string);
虽然严格来说 calloc 将所有元素初始化为零,而在 string[100] 声明中数组元素是未定义的,除非你使用 字符串[100]={} 如果您使用 malloc 而不是对内存进行分级,则内容是未定义的。
@PaulRooney 提出的另一点是 char string[100] 在堆栈上分配内存,而 calloc 使用堆。 For more information about the heap and stack see this question and answers...
char *filename;
不分配任何内容。它只是一个指向未指定位置的指针(该值是之前该内存中的任何值)。使用此指针永远不会起作用,因为它可能指向您的程序允许使用的内存范围之外。
char *filename = "";
指向一段程序数据段。正如您已经说过的,它是只读的,因此尝试更改它会导致段错误。
在您的最后一个示例中,您正在处理单个 char
值,而不是 char 值的字符串,并且您的函数 foo
将它们视为这样。因此 char* 值指向的缓冲区长度没有问题。