我是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;
}
答案 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)
如果传入str
和str2
的字符串总是是字符串常量而不是是,那么就可以通过这种方式实现。但我的猜测是,事实并非如此。因此,最好使用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;
}