我认为我在理解字符串和字符串文字时遇到一些问题。
这是我从类中学到的,传递给函数时,const char *表示这是字符串文字,而char *表示字符串。
假设我有一个结构声明:
struct node{
char *name;
struct node *next;
};
和一个函数,这是我要实现的函数:
void load_buffer(struct node *input_node, char *input_name);
该功能应该将input_name分配给结构的成员名称。
我的困惑来自这里。我应该在load_buffer主体内写:
input_node->name = input_name;
还是我应该使用strcpy / strncpy来做到这一点?
strcpy(input_node->name, input_name);// Suppose it's safe in this case.
总而言之,我不确定是否应该使用直接赋值或strcpy族函数将字符串/字符串文字赋值给struct成员。
感谢您的帮助。 :)
答案 0 :(得分:3)
在分配指针的情况下,每个节点中的指针将指向相同的位置。因此,节点将始终指向更新的值。如果要使每个节点包含不同的input
,则此方法不适合您的要求。
input_node->name = input_name;
对于strcpy
,每个节点中的指针将指向不同的位置。在此之前,您需要为每个指针创建内存。
input_node->name = malloc(strlen(input_name)+1); //Allocate memory first.
strcpy(input_node->name, input_name);// Suppose it's safe in this case.
答案 1 :(得分:3)
...传递给函数时,
const char *
表示这是字符串文字,而char *
则表示字符串。
不完全是。 const char *
声明该函数将不会尝试修改字符串。因此,它非常适合用于乱抛垃圾,因为它们不能被修改。
对于您的问题,答案是这取决于您的实际要求。但是,如果结构可以在函数之后继续存在并且字符串可以在调用方中更改,则在危险的情况下,只需存储传递的指针即可。让我们看下面的代码:
void load_buffer(struct node *input_node, const char *input_name) {
input_node->name = name;
}
struct node nodes[2];
char buf[4];
const char *data[] = { "foo", "bar"};
for (int i=0; i<2; i++) {
strcpy(buf, data[i]); // suppose it is read from somewhere (file, stdin, socket)
load_buffer(node + i, buf);
}
两个node
对象的name
成员都指向调用者的字符串buf
,并且都指向"bar"
(buf
的内容位于循环结束)!
如果要在调用时保留字符串的值,则应将其复制到分配的内存中:
void load_buffer(struct node *input_node, const char *input_name) {
input_node->name = strdup(name); // allocation errors should be tested...
}
但是当该节点不再使用时,您应该释放name
成员...
答案 2 :(得分:1)
首先要讲一些术语:
"I am a string literal"
char*
(也就是指向char的指针)const char*
(也就是指向常量char的指针)char*
类型的变量的声明:char* str
const char*
类型的变量的声明:const char* cstr
指针不是字符串文字。指针可以指向字符串文字,数组,仅指向单个元素或可以为null。
在C
中,字符串是一个以null结尾的char数组。
您可以在C
中为字符串文字分配一个char*
变量,但是修改字符串文字是非法的,因此强烈建议不要这样做。允许这样做的原因是历史性的。
char* a = "asd"; // allowed, but frowned upon
// a points to a string literal, so we can say a is a string
// a is not a string literal
char b = 'x';
char* c = &b;
// c points to a single char
// we cannot say c is a string
char d[10] = "asd";
// d is a char array. Its content is a string, so we can say d is a string.
// d is not a string literal
// the string literal is copied into the array d
char* e = d; // or equivalent char* e = &d[0];
// e points to a string
char f[4] = {'a', 's', 'd', '\0'};
// f is an array. Its content is a string, so we can say f is a string
char* g = f;
// g points to a string. We can say g is a string
char h[3] = {'a', 's', 'd'};
// h is an array. Its content is NOT a string, because the char array is not null terminated
char* i = h;
// i is not a string
现在再次进行以上所有操作,但不要用char
替换const char
,并且所有注释仍然有效(除了`const char * a =“ asd”现在可以了)。
现在要解决手头的问题。
有两种情况:
每个节点都有自己的字符串,并“拥有”该字符串。每个节点负责为字符串分配内存并释放该内存。只要节点存在,字符串就存在。在这种情况下,请使用malloc
和strcpy
为每个节点创建一个字符串。节点被销毁时,请不要忘记free
字符串。这是最常见的情况,可能是您想要的。
节点不拥有自己的字符串,而是指向外部字符串。不允许为该字符串分配或释放内存。还有另一个实体负责管理该字符串的生存期,并至少在节点处于活动状态时确保该字符串处于活动状态。字符串可以使节点的寿命更长,而不会导致内存泄漏。
例如,请考虑以下情形: