我应该使用strdup()还是只分配一个地址?

时间:2017-04-29 00:09:59

标签: c

我有一个结构,其中一个成员是指向char的指针。

让我们说结构看起来像

  struct{
         int a;
         char *cp;
  }X;

如果我应该这样做,我有点困惑

 X.cp = str;

X.cp = strdup(str);

str是一个字符串。

决定采用哪种实施的标准是什么?

4 个答案:

答案 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);