C 返回结构数组

C 返回结构数组,c,pointers,C,Pointers,我试图找出如何修改我的代码,使我能够在readFile中创建一个结构数组,然后将该数组返回到main 这是我的数据结构 struct data{ char *model; float engineSize; int cost; char *color; }; 这是我的readFile函数的当前设置,然后是我当前用于此函数的调用 struct data * readFile(){ FILE *fp; int c; int count

我试图找出如何修改我的代码,使我能够在readFile中创建一个结构数组,然后将该数组返回到main

这是我的数据结构

struct data{

    char *model;
    float engineSize;
    int cost;
    char *color;
};
这是我的readFile函数的当前设置,然后是我当前用于此函数的调用

 struct data * readFile(){

    FILE *fp;
    int c;
    int count = 0;
    char *line = NULL;
    size_t len = 0;

    fp = fopen("hw3.data", "r");

    while ((c = fgetc(fp)) != EOF){

        count++;

    }

    if (feof(fp)){

        rewind(fp);

        struct data *vehicles = malloc((sizeof(struct data))* count);


        count = 0;
        char *token = NULL;
        while (getline(&line, &len, fp)!= -1){

            printf("%s", line);

            token = strtok(line,  " ");
            vehicles[count].model = token;

            token = strtok(NULL, " ");
            vehicles[count].engineSize = atof(token);

            token = strtok(NULL, " ");
            vehicles[count].cost = atoi(token);

            token = strtok(NULL, " ");
            vehicles[count].color = token;

        }

    }


}
int main(){

    int check = 1;
    int input;

    while (check == 1){

        printf("Enter a value corresponding to a option on the menu below\n\n");

        printf("1. Sort data by the float value & print high to low\n");
        printf("2. Sort data by the float value & print low to high\n");
        printf("3. Sort data by the int value & print high to low\n");
        printf("4. Sort data by the int value & print low to high\n");
        printf("5. Exit\n\n");

        printf("Enter a value corresponding to the above menu\n");
        scanf("%d", &input);

        //readFile()

        if(input == 1 || input == 2 || input == 3 || input == 4 || input == 5){

            if (input == 5){

                exit(0);

            }if (input == 1){

                //sort float high to low

            }if (input == 2){

                //sort float low to high

            }if (input == 3){

                //sort int value high to low

            }if (input == 4){

                //sort int value low to high

            }

        }else{

            printf("Enter a correct value for the menus above\n\n" );
        }

        readFile();

    }

}
这是我的菜单的主要位置,我将在这里调用readFile函数

 struct data * readFile(){

    FILE *fp;
    int c;
    int count = 0;
    char *line = NULL;
    size_t len = 0;

    fp = fopen("hw3.data", "r");

    while ((c = fgetc(fp)) != EOF){

        count++;

    }

    if (feof(fp)){

        rewind(fp);

        struct data *vehicles = malloc((sizeof(struct data))* count);


        count = 0;
        char *token = NULL;
        while (getline(&line, &len, fp)!= -1){

            printf("%s", line);

            token = strtok(line,  " ");
            vehicles[count].model = token;

            token = strtok(NULL, " ");
            vehicles[count].engineSize = atof(token);

            token = strtok(NULL, " ");
            vehicles[count].cost = atoi(token);

            token = strtok(NULL, " ");
            vehicles[count].color = token;

        }

    }


}
int main(){

    int check = 1;
    int input;

    while (check == 1){

        printf("Enter a value corresponding to a option on the menu below\n\n");

        printf("1. Sort data by the float value & print high to low\n");
        printf("2. Sort data by the float value & print low to high\n");
        printf("3. Sort data by the int value & print high to low\n");
        printf("4. Sort data by the int value & print low to high\n");
        printf("5. Exit\n\n");

        printf("Enter a value corresponding to the above menu\n");
        scanf("%d", &input);

        //readFile()

        if(input == 1 || input == 2 || input == 3 || input == 4 || input == 5){

            if (input == 5){

                exit(0);

            }if (input == 1){

                //sort float high to low

            }if (input == 2){

                //sort float low to high

            }if (input == 3){

                //sort int value high to low

            }if (input == 4){

                //sort int value low to high

            }

        }else{

            printf("Enter a correct value for the menus above\n\n" );
        }

        readFile();

    }

}

谢谢

这几乎是正确的,想法还可以,但有几个问题:

while ((c = fgetc(fp)) != EOF){
        count++;
}
这计算字节数,我认为基于您希望 行数

while ((c = fgetc(fp)) != EOF){
    if(c == '\n')
        count++;
}
我会告诉你行数

while ((c = fgetc(fp)) != EOF){
    if(c == '\n')
        count++;
}
在下面

token = strtok(line,  " ");
vehicles[count].model = token;
...
token = strtok(NULL, " ");
vehicles[count].color = token;
是有效的,但可能不是你想要的<代码>strtok成功返回
行+一些偏移量
,因此如果以后需要 将更多字符添加到
车辆[i]。模式
车辆[i]。颜色
,您可以
覆盖内存<代码>车辆[i]。颜色仅位于偏移量
车辆[i].型号
。如果您甚至想重新分配,
realloc
将失败, 因为您不会在请求的内存开始时重新分配 块同时,这样做会丢失请求内存的开头, 它将泄漏内存,因为您无法释放它(
free(vehicles[i].color)
is 无效)1

另一个问题是,只有初始行具有正确数量的 已分配内存,如果使用非
NULL
指针调用
getline
,则 非零长度,
getline
将在必要时重新分配内存并更新 指针和长度。如果重新分配返回相同的地址,则 以前的值将被覆盖。如果重新分配返回 如果地址不同,则上一个指针将无效

我建议(我认为这是唯一安全的方法)使用
strdup
(如果可用,或
malloc
+
strcpy
)复制令牌 在那之后,你要做:

while (getline(&line, &len, fp)!= -1){
    // the strtok calls
    ...
    free(line);
    line = NULL;
    len = 0;
}
这样,代码就不会泄漏内存,也不会覆盖内存

编辑

我应该改为使用strcpy设置model和color的值

您可以使用strcpy,但需要首先分配内存,因为
model
color
只是指针。
malloc
仅调用保留内存, 它不会初始化它。那么就这么做吧

strcpy(vehicles[count].model, token);
这是错误的,因为它会试图在未定义的 地点。我就是这个意思

我建议(我认为这是唯一安全的方法)您使用
strdup
复制令牌(如果可用,或
malloc
+
strcpy

函数
strdup
基本上就是这样做的:
malloc
+
strcpy
,因此如果 系统有
strdup
您可以这样做:

vehicles[count].model = strdup(token);
if(vehicles[count].model == NULL)
{
    // error handling
    // for example
    // free everything and return

    return NULL;
}
另一种选择是更改结构,而不是使用指向的指针
char
,使用
char
数组:

struct data{
    char model[100];
    float engineSize;
    int cost;
    char color[100];
};
现在可以保存最大长度为99个字符的字符串(这应该足够了) 只需使用
strncpy
即可,无需 额外内存分配:

strncpy(vehicles[count].model, token, sizeof vehicles[count].model);
// making sure to terminate the string
vehicles[count].model[sizeof(vehicles[count].model) - 1] = 0;
另外,我还没有机会更改免费(line)line=null和len=0的代码

我不知道你这是什么意思。只需在后面添加行

vehicles[count].color = token;
while
循环结束之前


那么,我也应该像在文件的第二次迭代中一样使用get行,因为我当前分配过多

第二个循环很好,问题是您被分配了相同的循环(+ 偏移)不同指针的内存位置,以及当
getline
重新分配时 如果获取不同的地址,则上一个指针将无效。这就是为什么

free(line);
line = NULL;
len = 0;
这很重要,你绝对应该这样做

总结:您的循环很好,但您需要进行以下更改:

  • 复制
    标记
    或将结构更改为使用
    字符
    数组
  • 添加

    free(line);
    line = NULL;
    len = 0;
    
    在循环的最后,你会没事的


fotenotes

1
vehicles[i]。模式
只会指向存储器的开头 当且仅当行不以空空格开头时阻止。像你一样 读一个文件,你不能保证这是真的。即使是 是的,我不会指望的。最好在这里做点安全的事,做一个
抄袭<代码>免费(车辆[i].color)
肯定是错误的。

差不多<代码>行
被永久重复使用。在处理每行之后,应该将其清除为null(并且长度arg为零),从而强制为下一行迭代重新分配。请注意,每一行最后都“属于”自己的记录。记住这一点,因为总有一天会有人释放这些数据。此外,您可以使用扩展算法而不是双文件遍历(顺便说一句,它的计数不能正确反映您的记录计数)。使用
fscanf
,例如
fscanf(fp,“%s%f%d%s”…)
并使用固定大小的字符数组分配结构,例如
char model[20],…
所以您不必担心额外的分配我没有使用fscanf的主要原因是因为我不太清楚应该如何使用它,因为它需要的最后一个参数是文件缓冲区。最后一个参数是字符串中变量对应的地址,所以对于“%d”您可以传递
&vehicles[count]。cost
@jeffreyhenen语法为
fscanf(fp,format,arg1,arg2,…)
其中
fp
文件*
对象,
格式
是格式,
arg1
arg2
是指向存储值的变量的指针。注意:如果要
自由(行)