在C中的函数中初始化struct指针

时间:2017-11-08 20:41:14

标签: c pointers struct

我是C的新手,我对在函数中初始化作为指针的结构变量的正确方法感到困惑。这种风格是否足够,或者在分配s-> str之前是否需要分配内存? 非常感谢您的回复,如果问题不清楚,我会道歉,因为我对这门语言不熟悉。

typedef struct Mystruct{
    const char* str1;
    const char* str2;
}mystruct;

mystruct* mystruct_new(const char* str1, const char* str2){
    mystruct *s = (mystruct*)(malloc(sizeof(mystruct)));
    s->str1 = str1;
    s->str2 = str2;
    return s;
}

4 个答案:

答案 0 :(得分:4)

你的功能是合法的,不会做任何坏事。不过,你应该记录它,提到不复制字符串,只有指针是。

因此,如果传递的数据的寿命比结构本身短,则可能会遇到未定义的行为。例如:

mystruct*func()
{
   char a[]="foo";
   char b[]="bar";

   return mystruct_new(a,b);
}
mystruct*func2()
{
   char *a="foo";
   char *b="bar";

   return mystruct_new(a,b);
}

int main()
{
    mystruct *s = func();
    printf(s->a); // wrong, memory could be trashed
    mystruct *s2 = func2();
    printf(s2->a); // correct
    mystruct *s3 = mystruct_new("foo","bar");
    printf(s3->a); // also correct, string literals have global scope
}

上面的代码是第一次打印的未定义行为,因为s->a指向一些不再分配的内存(func本地)。 第二个打印是正常的,因为s2->a指向具有无限寿命的字符串文字。

所以也许你的功能更有用:

mystruct* mystruct_new(const char* str1, const char* str2){
    mystruct *s = malloc(sizeof(mystruct));
    s->str1 = strdup(str1);
    s->str2 = strdup(str2);
    return s;
}

现在为字符串分配了内存。丢弃结构时不要忘记free,最好在另一个效用函数中完成。

答案 1 :(得分:3)

如果传入strstr2的字符串总是是字符串常量而不是是,那么就可以通过这种方式实现。但我的猜测是,事实并非如此。因此,最好使用strdup制作每个字符串的副本,并将其分配给结构成员:

mystruct* mystruct_new(const char* str1, const char* str2){
    mystruct *s = malloc(sizeof(mystruct));
    s->str1 = strdup(str1);
    s->str2 = strdup(str2);
    return s;
}

在释放结构之前,请确保释放每个字段。

答案 2 :(得分:1)

这样想:当你为struct分配内存时,你可以免费获得指针成员变量。所以从本质上讲,当你这样做时:

mystruct *s = malloc(sizeof(mystruct)); //don't cast result of malloc.

然后,您可以使用与常规s->str1变量完全相同的方式处理char*,例如

char *str1 = NULL;

如果你想要它指向什么,那么你必须为指针分配内存。考虑一下:

mystruct* mystruct_new(const char* str1, const char* str2){
    mystruct *s = malloc(sizeof(mystruct);

    char* someString = getMyString(); //gets some arbitrary string
    char* str1 = NULL;//just for demonstration
    int length = strlen(someString) + 1;

   //for struct members
    s->str1 = malloc(sizeof(char) * length);
    strcpy(s->str1, someString);

   //For regular pointers
    str1 = malloc(sizeof(char) * length);
    strcpy(str1, someString);

    return s;
}

另请注意,如果您只是使用=运算符而不是分配内存来指定指针,那么它只会将地址复制到原始值。根据具体情况,这可能是您想要的,也可能不是。通常,如果您知道内存位置将保留在范围内并且您不需要(或不介意)更改原始字符串,则最好只是分配它。否则,建议复制。

//Makes a copy of the string
s->str1 = malloc(sizeof(char) * length);
strcpy(s->str1, someString);

//copies the address of the original value only!
s->str1 = someString;

答案 3 :(得分:0)

使用strncpy()而不是strcpy()。后者受到缓冲区溢出的影响。

例如,在其他用户提供的此代码段中,使用strncpy()代替strcpy()

mystruct* mystruct_new(const char* str1, const char* str2){
    mystruct *s = malloc(sizeof(mystruct);

    char* someString = getMyString(); //gets some arbitrary string
    char* str1 = NULL;//just for demonstration
    int length = strlen(someString) + 1;

   //for struct members
   s->str1 = malloc(sizeof(char) * length);
   strcpy(s->str1, someString);

  //For regular pointers
  str1 = malloc(sizeof(char) * length);
  strcpy(str1, someString);   // replace with strncpy(str1, someString, bufsize);  where bufsize is the maximum number of characters in your string + 1 for the terminator '\0'.  

  return s;

}