2016-07-16 970 views
-2

我正在學習C中的數據結構,並認爲實現相同, 下面是代碼和它給怪異的輸出,它顯示正確的數據時,顯示在添加記錄功能,但當相同函數被調用從主值改變,我知道它與價值調用有關,但無法弄清楚確切的原因。鏈接列表添加功能不按預期工作

PS:抱歉,如果程序過長或不按標準

#include <stdio.h> 
#include <stdlib.h> 

struct record; 
typedef struct record data_record; 

struct record{ 
    int data; 
    struct record *next_record; 
}; 

// forward function declarations 
data_record *get_record(); 
void initialize_record(data_record *,int); 
void display_record(data_record *); 
void display_list(data_record *,int); 
data_record *generate_link_list(data_record *,int); 
void add_record(data_record *,data_record,int); 

int main(int argc,char *argv[]) 
{ 
    printf("Initializing the data ... \n"); 
    printf("Data length: %d \n",sizeof(data_record)); 
    int array_length = 5; 

    data_record *start; 
    // generate_list function 
    start = generate_link_list(start,array_length); 
    printf("------------------------------------\n\n"); 
    display_list(start,array_length); 
    printf("Address : %x \n",start); 

    // add the extra item to the existing list 
    data_record record; 
    record.data = 100; 
    record.next_record = NULL; 
    add_record(start,record,2); 
    display_list(start,array_length +1); 

    printf("Terminating the program \n"); 
    return 0; 
} 

data_record *get_record() 
{ 
    return (data_record *)malloc(sizeof(data_record)); 
} 

void initialize_record(data_record *record,int data) 
{ 
    record->data = data; 
    record->next_record = NULL; 
} 

void display_record(data_record *record) 
{ 
    printf("Printing data: \t"); 
    printf("Data: %d \t",record->data); 
    printf("Next Item address: %x \n",record->next_record); 
} 

void display_list(data_record *list,int length) 
{ 
    data_record *list_pointer = list; 
    printf("Printing the list: \n"); 
    int index; 
    for(index = 0;index < length;index++) 
    { 
     display_record(list_pointer); 
     list_pointer = list_pointer->next_record; 
    } 
    printf("Done with the printing \n"); 
} 

data_record *generate_link_list(data_record *list,int array_length) 
{ 
    list = get_record(); 
    initialize_record(list,0); 
    data_record *current_record_pointer, *record; 
    int index = 0; 

    current_record_pointer = list; 

    printf("First record: "); 
    display_record(current_record_pointer); 

    for(index = 1;index < array_length;index ++) 
    { 
     record = get_record(); 
     initialize_record(record,index); 
     current_record_pointer->next_record = record; 
     current_record_pointer = record; 
    } 
    return list; 
} 

void add_record(data_record *list,data_record record,int position) 
{ 
    printf("Start address %x \n",list); 
    printf("New record address %x \n",&record); 
    data_record *list_pointer = list; 
    int list_position = 0; 
    for(list_position = 0;list_position < position - 1;list_position ++) 
    { 
     list_pointer = list_pointer->next_record; 
    } 
    if(list_pointer != NULL) 
    { 
     data_record *next_record = list_pointer->next_record; 
     list_pointer->next_record = &record; 
     record.next_record = next_record; 
    } 
    display_list(list,6); 
} 

從add函數調用時display_list顯示正確的,但同樣從主叫值改變

附加功能後,當

回答

2

問題是傳遞給add_recordrecordmain中的record的副本。當參數是一個結構時,這就是通過值傳遞的方式。所以對record的更改只會影響副本,而不會影響原始副本。

要解決此問題,聲明record爲指針

void add_record(data_record *list,data_record *record,int position) 
{ 
    ... 

    list_pointer->next_record = record; 
    record->next_record = next_record; 

    ... 
} 

main

add_record(start,&record,2); 

旁註通過記錄的地址:這是毫無意義的start傳遞給generate_link_list由於start不包含generate_link_list需要的任何信息或使用。因此,將其更改爲:

data_record *generate_link_list(int array_length) 
{ 
    data_record *list = get_record(); 

    ... 
} 

另注:正如評論所指出的@JonathanLeffler,你應該總是使用get_record函數來創建記錄。我會走得更遠,並說get_recordinitialize_record應該組合成單一功能create_record,例如,

data_record *create_record(int data) 
{ 
    data_record *record = malloc(sizeof(data_record)); 
    if (record) 
    { 
     record->data = data; 
     record->next_record = NULL; 
    } 
} 

然後在main代碼變得

// add the extra item to the existing list 
data_record *record = create_record(100); 
if (record) 
    add_record(start,record,2); 
display_list(start,array_length +1); 

通過使用列表中的create_record所有的記錄,你可以放心地在需要的時候free在列表中的項目。

+1

如果你真的很細心,你會注意到在'main()'中定義了'data_record記錄;並且在修改後的代碼中通過地址傳遞給'add_record()'。對於這個答案(當前程序)這可以正常工作,但是當你想要釋放分配給列表的內存時,這個未分配的記錄將成爲災難的根源。確保你統一分配列表中的所有節點。如果不這樣做,釋放與列表關聯的內存將變得非常困難。 –