C语言 在一个循环内部,一个链表看起来很好,但是在外部它是空的

3bygqnnd  于 2022-12-17  发布在  其他
关注(0)|答案(2)|浏览(111)

我刚开始学习C语言,在试图从文本文件中读取汽车和它们的制造年份时,我迷路了。当我尝试读取包含以下行的.txt文件时,程序说它找不到任何汽车:

Lada 1976
Ferrari 2005
Suzuki 1985
Volvo 1963
Toyota 1993
Honda 2011

我做了一个类似的链表程序,从用户那里读取一个整数来添加到链表中,而不是一个文件。我认为这是完全相同的,除了现在程序从一个文件中读取,指针first出错了(根据我添加到几个地方的调试打印,我最好的猜测是)或者可能是我设法只在while循环内更改了节点(另一种猜测)有人能指出这里出了什么问题吗?

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

typedef struct car {
    char brand[15];
    int year; 
    struct car *prev; 
    struct car *next; 
} car;

void readCars(char *fname, car *newCar, car *first, car *last);
void printCars(car *ptr, car *first);
void freeMemory(car *ptr, car *first);

int main(int argc, char *argv[]) {
    car *first = NULL; // a pointer to the first node of the linked list
    car *last = NULL; // a pointer to the last node of the linked list
    car *newCar; // a pointer for new nodes
    car *ptr; // a pointer for iterating the linked list
    if(argc != 2) {
        printf("No filename provided.\n");
        exit(0);
    } 
    printf("Reading the file %s.\n", argv[1]);
    readCars(argv[1], newCar, first, last);
    printCars(ptr, first);
    freeMemory(ptr, first);
    printf("Program ended.\n");
    return(0);
}

void readCars(char *fname, car *newCar, car *first, car *last) {    
    FILE *tiedosto;
    char rivi[22];
    if ((tiedosto = fopen(fname, "r")) == NULL) {
        printf("Failed to open the file.\nProgram ended.\n");
        exit(0);
    }
    while (fgets(rivi, 22, tiedosto) != NULL) {
        if ((newCar = (car*)malloc(sizeof(car))) == NULL) { // allocate memory for a new node
                perror("Memory allocation failure.\n");
                exit(1);
        }
        sscanf(rivi, "%s %d", newCar->brand, &newCar->year); // set the car brand and age to the new node
        newCar->next = NULL; // set the pointer to next node to NULL as there is no next node
        newCar->prev = last; // set the pointer to the previous node to the previous last node (NULL if there was no previous)
        if (first == NULL) { 
            first = newCar; // the new node is the only node so it is the first node
            last = newCar; // the new node is the only node so it is also the last node
        } else {
            last->next = newCar; // the new node is next node of the previous last node
            last = newCar; // the new node is now the last node
        }
    }
    fclose(tiedosto);
    printf("File read into a linked list.\n");
}

void printCars(car *ptr, car *first) {
    if(first == NULL) {
        printf("No cars found.\n");
    } else {
        ptr = first;
        int count = 1;
        while (ptr != NULL) {
            printf("%d. car: %s from the year %d.\n", count, ptr->brand, ptr->year);
            count += 1;
            ptr = ptr->next;
        }
    }
}

void freeMemory(car *ptr, car *first) { 
    ptr = first;
    while (ptr != NULL) {
        first = ptr->next;
        free(ptr);
        ptr = first;
    }
    printf("Memory freed.\n");
}
ldioqlga

ldioqlga1#

台词

if (first == NULL) { 
    first = newCar; // the new node is the only node so it is the first node
    last = newCar; // the new node is the only node so it is also the last node
} else {
    last->next = newCar; // the new node is next node of the previous last node
    last = newCar; // the new node is now the last node
}

在函数readCars中只修改函数readCars中的变量firstlast,不修改函数main中的变量firstlast
因此,函数main中的变量first将保持NULL,因此,就该函数而言,链表保持为空。
为了解决这个问题,函数main不应该将变量firstlast的副本传递给函数readCars,而应该传递指向这些变量的指针(即引用),因此您应该将函数readCars的参数更改为:

void readCars(char *fname, car *newCar, car **first, car **last)

您还应将上面引用的行更改为以下内容:

if ( *first == NULL ) { 
    *first = newCar; // the new node is the only node so it is the first node
    *last = newCar; // the new node is the only node so it is also the last node
} else {
    (*last)->next = newCar; // the new node is next node of the previous last node
    (*last) = newCar; // the new node is now the last node
}

另外,函数readCars的参数newCar不作为参数使用,而是作为局部变量使用,因此应该声明为局部变量,并从函数的参数列表中删除。
编辑:正如下面的注解所指出的,你正在对函数printCarsfreeMemory中的参数ptr做同样的事情,你也应该从这些函数中删除这个参数。

h7appiyu

h7appiyu2#

我的解决方案是:

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

typedef struct car {
    char brand[15];
    int year; 
    struct car *prev; 
    struct car *next; 
} car;

void readCars(char *fname, car *newCar, car **first, car **last);
void printCars(car *ptr, car *first);
void freeMemory(car *ptr, car *first);

int main(int argc, char *argv[]) {
    car *first = NULL; // a pointer to the first node of the linked list
    car *last = NULL; // a pointer to the last node of the linked list
    car *newCar; // a pointer for new nodes
    car *ptr; // a pointer for iterating the linked list
    if(argc != 2) {
        printf("No filename provided.\n");
        exit(0);
    } 
    printf("Reading the file %s.\n", argv[1]);
    readCars(argv[1], newCar, &first, &last);
    printCars(ptr, first);
    freeMemory(ptr, first);
    printf("Program ended.\n");
    return(0);
}

void readCars(char *fname, car *newCar, car **first, car **last) {    
    FILE *tiedosto;
    char rivi[22];
    if ((tiedosto = fopen(fname, "r")) == NULL) {
        printf("Failed to open the file.\nProgram ended.\n");
        exit(0);
    }
    while (fgets(rivi, 22, tiedosto) != NULL) {
        if ((newCar = (car*)malloc(sizeof(car))) == NULL) { // allocate memory for a new node
                perror("Memory allocation failure.\n");
                exit(1);
        }
        sscanf(rivi, "%s %d", newCar->brand, &newCar->year); // set the  car brand and age to the new node
        newCar->next = NULL; // set the pointer to next node to NULL as  there is no next node
        newCar->prev = *last; // set the pointer to the previous node to  the previous last node (NULL if there was no previous)
        if (*first == NULL) {
            *first = newCar; // the new node is the only node so it is the  first node
            *last = newCar; // the new node is the only node so it is also  the last node
        } else {
            (*last)->next = newCar; // the new node is next node of the previous last node
            *last = newCar; // the new node is now the last node
        }
    }
    fclose(tiedosto);
    printf("File read into a linked list.\n");
}

void printCars(car *ptr, car *first) {
    if(first == NULL) {
        printf("No cars found.\n");
    } else {
        ptr = first;
        int count = 1;
        while (ptr != NULL) {
            printf("%d. car: %s from the year %d.\n", count, ptr->brand,  ptr->year);
            count += 1;
            ptr = ptr->next;
        }
    }
}

void freeMemory(car *ptr, car *first) { 
    ptr = first;
    while (ptr != NULL) {
        first = ptr->next;
        free(ptr);
        ptr = first;
    }
    printf("Memory freed.\n");
}

主要的区别是readCars需要一个指针来指向first和last,这样,当函数结束时,first和last的值不会变成初始值(在NULL的情况下),如果你理解了,请告诉我。

相关问题