【问题标题】:After each printed line there are 2 blank lines每个打印行之后有 2 个空白行
【发布时间】:2020-10-31 11:11:41
【问题描述】:

我正在尝试创建一个函数,该函数从文件中读取一些带有学生姓名的成绩并按降序打印成绩。这是函数:

char studenteUN[50];
int punti;
int maxP = MAX_LNG;
int max = -1000;
int min = MAX_LNG;

FILE *ftemp = f;
while(fscanf(ftemp, "%s", studenteUN) != EOF){
  fscanf(ftemp, "%d", &punti);
  if(punti < min)
    min = punti;
}

while (maxP != min) {
  max = -1000;
  ftemp = muovi(f);
  while(fscanf(ftemp, "%s", studenteUN) != EOF){
    fscanf(ftemp, "%d", &punti);
    if(punti > max && punti < maxP)
      max = punti;
  }
  maxP = max;
  ftemp = muovi(f);
  while(fscanf(ftemp, "%s", studenteUN) != EOF){
    fscanf(ftemp, "%d", &punti);
    if(punti == max)
      printf("%s %d\n", studenteUN, punti);
  }
}

输出如下:

阿斯达斯 8 阿斯达斯 7 六号 安德里亚 5 asd 4 asd 1 阿萨德 1 阿斯达斯 0 0

我无法弄清楚为什么会发生这种情况。 我从中读取的文件如下:

2
1- askd a
   1- asd
   2- asd as
   3- asd as d
   4- asdas
   5- Non lo so.
1
2- asdsad asd as d
   1- asd a
   2- asd
   3- asd
   4- as df
   5- Non lo so.
2
andrea 5
asdsa 6
asdas 7
asd 1
asdas 0
asd 0
asdsad 1
asdas 8
asd 4

muovi 功能:

FILE *muovi(FILE *f){
 fseek(f, 0, SEEK_SET);
 char resultato[MAX_LNG];
 int nD;
 fscanf(f, "%d", &nD);
 printf("\n");
 for(int i = 0; i <= nD*7;i++)
  fgets(resultato, MAX_LNG, f);
 return f;
}

【问题讨论】:

  • 什么是muovi(f)?和fseek(f, 0, SEEK_SET)一样吗?
  • edit您的问题包含minimal reproducible example,包括您从中读取的输入文件的示例。
  • 我把你的代码放在main() 函数中,我无法重现问题。
  • 因为printf("\n"); in muovi()
  • 顺便说一句,这是一种可怕的方法,重新读取每个地方的文件。将所有内容读入结构数组,对数组进行排序,然后打印数组。

标签: c file printf


【解决方案1】:

我编写了一个演示示例: 它读取“名称等级”形式的输入:

student1 1
student2 7
student3 -4
student4 11
student5 1111
student6 -11111

然后输出:

student5 1111
student4 11
student2 7
student1 1
student3 -4
student6 -11111

这是后面的代码,也许你可以提出一个想法

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

struct studs {
    int grade;
    char name[50];
};

int md_comparator(const void *v1, const void *v2)
{
    const struct studs *p1 = (struct studs *)v1;
    const struct studs *p2 = (struct studs *)v2;
    
    if (p1->grade < p2->grade)
        return 1;
    else if (p1->grade > p2->grade)
        return -1;
    else
        return 0;
}


int main()
{
    struct studs students[1000];
    struct studs temp;
    
    //read all students into students[] array
    int idx = 0;
    for (; fscanf(stdin, "%s %d", temp.name, &temp.grade) == 2; students[idx++] = temp)
        ;
    
    //sort descending, with the help of qsort and md_comparator function above
    qsort(students, idx, sizeof(students[0]), md_comparator);
    
    //print
    for (int i = 0; i < idx; i++)
        printf("%s %d\n", students[i].name, students[i].grade);
    
    return 0;
}

【讨论】:

  • 如果您将带有fgets() 的每一行读入缓冲区,然后使用sscanf 解析缓冲区,检查返回值是否为2——您可以读取整个文件,只挑选学生数据.
【解决方案2】:

从文件中读取数据行时,您希望使用面向行的输入函数,例如fgets() 或POSIX getline()。这可确保在每次读取期间消耗完整的输入行。否则,在查找模式时,如字符串后跟整数,部分读取可能会导致错误匹配,具体取决于输入缓冲区中未读取的行的哪些部分。

将每一行读入缓冲区后,您只需使用sscanf() 解析每行所需的信息,而不是尝试使用fscanf() 进行读取和解析。

综上所述,从文件中仅读取和隔离学生姓名和编号完全没有问题,例如

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

#define NAMC 50         /* if you need a constant, #define one (or more) */
#define MAXC 1024

typedef struct {        /* struct for student name and number */
    char name[NAMC];
    int no;
} student;

int cmpstd (const void *a, const void *b)   /* qsort descending by student.no */
{
    const student *pa = a, *pb = b;
    
    return (pa->no < pb->no) - (pa->no > pb->no);
}

int main (int argc, char **argv) {
    
    student std[NAMC];      /* array of student */
    char buf[MAXC];         /* buffer to hold line */
    int n = 0;              /* student counter */
    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
    
    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }
    
    while (n < NAMC && fgets (buf, MAXC, fp)) { /* limit to array sz, read line */
        student tmp;        /* temporary struct for student */
        /* parse name and number from line, validating return */
        if (sscanf (buf, "%s %d", tmp.name, &tmp.no) == 2)
            std[n++] = tmp; /* add to array */
    }
    
    if (fp != stdin)   /* close file if not stdin */
        fclose (fp);
    
    qsort (std, n, sizeof *std, cmpstd);    /* sort by student.no descending */
    
    for (int i = 0; i < n; i++)             /* output results */
        printf ("%-10s %d\n", std[i].name, std[i].no);
}

使用/输出示例

使用dat/prefixedstd.txt 中的输入文件,您将收到以下信息:

$ ./bin/read_prefixstd dat/prefixedstd.txt
asdas      8
asdas      7
asdsa      6
andrea     5
asd        4
asd        1
asdsad     1
asdas      0
asd        0

查看一下,如果您还有其他问题,请告诉我。

【讨论】:

  • 感谢您的回答。我有个问题。我正在尝试编写一个函数,它将一个学生添加到文件中(所以用户名、密码、状态(int 1 或 0))。这将是一个更好的解决方案:1-从文件中获取所有数据并将其放入列表中,修改列表并最后编写一个函数来将所有更改写入文件或2-直接使用写入文件只有1个功能?谢谢