2017-02-12 10 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

是的,你需要,因爲列表的起始元素也可以改變,這將不會反映在調用函數中。 –

相關問題