简体   繁体   English

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

[英]Initialise struct pointers in a function in C

I'm fairly new to C and I'm a little confused as to the correct way to initialise struct variables which are pointers, within a function. 我对C很新,我对在函数中初始化作为指针的struct变量的正确方法感到困惑。 Is this style sufficient, or do I need to allocate memory before I assign s->str? 这个样式是否足够,或者在分配s-> str之前是否需要分配内存? Thank you kindly for your replies, apologies if the question is unclear as I am very new to this language. 谢谢你的回复,如果问题不清楚,我会道歉,因为我对这门语言很陌生。

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;
}

your function is legal and doesn't do anything bad. 你的职能是合法的,没有做任何坏事。 Nevertheless, you should document it to mention that the strings are not copied, only the pointers are. 不过,你应该记录它,提到不复制字符串,只有指针。

So if the passed data has a shorter life than the structure itself, you may meet undefined behaviour. 因此,如果传递的数据的寿命比结构本身短,则可能会遇到未定义的行为。 Example: 例:

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
}

the above code is undefined behaviour for the first print because s->a points to some memory that is no longer allocated (local to func ). 上面的代码是第一次打印的未定义行为,因为s->a指向一些不再分配的内存( func本地)。 The second print is OK because s2->a points to a string literal which has infinite life span. 第二次打印是正常的,因为s2->a指向具有无限寿命的字符串文字。

So maybe your function is more useful like this: 所以也许你的功能更有用:

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

now the memory is allocated for the strings. 现在为字符串分配了内存。 Don't forget to free it when discarding the structure, better done in another utility function. 丢弃结构时不要忘记free它,最好在另一个实用功能中完成。

If the strings being passed in to str and str2 will always be string constants than yes you can get away with doing it this way. 如果传入strstr2字符串总是字符串常量而不是yes,那么你就可以这样做了。 My guess however is that this is not the case. 但我的猜测是,事实并非如此。 So you would be better off making a copy of each string with strdup and assigning those to the struct members: 所以你最好用strdup制作每个字符串的副本并将它们分配给struct成员:

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

Just make sure to free each of those fields before freeing the struct. 只需确保在释放结构之前释放每个字段。

Think of it this way: when you allocate memory for the struct, you get the pointer member variables for free. 可以这样想:当你为struct分配内存时,你可以免费获得指针成员变量。 So in essence, when you do this: 所以从本质上讲,当你这样做时:

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

Then you can treat s->str1 in the exact same way as you would any regular char* variable, say 然后你可以用与任何常规char*变量完全相同的方式处理s->str1

char *str1 = NULL;

If you want it to point to something, then you have to allocate memory for the pointers. 如果你想让它指向某个东西,那么你必须为指针分配内存。 Consider this: 考虑一下:

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;
}

Also note that if you just assign to a pointer by using the = operator instead of allocating memory, then it will only copy the address to the original value. 另请注意,如果您只是使用=运算符而不是分配内存来指定指针,那么它只会将地址复制到原始值。 This may or may not be what you want depending on the context. 根据具体情况,这可能是您想要的,也可能不是。 Generally, if you know the memory location will stay in scope and you don't need (or don't mind) to change the original string, then it is preferred to simply assign it. 通常,如果您知道内存位置将保留在范围内并且您不需要(或不介意)更改原始字符串,则最好只是分配它。 Otherwise, it is advisable to make a copy. 否则,建议复制。

//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;

Use strncpy() instead of strcpy(). 使用strncpy()而不是strcpy()。 The latter is subject to buffer overruns. 后者受到缓冲区溢出的影响。

For example in this code snippet given by another user, use the strncpy() in place of 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;

} }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM