如果这个问题是基本的,我很抱歉 - 我对C非常陌生,并且仍然有点不确定如何处理数组,而不是指针(对于数组),在内存中。 (例如,正如所讨论的here。)
以下代码段与我遇到的问题类似。假设我在一个:
中构造了如此定义的List和Sublisttypedef 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]。
有人可以帮助我理解我的错误吗?
答案 0 :(得分:2)
问题与pass-by-value无关,而pass-by-value与传递给函数的参数有关(这可能会导致类似的问题),但事实上你正在分配给Sublist
变量。
Sublist current;
这是一个语义问题。 current
是Sublist
的一个实例,不是某个别名的别名,不是指针而是整个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];
我已经改变了类型(并在你的结构中发明了一个新元素),但基本的想法是一样的。第一个是结构中值的副本,第二个是结构中数据的副本,以便可以修改结构中的值。