我有一个结构,其中一个成员是指向char的指针。
让我们说结构看起来像
struct{
int a;
char *cp;
}X;
如果我应该这样做,我有点困惑
X.cp = str;
或
X.cp = strdup(str);
str是一个字符串。
决定采用哪种实施的标准是什么?
答案 0 :(得分:2)
假设str
指向地址0x111111,并且该地址处的字符串开头是“foobar”。
执行X.cp = str;
后,X.cp的值将为0x111111,即X.cp“指向”0x111111。此时printf("%s",X.cp)
和printf("%s",str)
将同时打印foobar,printf("%p",X.cp)
和printf("%p",str)
将同时打印0x111111。内存中唯一会改变的是X.cp
的值(它只是0x111111,而不是字符串本身)。
执行X.cp = strdup(str);
后,X.cp的值不会是0x111111,而是新分配的地址;我们假设它是0x222222。
此外,存储在0x111111的字符串将被复制到从0x222222开始的SEVEN地址(即'f''o'''''b''''r''\ 0')。因此,在这种情况下,对内存有两处更改:X.cp的值和新分配的包含字符串的地址块。在这种情况下,前一个案例中的所有printf
s将在此处生成相同的输出,除printf("%p",X.cp)
外,它将打印0x222222
。
这两种分配给X.cp的方法服务于非常不同的目的。如果您希望在访问str时看到X.cp的更改,则应使用第一种情况,反之亦然。另一方面,当您希望能够独立更改X.cp和str时,应使用第二种情况。小心第一种情况:如果你取消分配X.cp或str中的一个,那么你不能试图去引用另一个,否则你会得到一个段错误。
请记住,“字符串”是特殊的。它们不是C中的数据类型。它们是内存中chars
的块,以'\0'
char
终止。
这就是为什么你不应该做*(X.cp) = *str
之类的事情(除非你真的只想复制一个字符)。
最后,我要注意,如果你不使用X.cp
,你可以调用你的变量strdup()
,因为strdup()是一个副本AKA“cp”。
答案 1 :(得分:1)
如果在使用strdup
之前可以销毁或重复使用原始字符串,请使用X.cp
。
例如,如果str
是函数中的本地数组,并且在仍然使用X
时从函数返回,则需要复制该字符串。或者,如果str
是动态分配的字符串,并且函数调用free(str);
,则需要复制它。
如果str
是您读取每一行的缓冲区,则需要复制,因为您要覆盖它。
如果对原始str
内容所做的更改应自动反映在X.cp
中,反之亦然,那么您应该只指定指针。
答案 2 :(得分:0)
如果您知道控制str
,则使用指针。就像你在自己的函数中分配str
并且没有将它存储在其他任何地方一样,没有必要复制它。
如果您想与他人共享str
的更改,请使用指针。
如果您想将自己与其他人str
的使用区分开来,请执行strdup
。
有时你可以知道这一点,通常你不能,但使用你的结构的人确实知道。让用户决定。编写函数以获取char *
并使用该指针。记录您的函数将使用原始指针。
X* X_new( char *str ) {
X* x = malloc( sizeof(X) );
x->cp = str;
x->a = 42; // I don't know what a is for
return x;
}
// The caller lets x control str, x->cp is str.
X* x = X_new( str );
// The caller passes in a copy of str, x->cp and str are independent of each other.
X* y = X_new( strdup(str) );
通过使用指针,它允许用户决定传入指针或副本。如果X_new
strdup(str)
用户没有发言权。
答案 3 :(得分:-1)
完美代码:
X.cp=malloc(strlen(str)+1);
if(X.cp==NULL)
{
printf("not enough memory \n");
return 0;
}
memset(X.cp,0,strlen(str)+1);
X.cp = strdup(str);
/**
*code
**/
if(X.cp)
free(x.cp);