很难说出我的问题,所以我只是给出一个代码示例:
#include <stdio.h>
typedef struct {
char *str;
} strHold;
void f2(char *s)
{
*s = "Char 2";
}
void f3(strHold *str)
{
(*str).str = "Struct 2";
}
int main()
{
char *s1 = "Char 1";
strHold str1;
str1.str = "Struct 1";
//f2(s1);
f3(&str1);
printf("%s, ", s1);
printf("%s", str1.str);
return 0;
}
这个C程序运行,甚至显示&#34; Struct 2&#34;在第二次印刷。但是函数f2不起作用,如果删除注释,程序崩溃。 我实际上并不感到惊讶,f2不起作用,我更想知道为什么f3有效?
当我在函数范围内定义一个字符串常量时,一旦我退出该函数的范围,该数据应该被释放,对吧?这意味着一旦我返回调用函数范围,数据就会变成垃圾。
那么......结构版本如何运作?有人可以解释记忆在这两种情况下是如何运作的,以及&#34;正确的&#34;从调用它的函数初始化调用函数中未知长度的字符串的方法吗?
答案 0 :(得分:2)
您的编译器应该为此行发出警告:
*s = "Char 2";
此处,*s
是char
,您尝试为其分配字符串(char*
)。通过将s1
的地址传递给函数来修复它:
f2(&s1);
并将函数标题更改为:
void f2(char **s)
当我在函数范围内定义一个字符串常量时,一旦我退出该函数的范围,该数据应该被释放,对吧?这意味着一旦我返回调用函数范围,数据就会变成垃圾。
没有。字符串文字具有静态生命周期,这意味着它们只要程序存在就存在。一旦函数结束,只有函数内的局部变量被销毁。
答案 1 :(得分:2)
您不能尝试修改字符串文字,否则您将调用未定义的行为。
"Char 1"
已分配,因此s
的参数f2
包含指向字符串文字的指针。因此,为*s
分配内容意味着您正在尝试修改字符串文字。
要修改调用者的局部变量,请使用指向该变量的指针进行修改。
根据N1256 6.4.5字符串文字-5,你不必释放字符串文字,并且你不能试图释放它们,因为它们被分配了静态存储持续时间。和N1570 6.4.5字符串文字-6。
结构版本有效,因为您将指针传递给结构并使用它来修改结构的成员而不尝试修改任何字符串文字。
此代码可以使用:
#include <stdio.h>
typedef struct {
char *str;
} strHold;
void f2(char **s) /* add * to receive a pointer to char* */
{
*s = "Char 2";
}
void f3(strHold *str)
{
(*str).str = "Struct 2";
}
int main(void)
{
char *s1 = "Char 1";
strHold str1;
str1.str = "Struct 1";
f2(&s1); /* add & to get the pointer to s1 */
f3(&str1);
printf("%s, ", s1);
printf("%s", str1.str);
return 0;
}
答案 2 :(得分:1)
在:
void f2(char *s)
{
*s = "Char 2";
}
你会得到一个编译器错误:你是取消引用指针,它产生一个字符(类型),现在想要为字符分配字符串。
更一般地说,字符串文字必须存储在内存中的某个位置,否则程序无法分配其值。因此,在离开函数后,文字仍然存储在内存中。
答案 3 :(得分:0)
您使用的指针 * s1 应指向足够大的内存块,以便初学者使用足够长的字符串来包含最长的输出。更有经验的程序员应该使用malloc并且适当地免费使用。
初学者:
static char buffer[80]; /* 80 chars of null bytes */
char *s1; /* pointer to string */
s1 = buffer; /* pointer now pointing to beginning of buffer */
strcpy(s1,"Char 1") /* buffer now contains initial text,
rest is null bytes, so string is terminated correctly */