当以不同的方式为两个指针分配字符串时,strcpy的行为会有所不同

当以不同的方式为两个指针分配字符串时,strcpy的行为会有所不同,c,C,对不起,我可能会问一个愚蠢的问题,但我想了解以下作业有什么不同吗?strcpy在第一种情况下有效,但在第二种情况下无效 char *str1; *str1 = "Hello"; char *str2 = "World"; strcpy(str1,str2); //Works as expected 编译器是如何理解每个赋值的?请澄清。对不起,这两个例子都是非常错误的,都会导致未定义的行为,可能会崩溃,也可能不会崩溃。让我试着解释一下原因: str1是一个悬空指针。这意味着str1指向

对不起,我可能会问一个愚蠢的问题,但我想了解以下作业有什么不同吗?strcpy在第一种情况下有效,但在第二种情况下无效

char *str1;
*str1 = "Hello";
char *str2 = "World";
strcpy(str1,str2);    //Works as expected


编译器是如何理解每个赋值的?请澄清。

对不起,这两个例子都是非常错误的,都会导致未定义的行为,可能会崩溃,也可能不会崩溃。让我试着解释一下原因:

  • str1
    是一个悬空指针。这意味着
    str1
    指向内存中的某个地方,写入
    str1
    可能会产生任意后果。例如,崩溃或重写内存中的某些数据(例如,其他局部变量、其他函数中的变量,一切皆有可能)
  • *str1=“Hello”
    也是错误的(即使
    str1
    是一个有效的指针),因为
    *str1
    具有类型
    char
    (不是
    char*
    ),并且是悬挂的
    str1
    的第一个字符。但是,您可以为它指定一个指针(
    “Hello”
    ,键入
    char*
    ),这是编译器将告诉您的类型错误
  • str2
    是一个有效的指针,但可能指向只读内存(因此崩溃)。通常,常量字符串以二进制形式存储在只读数据中,您无法对其进行写入,但这正是您在strcpy(str1,str2)中所做的
您想要实现的一个更正确的示例可能是(堆栈上有一个数组):

其他选项(使用动态管理内存):


编辑:@chqrlie在注释中要求将
\define
命名为
STR1\u SIZE
而不是
STR1\u LEN
。可能是为了减少混淆,因为不是“字符串”的字符长度,而是分配的缓冲区的长度/大小。此外,@chqrlie要求不要给出
strncpy
函数的示例。这并不是我的选择,因为OP使用了非常危险的strcpy
strcpy
,所以我选择了可以正确使用的最接近的函数。但是,是的,我应该补充一点,不建议使用
strcpy
strncpy
,以及类似的函数。

对不起,这两个示例都是非常错误的,都会导致未定义的行为,可能会崩溃,也可能不会崩溃。让我试着解释一下原因:

  • str1
    是一个悬空指针。这意味着
    str1
    指向内存中的某个地方,写入
    str1
    可能会产生任意后果。例如,崩溃或重写内存中的某些数据(例如,其他局部变量、其他函数中的变量,一切皆有可能)
  • *str1=“Hello”
    也是错误的(即使
    str1
    是一个有效的指针),因为
    *str1
    具有类型
    char
    (不是
    char*
    ),并且是悬挂的
    str1
    的第一个字符。但是,您可以为它指定一个指针(
    “Hello”
    ,键入
    char*
    ),这是编译器将告诉您的类型错误
  • str2
    是一个有效的指针,但可能指向只读内存(因此崩溃)。通常,常量字符串以二进制形式存储在只读数据中,您无法对其进行写入,但这正是您在strcpy(str1,str2)中所做的
您想要实现的一个更正确的示例可能是(堆栈上有一个数组):

其他选项(使用动态管理内存):


编辑:@chqrlie在注释中要求将
\define
命名为
STR1\u SIZE
而不是
STR1\u LEN
。可能是为了减少混淆,因为不是“字符串”的字符长度,而是分配的缓冲区的长度/大小。此外,@chqrlie要求不要给出
strncpy
函数的示例。这并不是我的选择,因为OP使用了非常危险的strcpy
strcpy
,所以我选择了可以正确使用的最接近的函数。但是,是的,我可能应该补充一点,不建议使用strcpy、strncpy和类似的函数。

编辑:在您编写的第一段代码中,str1=“Hello”相当于分配给str[0],这显然是错误的,因为str1未初始化,因此是无效指针。如果我们假设您的意思是
str1=“Hello”
,那么您仍然是错的:

根据C规范,试图修改字符串文字会导致未定义的行为:它们可能存储在只读存储器(如.rodata)中,或者与其他字符串文字组合,因此您提供的两个代码段都会产生未定义的行为


我只能猜测,在第二个代码段中,编译器将字符串存储在某个只读存储器中,而在第一个代码段中,它没有存储字符串,因此它可以工作,但不能保证

编辑:在您编写的第一个代码段中,
*str1=“Hello”
相当于分配给
str[0]
,这显然是错误的,因为
str1
未初始化,因此是无效指针。如果我们假设您的意思是
str1=“Hello”
,那么您仍然是错的:

根据C规范,试图修改字符串文字会导致未定义的行为:它们可能存储在只读存储器(如.rodata)中,或者与其他字符串文字组合,因此您提供的两个代码段都会产生未定义的行为


我只能猜测,在第二个代码段中,编译器将字符串存储在某个只读存储器中,而在第一个代码段中,它没有存储字符串,因此它可以工作,但不能保证

这里似乎有些混乱。两个片段都调用未定义的行为。让我解释一下原因:

  • char*str1定义指向字符的指针,但
    
    char *str1 = "Hello";
    char *str2 = "World";
    strcpy(str1,str2);    //SEGMENTATION FAULT
    
    #define STR1_LEN 128
    char str1[STR1_LEN] = "Hello"; /* array with space for 128 characters */
    char *str2 = "World";
    strncpy(str1, str2, STR1_LEN);
    str1[STR1_LEN - 1] = 0; /* be sure to terminate str1 */
    
    #define STR1_LEN 128
    char *str1 = malloc(STR1_LEN); /* allocate dynamic memory for str1 */
    char *str2 = "World";
    /* we should check here that str1 is not NULL, which would mean 'out of memory' */
    strncpy(str1, str2, STR1_LEN);
    str1[STR1_LEN - 1] = 0; /* be sure to terminate str1 */
    free(str1); /* free the memory for str1 */
    str1 = NULL;
    
    char *str1;
    
    char *str = "Hello";