2017-02-12 6 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」のままであると主張しているとはどういう意味ですか?そして、 'uncirc'関数を使うのは、引数がすべて返ってきたときにどうしたらいいですか? – Jarvis

+1

関連して、 'uncirc'の意味は疑問です。見た目では、列挙ループのためにリストの循環的な性質を破ることが唯一の目的であり、それはまさに列挙論理最初の場所でサークルを破った。 – WhozCraig

+0

@WhozCraigあなたは正しいですが、私はこの問題に遭遇しましたが、それは私が理解するために重要です。 – Yos

答えて

2

リストはないポインタでが含まれています。最初の要素のアドレスのみが存在します。そして、あなたは、メインのポインタがどんな地点にも含まれているアドレスを変更しようとしていません。

最初の要素のアドレスを渡してからそれを使用してリストをトラバースして要素を変更すると、同じアドレスを再度使用すると表示されます。


サイドノート

while(p -> next != light) { 

を渡すリストが円形でない場合、これは無限ループになります。

+0

私は理解していません:私が 'printList'のリストを反復し、繰り返しのために' printList'が受け取る引数である 'light = light - > next'を使うと、' main'の元のリスト何も縮まないだろう。しかし、 'uncirc'は恒久的な変更を残します。 – Yos

+1

@Yos - ポインタをリストとして扱っているので混乱します。 'circ'と' uncirc'の両方は、ポインタが含むアドレスを変更しようとしません。彼らはメモリを変更するだけです。私の家を並べ替えると住所が変わるわけではなく、私の知り合いをすべて更新する必要があります。彼らはまだ同じ住所で私を見つけることができます。 – StoryTeller

+0

それは正しいですが、printListから 'light = light - > next'を反復するのはなぜですか(もし私がそのような方法で反復するのであれば)元のリストを再配置しないでしょうか? – Yos

2

はい「ポインタは値によって渡されます」が、ポインタが指すものは、「値渡し」ないです。つまり、リスト自体はコピーされません。

したがって、関数内で指されているリストを変更すると、リストが変更されます。

+0

元のリストの変更を実際に実行するためにダブルポインタを渡す必要はありませんか? – Yos

+0

リストの開始要素も変更することができます。これは呼び出し関数に反映されないためです。 –

関連する問題