【问题标题】:how to print values from file after appending附加后如何从文件中打印值
【发布时间】:2015-06-06 12:43:00
【问题描述】:

我有以下问题:我必须制作一个包含姓名、年龄和成绩的学生档案。它工作正常,但问题是在屏幕上打印所有内容时。假设我读了 3 个学生,当我输入“L”在屏幕上打印内容时效果很好。当我按“A”将另一个学生添加到文件中(追加)时,该学生将出现在我的文件中(所以我们总共有 4 个学生),但是当我按“L”再次打印时,它只打印 3在 4 名学生中,包括附加的一名,但删除了另一名。 'S' 代表写入文件。

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

struct student{
    char nume[20];
    int varsta;
    float medie;
};

void citire_date(struct student *studenti, FILE *f, int n){
    int i;

    for(i=0;i<n;i++){
        printf("Introduceti datele studentului %d\n", i+1);
        printf("Nume: "); fflush(stdin); gets((studenti+i)->nume);
        printf("Varsta: "); scanf("%d", &((studenti+i)->varsta));
        printf("Medie: "); scanf("%f", &((studenti+i)->medie));
        fprintf(f, "Nume: %s\n", (studenti+i)->nume);
        fprintf(f, "Varsta: %d\n", (studenti+i)->varsta);
        fprintf(f, "Medie: %.2f\n", (studenti+i)->medie);
        fprintf(f, "\n");
    }
}

void afisare_date(struct student *studenti, int n){
    int i;
    char nume1;
    int varsta1;
    float medie1;

    for(i=0;i<n;i++){
       printf("Nume: %s\n", (studenti+i)->nume);
        printf("Varsta: %d\n", (studenti+i)->varsta);
        printf("Medie: %.2f\n", (studenti+i)->medie);
        printf("\n");
    }
}

void append(struct student *studenti, FILE *f){
    int i;

    for(i=0;i<1;i++){
        printf("Nume: "); fflush(stdin); gets((studenti+i)->nume);
        printf("Varsta: "); scanf("%d", &((studenti+i)->varsta));
        printf("Medie: "); scanf("%f", &((studenti+i)->medie));
        fprintf(f, "Nume: %s\n", (studenti+i)->nume);
        fprintf(f, "Varsta: %d\n", (studenti+i)->varsta);
        fprintf(f, "Medie: %.2f\n", (studenti+i)->medie);
        fprintf(f, "\n");
    }
}

int main()
{
    FILE *f;
    struct student studenti[20];
    int n;
    char optiune;

    f=fopen("studenti.txt", "w");
    if(f==NULL){
        printf("Nu s-a putut deschide/crea fisierul pentru scriere.\n");
        exit(1);
    }

    printf("\n");

    do{
        printf("S. Scriere fisier.\n");
        printf("A. Adaugarea unui nou student in fisier.\n");
        printf("L. Listarea datelor tuturor studentilor.\n");
        printf("M. Modificarea datelor unui student.\n");
        printf("C. Cautarea unui student dupa nume.\n");
        printf("X. Terminarea programului.\n");
        printf("Introduceti optiunea: "); fflush(stdin); optiune=toupper(getchar());
        printf("\n");


        switch(optiune){
            case 'S':
                printf("Introduceti numarul de studenti: "); scanf("%d", &n);
                citire_date(studenti, f, n);
                fclose(f);
                printf("\n");
                break;
            case 'A':
                f = fopen("studenti.txt", "a");
                if(f==NULL ){
                    printf("Nu s-a putut deschide fisierul pentru adaugare.\n");
                    exit(2);
                }
                append(studenti, f);
                fclose(f);
                break;
            case 'L':
                afisare_date(studenti, n);
                break;
            case 'M':
                break;
            case 'C':
                break;
            case 'X':
                break;
            default:
                printf("\nAti introdus o optiune eronata!\n");
                break;

        }
    }while(optiune!='X');





    return 0;
}

我想我需要使用 fscanf,但我不知道它会如何从文件中读取 "Nume: name" "Varsta: 19" 等等。 提前谢谢你。

【问题讨论】:

  • 您是否尝试在调试器中运行代码?
  • fflush(stdin);未定义的行为。总是。另外,不要使用gets,由于非常不安全,它不再是 C 标准的一部分。请改用fgets
  • f = fopen("studenti.txt", "a"); 但该文件之前已使用f 打开。不要这样做:使用fseek() 在列出之前和追加之前定位文件指针。
  • 如果我不使用 'fflush(stdin):' 它会在不让我输入名称的情况下从 'Nume' 跳转到 'Varsta'。
  • case 'S' 那是我关闭文件的地方。

标签: c file struct scanf


【解决方案1】:

您的代码离您不远了。主要问题是您对输入的处理以及附加学生。首先是几个关键问题:

fflush(stdin)未定义的行为 并且总是错误的。永远不要使用 gets 它不再是 libc 的一部分并且不安全。

您可以使用格式字符串"%[^\n]%*c" 很好地处理带有scanf 的单个字符串的输入。这将消耗尾随的newline 和空的stdin。 (它不是万无一失的,但它适用于大多数目的)。它还为您提供了一种方法来检查空字符串的返回(例如 [Enter] 单独)并终止输入(见下文)。对于读取数字(例如intfloat、...),您有责任在再次调用scanf 之前清空stdin。我在下面创建了一个简单的flush_stdin() 函数来为您执行此操作。

最后,append 需要获取当前学生人数并在函数内增加该人数。传递指向n 的指针是解决此问题的最简单方法。它还允许您阅读append 中的多个学生,只需在(studenti + *n)-&gt;nume) 的空白行上点击[Enter] 即可终止输入。 (您还应该#define MAXSTUDENTS 20(您当前的,或您需要的任何东西),以便您可以在追加时检查您没有超过学生人数。(例如if (*n == MAXSTUDENTS)并采取适当的措施)

以下是您的代码的更新版本,它的工作方式更接近您的预期。查看代码,如果您有任何问题,请告诉我。

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

void flush_stdin () 
{
    int c = 0;
    while ((c = getchar()) != '\n' && c != EOF);
}

struct student{
    char nume[20];
    int varsta;
    float medie;
};

void citire_date(struct student *studenti, FILE *f, size_t n)
{
    int i = 0;  /* always initialize ALL variables */

    for(i=0;i<n;i++){
        printf("Introduceti datele studentului %d\n", i+1);
        printf("  Nume: "); scanf ( "%[^\n]%*c", (studenti+i)->nume);
        printf("  Varsta: "); scanf("%d", &((studenti+i)->varsta));
    flush_stdin ();
        printf("  Medie: "); scanf("%f", &((studenti+i)->medie));
    flush_stdin ();
        fprintf(f, "Nume: %s\n", (studenti+i)->nume);
        fprintf(f, "Varsta: %d\n", (studenti+i)->varsta);
        fprintf(f, "Medie: %.2f\n", (studenti+i)->medie);
        fprintf(f, "\n");
    }
}

void afisare_date(struct student *studenti, size_t n)
{
    int i = 0;
//     char nume1 = 0;     /* what are these for? */
//     int varsta1 = 0;
//     float medie1 = 0.0;

    for(i=0;i<n;i++)
    {
        printf("Nume: %s\n", (studenti+i)->nume);
        printf("Varsta: %d\n", (studenti+i)->varsta);
        printf("Medie: %.2f\n", (studenti+i)->medie);
        printf("\n");
    }
}

void append(struct student *studenti, FILE *f, size_t *n)
{
    int i = 0;

    while (1)
    {
        printf ("\nEnter student information ([Enter] when done)\n\n");
        printf("  Nume: "); 
        if (!scanf ( "%[^\n]%*c", (studenti + *n)->nume))
        {
            flush_stdin ();
            break;
        }
        printf("  Varsta: "); scanf("%d", &((studenti + *n)->varsta));
        if ((studenti+i)->varsta == '\n')
            break;
    flush_stdin ();
        printf("  Medie: "); scanf("%f", &((studenti + *n)->medie));
        if ((studenti+i)->medie == '\n')
            break;
    flush_stdin ();

        fprintf(f, "Nume: %s\n", (studenti + *n)->nume);
        fprintf(f, "Varsta: %d\n", (studenti + *n)->varsta);
        fprintf(f, "Medie: %.2f\n", (studenti + *n)->medie);
        fprintf(f, "\n");

        (*n)++;  /* increment numbre of students */
    }
}

int main()
{
    FILE *f = NULL;
    struct student studenti[20];
    size_t n = 0;
    char optiune = 0;

    f=fopen("studenti.txt", "w");
    if(f==NULL){
        printf("Nu s-a putut deschide/crea fisierul pentru scriere.\n");
        exit(1);
    }

    printf("\n");

    do{
        printf("S. Scriere fisier.\n");
        printf("A. Adaugarea unui nou student in fisier.\n");
        printf("L. Listarea datelor tuturor studentilor.\n");
        printf("M. Modificarea datelor unui student.\n");
        printf("C. Cautarea unui student dupa nume.\n");
        printf("X. Terminarea programului.\n");
        printf("Introduceti optiunea: "); 
        optiune=toupper(getchar());
        flush_stdin(); 
        printf("\n");


        switch(optiune){
            case 'S':
                printf("Introduceti numarul de studenti: "); scanf("%d", &n);
            flush_stdin ();
                citire_date(studenti, f, n);
                fclose(f);
                printf("\n");
                break;
            case 'A':
                f = fopen("studenti.txt", "a");
                if(f==NULL ){
                    printf("Nu s-a putut deschide fisierul pentru adaugare.\n");
                    exit(2);
                }
                append(studenti, f, &n);
                fclose(f);
                break;
            case 'L':
                afisare_date(studenti, n);
                break;
            case 'M':
                break;
            case 'C':
                break;
            case 'X':
                break;
            default:
                printf("\nAti introdus o optiune eronata!\n");
                break;

        }
    }while(optiune!='X');


    return 0;
}

输出

$ ./bin/student_missing

S. Scriere fisier.
A. Adaugarea unui nou student in fisier.
L. Listarea datelor tuturor studentilor.
M. Modificarea datelor unui student.
C. Cautarea unui student dupa nume.
X. Terminarea programului.
Introduceti optiunea: s

Introduceti numarul de studenti: 1
Introduceti datele studentului 1
  Nume: John Student
  Varsta: 1
  Medie: 91.2

S. Scriere fisier.
A. Adaugarea unui nou student in fisier.
L. Listarea datelor tuturor studentilor.
M. Modificarea datelor unui student.
C. Cautarea unui student dupa nume.
X. Terminarea programului.
Introduceti optiunea: l

Nume: John Student
Varsta: 1
Medie: 91.20

S. Scriere fisier.
A. Adaugarea unui nou student in fisier.
L. Listarea datelor tuturor studentilor.
M. Modificarea datelor unui student.
C. Cautarea unui student dupa nume.
X. Terminarea programului.
Introduceti optiunea: a


Enter student information ([Enter] when done)

  Nume: Jill Student
  Varsta: 2
  Medie: 94.3

Enter student information ([Enter] when done)

  Nume: Juan Student
  Varsta: 3
  Medie: 92.5

Enter student information ([Enter] when done)

  Nume:
S. Scriere fisier.
A. Adaugarea unui nou student in fisier.
L. Listarea datelor tuturor studentilor.
M. Modificarea datelor unui student.
C. Cautarea unui student dupa nume.
X. Terminarea programului.
Introduceti optiunea: l

Nume: John Student
Varsta: 1
Medie: 91.20

Nume: Jill Student
Varsta: 2
Medie: 94.30

Nume: Juan Student
Varsta: 3
Medie: 92.50

S. Scriere fisier.
A. Adaugarea unui nou student in fisier.
L. Listarea datelor tuturor studentilor.
M. Modificarea datelor unui student.
C. Cautarea unui student dupa nume.
X. Terminarea programului.
Introduceti optiunea: x

【讨论】:

  • 非常感谢。我已经设法以另一种方式做到这一点,但我也会这样做。我还有一个问题,我怎样才能在文件中搜索一个特定的名字,一旦我找到它来修改某些东西(名字、年龄或年级),?
  • 您将使用whilefor 循环遍历每个学生iif (strcmp ((studenti+i)-&gt;nume), SearchName) == 0) strncpy ((studenti+i)-&gt;nume, NewName, strlen(NewName)); 这可能是最简单的方法。
  • 我得跑了。如有更多问题,请给我留言,稍后我会回答。
【解决方案2】:

append() 循环中

for(i=0;i<1;i++) {
    ...
    gets((studenti+i)->nume);

写信给studenti[0]

它附加到文件而不是数组。该函数需要知道(并返回)您已经拥有的学生人数。

int append(struct student *studenti, FILE *f, int studs){
    int i;

    printf("Nume: "); fflush(stdin); gets((studenti+studs)->nume);
    printf("Varsta: "); scanf("%d", &((studenti+studs)->varsta));
    printf("Medie: "); scanf("%f", &((studenti+studs)->medie));
    fprintf(f, "Nume: %s\n", (studenti+studs)->nume);
    fprintf(f, "Varsta: %d\n", (studenti+studs)->varsta);
    fprintf(f, "Medie: %.2f\n", (studenti+studs)->medie);
    fprintf(f, "\n");
    return studs + 1;
}

【讨论】:

  • @OlarAndrei 添加到我的答案中,因为 append() 函数会覆盖第一个数组元素。
  • 好的,我添加了 2 个学生,然后又添加了一个,所以应该有 3 个,但是当我打印时它只打印前 2 个,附加的不会打印在屏幕。
  • 照顾学生总数。
  • 好吧,我还是不明白:)
  • 保留变量int totalstudents。添加记录时,将其递增。打印列表时,请使用它。但不要使用标识符n。仅在非常局部和明显的情况下使用这样一个简短的标识符,因为n 没有任何含义。
【解决方案3】:

我编辑了我的主要内容,所以现在应该可以清楚地看到所有内容了。

int main()
{
    FILE *f;
    struct student studenti[20];
    int n;
    char optiune;

     printf("Introduceti numarul de studenti: "); scanf("%d", &n);

    f=fopen("studenti.txt", "w");
    if(f==NULL){
        printf("Nu s-a putut deschide/crea fisierul pentru scriere.\n");
        exit(1);
    }
    citire_date(studenti, f, n);
    fclose(f);

    printf("\n");

    do{
        printf("A. Adaugarea unui nou student in fisier.\n");
        printf("L. Listarea datelor tuturor studentilor.\n");
        printf("M. Modificarea datelor unui student.\n");
        printf("C. Cautarea unui student dupa nume.\n");
        printf("X. Terminarea programului.\n");
        printf("Introduceti optiunea: "); fflush(stdin); optiune=toupper(getchar());
        printf("\n");


        switch(optiune){
            case 'A':
                f = fopen("studenti.txt", "a");
                if(f==NULL ){
                    printf("Nu s-a putut deschide fisierul pentru adaugare.\n");
                    exit(2);
                }
                append(studenti, f);
                fclose(f);
                break;
            case 'L':
                afisare_date(studenti, n);
                break;
            case 'M':
                break;
            case 'C':
                break;
            case 'X':
                break;
            default:
                printf("\nAti introdus o optiune eronata!\n");
                break;

        }
    }while(optiune!='X');





    return 0;
}

现在有什么建议吗?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-11
    • 1970-01-01
    相关资源
    最近更新 更多