C 为什么从main()向函数传递链表指针会影响main中的链表?
我正在用C写一个程序。这个程序接收从标准输入到包含数据的文件的文件路径。然后根据数据构建链表。链表必须是循环的,但是为了简单起见(为了添加节点、打印列表),我正在将循环列表转换为常规的非循环链表。这是通过C 为什么从main()向函数传递链表指针会影响main中的链表?,c,list,pointers,C,List,Pointers,我正在用C写一个程序。这个程序接收从标准输入到包含数据的文件的文件路径。然后根据数据构建链表。链表必须是循环的,但是为了简单起见(为了添加节点、打印列表),我正在将循环列表转换为常规的非循环链表。这是通过unscrc功能完成的。最后,我使用circ函数将列表组装回循环结构 我将指向链接列表的指针传递给函数printList,该函数将打印列表的内容。但是,在从内部printList使用unsrc后,列表实际上仍然是“unsrc”——即使是主列表也是如此。据我所知,指针是按值传递的,因此对print
unscrc
功能完成的。最后,我使用circ
函数将列表组装回循环结构
我将指向链接列表的指针传递给函数printList
,该函数将打印列表的内容。但是,在从内部printList
使用unsrc
后,列表实际上仍然是“unsrc”——即使是主列表也是如此。据我所知,指针是按值传递的,因此对printList
中的列表执行任何操作都不会影响原始列表
下面是代码(我只包含了与问题相关的基本函数,否则代码会非常大)。我怀疑,如果你可以说,我可以很容易地打印列表,即使是在循环结构,但真正困扰我的是,原来的列表是改变了指针
#include <stdio.h>
#include <stdlib.h>
#define MAX_FILE_NAME_LEN 300
#define MAX_LINE_LEN 300
#define MATERIAL_LEN 100
#define FIELDS_IN_LIGHTING_NUM 8
enum l_type {
TABLE = 1, WALL, CEILING
};
typedef struct Lighting {
enum l_type type;
int length;
int width;
int height;
int bulbs;
char material[MATERIAL_LEN];
int strength;
struct Lighting * next;
} Lighting;
char * getFileName();
int getVolume(Lighting * light);
Lighting * uncirc(Lighting * light);
Lighting * circ(Lighting *light);
void addNode(Lighting **head, FILE *fd);
void printNode(Lighting * light);
void printList(Lighting * light);
int countLines(FILE *fd);
void printMaxLight(Lighting * light);
int main() {
FILE * fd;
char * path;
Lighting * n1 = NULL;
int linesInFile, lightNum, i;
path = getFileName();
if(!(fd = fopen(path, "r+"))) {
printf("Cannot open file %s\n", path);
fprintf(stderr, "Cannot open file %s\n", path);
exit(0);
}
linesInFile = countLines(fd);
lightNum = linesInFile / 7;
for(i = 0; !(feof(fd)) && i < lightNum; i++) {
addNode(&n1, fd); //read file data and create node
//7 lines of data are required to create node
}
fclose(fd);
printList(n1); //print the linked list
return 0;
}
Lighting * uncirc(Lighting * light) {
Lighting * p = light;
if(p == NULL) {
return p;
}
while(p -> next != light) {
p = p -> next;
}
p -> next = NULL;
return light;
}
Lighting * circ(Lighting *light) {
Lighting * p = light;
if(p == NULL) {
return p;
}
while(p -> next != NULL) {
p = p -> next;
}
p -> next = light;
return light;
}
void printList(Lighting * light) {
Lighting * p;
p = uncirc(light);
if(p == NULL) {
printf("Empty list\n");
return;
}
while(p != NULL) {
printNode(p);
p = p -> next;
}
}
#包括
#包括
#定义最大文件名\u LEN 300
#定义最大线长度300
#定义材料规格100
#在照明数量8中定义字段
枚举l_类型{
表=1,墙壁、天花板
};
typedef结构照明{
枚举l_类型;
整数长度;
整数宽度;
内部高度;
int灯泡;
炭材料[材料];
内在力量;
结构照明*下一步;
}照明;
char*getFileName();
int getVolume(照明*灯光);
照明*UNCRC(照明*light);
照明*电路(照明*灯);
void addNode(照明**头部,文件*fd);
void打印节点(照明*灯光);
无效打印列表(照明*灯光);
int countLines(文件*fd);
void printMaxLight(照明*灯光);
int main(){
文件*fd;
字符*路径;
照明*n1=零;
int linesInFile,lightNum,i;
path=getFileName();
如果(!(fd=fopen(路径,“r+”)){
printf(“无法打开文件%s\n”,路径);
fprintf(stderr,“无法打开文件%s\n”,路径);
出口(0);
}
linesInFile=计数行(fd);
lightNum=linesInFile/7;
对于(i=0;!(feof(fd))&&inext!=灯){
p=p->next;
}
p->next=NULL;
返回灯;
}
照明*电路(照明*灯){
照明*p=照明;
if(p==NULL){
返回p;
}
while(p->next!=NULL){
p=p->next;
}
p->next=灯;
返回灯;
}
无效打印列表(照明*灯光){
照明*p;
p=UNCRC(光);
if(p==NULL){
printf(“空列表”);
返回;
}
while(p!=NULL){
printNode(p);
p=p->next;
}
}
指针中不包含列表。只有第一个元素的地址在那里。并且您不会试图修改main中指针在任何点包含的地址
如果您传递第一个元素的地址,然后使用它遍历列表并修改元素,那么当您再次使用相同的地址进行遍历时,它自然会可见
旁注
while(p -> next != light) {
如果您传递的列表不是循环的,这将是一个无限循环。是“指针按值传递”,但指针指向的任何对象都不是“按值传递”。也就是说,列表本身不会被复制
因此,如果您更改函数中指向的列表,该列表将被更改 当你说
时,列表实际上保持“unsrc”-即使是主,这是什么意思?当unscrc
函数只返回其参数时,使用该函数有什么意义?与此相关,unscrc
的意义值得怀疑,因为从外观上看,唯一的目的是为了打破枚举循环列表的循环性质,这也可以通过一开始就打破循环的枚举逻辑来完成。@WhozCraig你是对的,但后来我偶然发现了这个问题,这对我理解很重要。我不需要向是否对原始列表执行更改?是的,您需要执行更改,因为列表的起始元素也可以更改,这不会反映在调用函数中。我不明白:如果我在printList
中迭代列表,对于迭代,我将使用light=light->next
,这是printList
接收的参数,那么main
中的原始列表不会收缩为零。但是unscrc
会留下永久性的更改。@Yos-您会感到困惑,因为您将指针视为您的列表,而它不是。circ
和unsrc
都不会试图更改指针包含的地址。他们只会修改内存。这样想:如果我重新安排我的房子,并不意味着它的地址改变,我需要更新我所有的熟人。他们仍然可以在同一个地址找到我。@Yos-因为你把第一栋房子的地址写在了一张纸上。然后你去了那里,得到了第二所房子的地址。你在自己的一张纸上写的,你没有在第一个房子里修改这张纸。所以列表的逻辑结构保持不变。@Yos-Yup。有人不仅给你复印了他们的论文,还把原件递给了你。如果你一直覆盖它