如果这个问题是基本的,我很抱歉——我对C很陌生,仍然有点不确定数组是如何处理的,而不是内存中的指针(指向数组)。(例如,正如所讨论的here)
以下代码片段与我遇到的问题类似。假设我在一个:
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;
我有一个函数,它接受一个指向列表的指针,希望能修改它。例如
void add_item_to_sublist(List *list, int sublist_number, const char *new_item) {...
目标是(如果有效的话,我会对其进行修饰)在指定的子列表中添加一个新项。
有一次我基本上做到了以下几点:
Sublist current = list->sublists[sublist_number];
然后执行将新的项目附加到当前项的操作。也许这并不让你吃惊,但这次失败了。当我试图找出哪里出了问题时,我突然想到这个问题可能与传递值范式有关,所以我试着
Sublist *current = &list->sublists[sublist_number];
相反,这起作用了。
这就是我的困惑。一方面,我发现存在一个传递值问题,所以如果current只存在于函数的框架中,那么很明显,在函数终止后,它会随着我的修改而消失。但另一方面,我认为带结构的赋值在内存中,即“引用副本”的情况-所以我最初认为,对当前(第一个版本)的任何更改都会自动更改子列表[子列表编号]。
有人能帮我理解我的错误吗?
最佳答案
这个问题与传递值无关,传递值与传递给函数的参数有关(这可能会导致类似的问题),而是与您正在分配给一个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;
但这没有意义,因为你不需要拷贝,但你想修改原始数据。
这就是为什么使用
*
,所以现在current是一个Sublist*
变量。它不是Sublist
的实例,而是指向(希望)存在的Sublist
实例的指针。现在,通过current
所做的每个修改都会反映到原始数据,因为没有其他实例。