【问题标题】:C struct data failing to be consistent outside iterative loopC 结构数据在迭代循环之外无法保持一致
【发布时间】:2017-09-19 20:29:42
【问题描述】:

我有一个程序,我希望使用 fscanf 将汽车数据读入一个 for 循环中的结构数组(我知道,我应该使用 fgets 或其他东西,但它是这个 assinment 所必需的)并排序平均 MPG 数据并使用 fprintf 将排序后的数据输出到新文件。在我读取数据时,在我的 main 函数的 for 循环中,作为调试功能,我打印分配给 struct[i] 的所有数据,然后继续到包含后续数据的文本文件中的下一行结构对象。但是,在所有的数据都输入完毕并且到目前为止一切正常之后,我重新打印了struct数组中的所有信息,前两个数据区域“make”和“model”都取了最后一个struct的字符串分配的。我已经修复了几个小时,但没有找到解决方案。谁能告诉我我的代码做错了什么? 提前谢谢大家!

// Written by 4ur0r4
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct Car {
    char *make;
    char *model;
    int year;
    int city_mpg;
    int highway_mpg;
};

int averagempg(struct Car car) {
    return (car.city_mpg + car.highway_mpg) / 2;
}

void selection_sort(struct Car *cars, int n) {
    struct Car temp;
    int i;
    for (i = 0; i < n - 1; i++) {
        if (averagempg(cars[i]) > averagempg(cars[i + 1])) {
            temp = cars[i];
            cars[i] = cars[i + 1];
            cars[i + 1] = temp;
        }
    }
}

void write_cars(struct Car *cars, int n) {
    FILE *output = fopen("sorted_cars.txt", "w");
    int i;
    for (i = 0; i < n; i++) {
        fprintf(output, "%s ", cars[i].make);
        fprintf(output, "%s ", cars[i].model);
        fprintf(output, "%d ", cars[i].year);
        fprintf(output, "%d ", cars[i].city_mpg);
        fprintf(output, "%d\n", cars[i].highway_mpg);
    }
}

void print_cars(struct Car *cars, int n) {
    int i;
    for (i = 0; i < n; i++) {
        printf("%s ", cars[i].make);
        printf("%s ", cars[i].model);
        printf("%d ", cars[i].year);
        printf("%d ", cars[i].city_mpg);
        printf("%d\n", cars[i].highway_mpg);
    }
}

int main() {
    FILE *input = fopen("cars.txt", "r");
    struct Car cars[9];
    int i;
    char make[20], model[20];
    int year, city_mpg, highway_mpg;
    if (input == NULL) printf("Unable to open file.\n");
    else {
        for (i = 0; i < 9; i++) {
            fscanf(input, "%s %s %d %d %d",
                make,
                model,
                &year,
                &city_mpg,
                &highway_mpg);

            cars[i].make = make;
            cars[i].model = model;
            cars[i].year = year;
            cars[i].city_mpg = city_mpg;
            cars[i].highway_mpg = highway_mpg;

            printf("%s ", cars[i].make);
            printf("%s ", cars[i].model);
            printf("%d ", cars[i].year);
            printf("%d ", cars[i].city_mpg);
            printf("%d\n", cars[i].highway_mpg);
        }
        printf("\n");
        print_cars(cars, 9);

        selection_sort(cars, 9);

        write_cars(cars, 9);

    }
    return 0;
}

这是我得到的结果:

Mercury Sable 2009 18 28
Jeep Wrangler 2016 17 21
Honda Civic 2015 31 41
Toyota Corolla 2015 30 42
Toyota Prius 2010 51 48
Ford Escape 2013 23 33
Ford Fusion 2013 25 37
Acura MDX 2014 20 28
Lexus RX 2013 32 28

Lexus RX 2009 18 28
Lexus RX 2016 17 21
Lexus RX 2015 31 41
Lexus RX 2015 30 42
Lexus RX 2010 51 48
Lexus RX 2013 23 33
Lexus RX 2013 25 37
Lexus RX 2014 20 28
Lexus RX 2013 32 28

这是我正在读取的文本文件:

Mercury Sable 2009 18 28
Jeep Wrangler 2016 17 21
Honda Civic 2015 31 41
Toyota Corolla 2015 30 42
Toyta Prius 2010 51 48
Ford Escape 2013 23 33
Ford Fusion 2013 25 37
Acura MDX 2014 20 28
Lexus RX 2013 32 28

【问题讨论】:

    标签: c struct printf scanf consistency


    【解决方案1】:

    您将每个cars[i].make 设置为make,并将每个cars[i].model 设置为model。所以他们都指向同一个地方。如果汽车的品牌和型号不同,这应该如何工作?

    您需要复制makemodel 中的数据,并使cars[i].makecars[i].model 指向该副本。否则,当您读取下一个品牌和型号时,您将覆盖您曾经存储过上一辆车的品牌和型号的唯一位置。

    如果你的平台有strdup,你可以改:

            cars[i].make = make;
            cars[i].model = model;
    

            cars[i].make = strdup(make);
            cars[i].model = strdup(model);
    

    strdup 函数分配一个新的内存块并将一个字符串复制到其中,返回一个指向新内存块的指针。

    【讨论】:

    • 显示了正确的值,因为它们在您覆盖之前是正确的。您每次都将makemodel 阅读到同一个地方,每次都会覆盖您之前阅读的内容。
    • 我还是有点迷茫,因为我正在打印结构变量“cars[i].make”和“cars[i].model”中的信息,据我所知,我我不再对结构变量调用任何写操作,只有主变量“make”和“model”,它们是 fscanf 在将它们的值写入 car[i 之前写入的“中间人”变量].make 和 car[i].model 另外,我尝试了 strdup,但 Visual Studio 不支持它。它给我一个编译错误。
    • @4ur0r4 你错过了一个基本点——cars[i].model 是一个指针。它指向model。所以如果你改变model,你就是在改变cars[i].model指向的字符串。您需要复制您读入的数据并让cars[i].model 指向该副本。
    • 你是否同意这两种说法: 1)每次你在一个模型中阅读,你在同一个地方阅读。 2) 你不会在任何地方复制你读入的任何字符串。
    • 我愿意!我以前不知道对结构元素的引用是指针,而不是实际元素本身。多亏了你,我才知道!
    猜你喜欢
    • 1970-01-01
    • 2017-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-17
    • 2017-05-02
    相关资源
    最近更新 更多