C 堆对象如何使用堆栈中的数据?

C 堆对象如何使用堆栈中的数据?,c,pointers,C,Pointers,我已经像这样声明了structfoo: struct foo { const char* name_lower; const char* name_caps //.. }; 我在堆上动态创建foo的实例,并希望在name\u lower和name\u caps成员变量中保存一个值。这是通过功能bar void bar(foo* entry, const char* str, int delimiter_pos) { char l[2] = {str[caps

我已经像这样声明了
struct
foo:

struct foo {
    const char* name_lower; 
    const char* name_caps
    //..
};
我在堆上动态创建
foo
的实例,并希望在
name\u lower
name\u caps
成员变量中保存一个值。这是通过功能
bar

void bar(foo* entry, const char* str, int delimiter_pos) {

    char l[2] = {str[caps_pos-1], '\0'}; // create new string
    char c[2] = {str[caps_pos+1], '\0'};

    entry->name_lower = &l[0]; // assign these strings the foo instance
    entry->name_caps =  &c[0];
}
我很担心,因为我不知道这个代码是否会崩溃。临时创建的数组
l
c
将保存在堆栈上。一旦函数终止,堆栈将被清除,
c
l
可能会消失


这是否意味着
foo
实例将丢失其名称,即其引用?如果是这样,我如何解决这个问题呢?

您应该使用
char*l=(char*)malloc(2*sizeof(char))然后初始化它;类似于
char*c
。然后设置
entry->name\u lower=l;条目->名称\u caps=c

分配时,确保检查分配是否成功,即
malloc
是否返回非空地址


确保在不再需要内存后释放内存:
free(entry->name\u lower);免费(输入->姓名/大写)

它不会丢失任何东西。
struct
中的指针将保留其值,但内容将发生变化,最终您将获得SIGSEGV

要使
char*
持久化,还需要在堆上分配它

void条(foo*entry、const char*str、int分隔符\u pos){
char*l=malloc(2);
char*c=malloc(2);
/*检查l和c是否为空*/
l[0]=str[caps_pos-1];
l[1]='\0';
c[0]=str[caps_pos+1];
c[1]='\0';
条目->名称\u下=l;
条目->名称\u caps=c;
}

请记住,当不再需要结构成员时,还应
free()
该结构成员。

从注释继续,为
l
c
的新内存块分配/复制和分配起始地址的最简单方法是使用
strdup
(来自
string.h
):


当不再需要时,不要忘记
释放
分配给
entry->name\u lower
entry->name\u caps
的内存。

如果字符串长度有限制,可以使用
char
数组而不是指针。在您的示例中,所有字符串的长度均为1。假设字符串不能超过这个长度,可以使用
char[2]
而不是
char*

struct foo {
    char name_lower[2];
    char name_caps[2];
    //..
};

void bar(foo* entry, const char* str, int delimiter_pos) {
    entry->name_lower[0] = str[caps_pos-1];
    entry->name_lower[1] = '\0';
    entry->name_caps[0] = str[caps_pos+1];
    entry->name_caps[1] = '\0';
}
历史注释:


因为这很容易使用,人们习惯了这一点,并强制对字符串长度进行人为限制,导致缓冲区溢出。如果您的字符串不受限制,请使用动态分配,而不要使用
char
数组。

谷歌搜索“动态内存分配”-我知道动态内存分配的原则。这是否意味着我必须通过调用malloc将l和c存储在堆上?是的,没错。否则,它们将指向在流从
条返回后将包含未定义值的地址。是的,因为在函数体结束后,指针不应该被取消引用。另一种放置指针的方法是当函数终止时,函数堆栈帧连同函数的所有局部变量一起被销毁。因此,您必须将
1
c
复制到
bar
中的新内存块中,并将新块的起始地址分别分配给
entry->name\u lower
entry->name\u caps
struct foo {
    char name_lower[2];
    char name_caps[2];
    //..
};

void bar(foo* entry, const char* str, int delimiter_pos) {
    entry->name_lower[0] = str[caps_pos-1];
    entry->name_lower[1] = '\0';
    entry->name_caps[0] = str[caps_pos+1];
    entry->name_caps[1] = '\0';
}