为什么我的输出文本文件与我想要的相差这么远。 C 中的结构

问题描述 投票:0回答:1

我正在尝试编写代码,将学生值分配给结构数组(我以前从未使用过)。我知道它部分地按预期方式工作,因为输出文件中的其中一行是正确的,但其他所有内容都偏离了目标。我对 C 编码相当陌生,所以我不完全理解。由于某种原因,某些值正在跨结构传递。

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

typedef struct{
    int Gnum;
    int semester;
    char course[10];
    int credits;
    float grade;
    char name[50];
}studentInfo;
void setStudentInfo(struct studentInfo *s,int *pos,FILE* ptr){
    char buffer[256];
    fseek(ptr,*pos,SEEK_CUR);
    fgets(buffer,256,ptr);
    sscanf(buffer,"%d%[^,],%d%s%d%f",&s->Gnum,s->name,&s->semester,s->course,&s->credits,&s->grade);
    *pos = ftell(ptr);
}

//takes info from input file and writes to output file
int main(int argc, char *argv[]){
    static int pos = 0;
    struct studentInfo s1,s2,s3,s4,s5,s6;
    struct studentInfo arr[]={s1,s2,s3,s4,s5,s6};
    FILE* ptr;
    FILE* ptr2;
    char buffer[50];
    ptr = fopen(argv[1],"r");
    ptr2 = fopen(argv[2],"w+");
    int lines = 0;


    if(ptr == NULL){
        
        printf("Error occurred while trying to open the input file");
        exit(1);
    }
    if(ptr2 == NULL){
        printf("An error occurred with your output file");
        exit(1);
    }
    fseek(ptr,pos,SEEK_CUR);
    fgets(buffer,50,ptr);
    //reads only the first line of the file to get the loop value
    sscanf(buffer,"%d",&lines);
    pos = ftell(ptr);

    for(int i = 0;i<lines;i++){
        setStudentInfo(&arr[i],&pos, ptr);
    }
    for(int i = 0;i<lines;i++){
        fprintf(ptr2,"%-25s%-10d%-8.2f%-10s%-3d%-3d\n",arr[i].name,arr[i].Gnum,arr[i].grade,arr[i].course,arr[i].credits,arr[i].semester);
    }

这是输入文件

6
1134970 Iron Man, 5 CS500 4 9.9689
1156731 Captain America, 2 CS262 3 8.7892
1070965 Black Widow, 3 CS310 3 8.3459
1133656 Clint Barton, 5 CS440 4 6.8921
1259273 Nick Fury, 1 CS101 2 4.6784
1284367 Wanda Maximoff, 3 CS367 4 7.9765

This is the input from the file

这应该是数组的输出内容

 Iron Man                4970      9.97    CS500     4  5  

                        92        76992937979330654969186091637145600.00         0  0  
 Nick Fury               9273      4.68    CS101     2  1  
 Nick Fury               9273      4.68    CS101     2  1  
 Nick Fury               9273      4.68    CS101     2  1  
 Nick Fury               9273      4.68    CS101     2  1  

输入值和输出应匹配且除顺序外不发生更改。

arrays c struct io formatting
1个回答
0
投票
  1. 使用
    argc == 3
    argv[1]
    之前请确保
    argv[2]
  2. struct studentInfo
    不仅仅定义了具有该名称的 typedef,因此请添加该
    struct
    名称,或者在使用该类型时删除
    struct
    关键字。
  3. 消除变量
    s1
    s6
    ,只使用数组
    studentInfo arr[6]
    (见下文)。
  4. 输入文件包含记录数,但您将其硬编码为 6。最好使用
    malloc()
    动态分配数组(请参阅下一步)。
  5. 当您对时间记录进行操作时,只需在单个循环中重用单个
    studentInfo s
    变量即可。
  6. 如果
  7. ptr
     失败,
    ptr2 = fopen(...)
    会泄漏,在正常情况下,
    ptr
    ptr2
    都会泄漏。
  8. (不固定)如果
    ptr
    ptr2
    引用同一个文件,那么你会遇到麻烦。
    w+
    将截断文件,如果您读取较小的记录,然后写入较大的记录,则可能会损坏您的输入。我建议你检查一下这两个文件是否不同。请参阅我可以检查两个 FILE* 或文件描述符编号是否引用同一个文件吗?
  9. main()
    fopen(..., "r")
    将光标定位在开头,因此
    fseek(ptr,pos,SEEK_CUR);
    不执行任何操作。
  10. ftell()
    返回
    long
    (不是
    int
    )。
  11. setStudentInfo()
    : On the first call *pos is relative to the beginning of the file so 
    fseek(ptr,*pos,SEEK_CUR)
    works as expected.  On the 2nd call you are on position 37 and advance another 37 positions.  Use
    SEEK_SET`。
  12. 检查特别是I/O操作的所有返回值。
  13. 使用
    scanf()
    系列函数读取字符串时,始终使用最大字段长度以避免缓冲区溢出。
  14. (不固定)如果第一行大于 50,或后续行大于 256,您将在部分输入上进行操作。检查一下吗?
  15. (未修复)考虑消除所有
    ftell()
    fseek()
    调用。不需要它们。
#include <stdio.h>

#define COURSE_LEN 9
#define NAME_LEN 49
#define str(s) str2(s)
#define str2(s) #s

typedef struct{
    int Gnum;
    int semester;
    char course[COURSE_LEN+1];
    int credits;
    float grade;
    char name[NAME_LEN+1];
} studentInfo;

void setStudentInfo(studentInfo *s,long *pos,FILE* ptr){
    if(fseek(ptr,*pos,SEEK_SET)) {
        printf("fseek failed");
        return;
    }
    char buffer[256];
    if(!fgets(buffer,sizeof buffer,ptr)) {
        printf("fgets failed");
        return;
    }
    if(sscanf(buffer,"%d%" str(NAME_LEN) "[^,],%d%" str(COURSE_LEN) "s%d%f",&s->Gnum,s->name,&s->semester,s->course,&s->credits,&s->grade) != 6) {
        printf("sscanf failed");
        return;
    }
    *pos = ftell(ptr);
    if(*pos == -1) {
        printf("ftell failed");
        return;
    }
}

int main(int argc, char *argv[]){
    if(argc != 3) {
        printf("usage: program INPUT OUTPUT\n");
        return 1;
    }
    FILE *ptr = fopen(argv[1],"r");
    if(!ptr) {
        printf("Error occurred while trying to open the input file");
        return 1;
    }
    FILE *ptr2 = fopen(argv[2],"w+");
    if(!ptr2){
        printf("An error occurred with your output file");
        fclose(ptr);
        return 1;
    }
    long pos = 0;
    if(fseek(ptr,pos,SEEK_CUR)) {
        printf("fseek failed\n");
        goto out;
    }

    char buffer[50];
    if(!fgets(buffer, sizeof buffer, ptr)) {
        printf("fgets failed\n");
        goto out;
    }
    int lines;
    if(sscanf(buffer,"%d",&lines) != 1) {
        printf("failed to read number of records\n");
        goto out;
    }
    pos = ftell(ptr);
    if(pos == -1) {
        printf("ftell failed\n");
        goto out;

    }
    for(int i = 0;i<lines;i++) {
        studentInfo s;
        setStudentInfo(&s, &pos, ptr);
        fprintf(ptr2,"%-25s%-10d%-8.2f%-10s%-3d%-3d\n",s.name,s.Gnum,s.grade,s.course,s.credits,s.semester);
    }
out:
    fclose(ptr);
    fclose(ptr2);
}

运行示例:

./a.out input.txt output.txt && cat output.txt
 Iron Man                1134970   9.97    CS500     4  5  
 Captain America         1156731   8.79    CS262     3  2  
 Black Widow             1070965   8.35    CS310     3  3  
 Clint Barton            1133656   6.89    CS440     4  5  
 Nick Fury               1259273   4.68    CS101     2  1  
 Wanda Maximoff          1284367   7.98    CS367     4  3  
© www.soinside.com 2019 - 2024. All rights reserved.