2017-02-12 11 views
-1

我正在用C编写一个程序。程序接收从标准输入到包含数据的文件的文件路径。然后链接列表是从数据中构建的。为简单起见,链表必须是循环的(用于添加节点,打印列表)我将循环列表转换为常规的非循环链表。这是通过uncirc函数完成的。最后,我使用circ函数将列表组装成圆形结构。为什么从main()向一个函数传递一个链表指针会影响main中的链表?

我将指向链接列表的指针传递给打印列表内容的函数printList。然而,从printList内部使用uncirc后,该列表实际上仍然是“uncirc” - 即使是主要的。据我所知,指针是按值传递的,所以对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; 
    } 
} 
+0

你是什么意思,当你说'这份名单实际上仍然是'未经核实' - 即使是主'?当它所做的只是返回它的参数时,使用'uncirc'函数有什么意义? – Jarvis

+1

相关,'uncirc'的含义是有问题的,因为从它的外观来看,唯一的目的是打破枚举循环的列表的循环性质,枚举循环可以像枚举逻辑一样完成这首先打破了这个圈子。 – WhozCraig

+0

@WhozCraig你是对的,但后来我偶然发现了这个对我来说很重要的问题。 – Yos

回答

2

这份名单是在指针不包含。只有第一个元素的地址在那里。而且你并没有试图修改main中指针包含的地址。

如果您传递第一个元素的地址,然后使用它遍历列表并修改元素,当您再次使用相同的地址进行遍历时,它自然会显示出来。


旁注

while(p -> next != light) { 

如果传递的列表不是圆形的,这将是一个无限循环。

+0

我不明白:如果我迭代'printList'中的列表并迭代,我会使用'print ='接收的参数'light = light - > next','main'中的原始列表不会收缩为无。然而'uncirc'会留下永久的变化。 – Yos

+1

@Yos - 你很困惑,因为你把指针当作你的列表,当它不是的时候。 'circ'和'uncirc'都不会尝试改变指针所包含的地址。他们只对内存进行修改。想想这样:如果我重新安排我的房子,这并不意味着它的地址变化,我需要更新我所有的熟人。他们仍然可以在相同的地址找到我。 – StoryTeller

+0

这是正确的,但为什么从'printList'迭代'light = light - > next'(如果我使用这种方式迭代)不会重新排列原始列表? – Yos

2

是但任何“指针是按值传递”指针指向的“按值传递”。也就是说,列表本身不会被复制。

所以,如果你改变了在一个函数中指向的列表,这个列表就改变了!

+0

我不需要传递一个双指针来实际执行原始列表上的更改? – Yos

+0

是的,你需要,因为列表的起始元素也可以改变,这将不会反映在调用函数中。 –

相关问题