内存中的结构赋值和持久性(C语言)

时间:2017-06-20 00:31:34

标签: c arrays struct

如果这个问题是基本的,我很抱歉 - 我对C非常陌生,并且仍然有点不确定如何处理数组,而不是指针(对于数组),在内存中。 (例如,正如所讨论的here。)

以下代码段与我遇到的问题类似。假设我在一个:

中构造了如此定义的List和Sublist
typedef struct {
char items[MAX_NUM_ITEMS][MAX_ITEM_LENGTH];
int num_items;
} Sublist;

typedef struct {
Sublist sublists[MAX_NUM_SUBLISTS];
int num_sublists;
} List;

我有一个函数,它接受一个指向List的指针,希望能修改它。例如

void add_item_to_sublist(List *list, int sublist_number, const char *new_item) {...

目标是(如果有效,我有点掩饰)将新项目附加到指定的子列表。

有一次,我基本上做了以下事情:

Sublist current = list->sublists[sublist_number];

然后执行将new_item附加到当前的操作。也许这并不让你感到惊讶,但这失败了。在试图弄清楚出了什么问题时,我发现问题可能与传值范式有关,所以我试过

Sublist *current = &list->sublists[sublist_number];

相反 - 这很有效。

所以这是我的困惑。一方面,我认为存在一个按值传递的问题,所以如果当前只存在于我的函数的框架中,那么显然它会在函数终止后被删除,以及我的修改。但另一方面,我认为结构的赋值是在内存中,即“引用副本”情况 - 所以我原本认为对当前(第一个版本)的任何更改都会自动更改子列表[sublist_number]。

有人可以帮助我理解我的错误吗?

2 个答案:

答案 0 :(得分:2)

问题与pass-by-value无关,而pass-by-value与传递给函数的参数有关(这可能会导致类似的问题),但事实上你正在分配给Sublist变量。

Sublist current;

这是一个语义问题。 currentSublist的一个实例,不是某个别名的别名,不是指针而是整个Sublist。分配给它时:

Sublist current = list->sublists[sublist_number];

您正在为Sublist实例分配另一个实例,该实例是通过将整个内容复制到目标而获得的。发生了什么。

然后您修改current,但您正在修改原始副本。你可以重新分配它,例如:

Sublist current = list->sublists[sublist_number];
/* alter current */
list->sublists[sublist_number] = current;

但这没有意义,因为你真的不需要副本,但你想修改原始数据。

这就是你使用*的原因,现在当前是Sublist*变量。它不是Sublist的实例,而是指向(希望)现有Sublist实例的指针。现在,通过current完成的每个修改都反映了原始数据,因为没有其他实例。

答案 1 :(得分:1)

我很高兴你能够修复代码;这是根据您声明的要求判断的正确方法。解释为什么有点难。

您有一个指针list传递给该函数。这意味着您可以修改它指向的结构。当您使用Sublist current = list->sublists[sublist_number];时,您从结构中创建了特定子列表的副本,因为current是一个简单的本地结构。当你使用Sublist *current = &list->sublists[sublist_number];时,你会得到一个指向原始结构子节的指针,你可以使用指针来修改它指向的内容。

这与以下内容没有任何不同:

int current = list->int_array[i];

VS

int *current = &list->int_array[i];

我已经改变了类型(并在你的结构中发明了一个新元素),但基本的想法是一样的。第一个是结构中值的副本,第二个是结构中数据的副本,以便可以修改结构中的值。