首页 > 解决方案 > C使用结构从C中的文本文件中读取记录

问题描述

我正在尝试从名为 lib.txt 的文本文件中提取记录。我的程序是一个非常简单的基于图书馆的管理程序,我必须打印给定出版商或部门的所有书籍。我的代码是:

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

struct Books
{
    char name[100];
    char author[100];
    char publisher[100];
    double price;
    char branch[100];
};

typedef struct Books Books;

void main()
{
    int a = 0,b=0,ch,i;
    char *pb = (char *)malloc(100*sizeof(char));
    Books *bk;
    FILE *fp;
    fp = fopen("lib.txt","r");
    if(fp == NULL)
    {
        fprintf(stderr,"\n Error to open the file \n");
        exit(1);
    }
    while(1)
    {
        if(feof(fp))
        {
            break;
        }
        char c;
        c = fgetc(fp);
        if(c=='\n')
        {
            a++;
        }
    }
    a++;
    bk = (Books *)malloc(a*sizeof(Books));
    while(fread(&bk[b],sizeof(Books),1,fp))  //Even tried individual character extraction but it is not working
    {
        b++;
        if(b==a)
        {
            break;
        }
    }
    for(i=0;i<a;i++)
    {
        printf("%s",bk[i].name);
    }
    printf("1. Display books supplied by a particular publisher \n");
    printf("2. Display books in a particular branch \n");
    printf("3. Exit");
    printf("\n");
    printf("Enter your choice : ");
    scanf("%d",&ch);
    switch(ch)
    {
        case 1:
        {
            printf("Enter the name of publisher \n");
            scanf(" %s",pb);
            printf("\nName\tAuthor\tPublisher\tPrice\tBranch\n");
            for(i=0;i<a;i++)
            {
                if(strcmp(bk[i].publisher,pb)==0)
                {
                    printf("%s\t%s\t%s\t%.2lf\t%s \n",bk[i].name,bk[i].author,bk[i].publisher,bk[i].price,bk[i].branch);
                }
            }
            fflush(pb);
            break;
        }
        case 2:
        {
            printf("Enter the name of branch \n");
            scanf(" %s",pb);
            printf("\nName\tAuthor\tPublisher\tPrice\tBranch\n");
            for(i=0;i<a;i++)
            {
                if(strcmp(bk[i].publisher,pb)==0)
                {
                    printf("%s\t%s\t%s\t%.2lf\t%s \n",bk[i].name,bk[i].author,bk[i].publisher,bk[i].price,bk[i].branch);
                }
            }
            fflush(pb);
            break;
        }
        case 3:
        {
            return;
        }
        default:
        {
            printf("Invalid choice");
        }
    }
    free(bk);
    free(pb);
    fclose(fp);

    getch();
}

文件 lib.txt 以相同的顺序包含以下行,如下所示:

Abc1    A1  P1  23.0    B1
Abc2    A2  P2  23.0    B2
Abc3    A3  P3  23.0    B3
Abc4    A4  P2  23.0    B4
Abc5    A5  P2  23.0    B5
Abc6    A6  P6  23.0    B6
Abc7    A7  P2  23.0    B7

哦,它们是由标签分隔的。甚至尝试使用空格但没有变化。该程序编译正常,但未生成所需的输出。任何人都可以请帮忙吗?编辑:甚至尝试提取单个字符,然后拆分为子字符串,但失败了。请帮忙

标签: cstructstdinfile-handlingfile-pointer

解决方案


这是我的做法:

首先,定义一些函数来帮助你读取输入(你也可以在其他程序中使用它们):

int readint(int *i)
{
    char buffer[255];
    if (!fgets(buffer, 255, stdin)) {
        fprintf(stderr, "stdin error\n");
        return 0; // failed
    }

    buffer[strcspn(buffer, "\n")] = '\0';
    
    if (sscanf(buffer, "%d", i) != 1)
        return 0; // failed
    
    return 1; // success
}

char *readstr(char *str, int size)
{
    if (!fgets(str, size, stdin)) {
        fprintf(stderr, "stdin error\n");
        return NULL;
    }
    
    str[strcspn(str, "\n")] = '\0';
    return str;
}

然后你的main()

int main()
{
    // 1. Attempt to open file
    // ------------------------------------------------------------------------
    FILE *fp = fopen("lib.txt", "r");
    if(!fp) {
        fprintf(stderr, "Error to open the file\n");
        return 1;
    }
    
    
    // 2. Read file text
    // ------------------------------------------------------------------------
    int lines_count = 7; // Depends on how many lines you have
    Books *bk = malloc(lines_count * sizeof(*bk));
    if (!bk) {
        fclose(fp);
        return 0;
    }
    
    char line[255];
    int i = 0;
    
    while(fgets(line, sizeof line, fp)) {
        line[strcspn(line, "\n")] = '\0'; // Remove \n read by fgets()
        
        char name[100];
        char author[100];
        char publisher[100];
        double price;
        char branch[100];
        
        sscanf(line, "%[^\t]\t%[^\t]\t%[^\t]\t%lf\t%[^\t]", name, author, publisher, &price, branch);
        
        strcpy(bk[i].name, name);
        strcpy(bk[i].author, author);
        strcpy(bk[i].publisher, publisher);
        bk[i].price = price;
        strcpy(bk[i].branch, branch);
        
        i++;
    }
    
    fclose(fp);
    
    // 3. User input
    // ------------------------------------------------------------------------
    
    printf("1. Display books supplied by a particular publisher\n");
    printf("2. Display books in a particular branch\n");
    printf("3. Exit");
    printf("\n");
    
    printf("Enter your choice: ");
    int ch;
    readint(&ch); // Ignored error checking for the sake of simplicity
    
    char pb[100];
    
    switch(ch)
    {
    case 1:
        printf("Enter the name of publisher: ");
        readstr(pb, sizeof(pb));
        
        printf("\nName\tAuthor\tPublisher\tPrice\tBranch\n");
        for(i = 0; i < lines_count; i++)
            if(!strcmp(bk[i].publisher, pb))
                printf("%s\t%s\t%s\t%.2lf\t%s \n", bk[i].name, bk[i].author, bk[i].publisher, bk[i].price, bk[i].branch);

        break;

    case 2:
        printf("Enter the name of branch: ");
        readstr(pb, sizeof(pb));
        
        printf("\nName\tAuthor\tPublisher\tPrice\tBranch\n");
        
        for(i = 0; i < lines_count; i++)
            if(!strcmp(bk[i].publisher, pb))
                printf("%s\t%s\t%s\t%.2lf\t%s \n",bk[i].name,bk[i].author,bk[i].publisher,bk[i].price,bk[i].branch);
        
        break;
    
    case 3:
        return 0;
    
    default:
        printf("Invalid choice");
    }
    
    free(bk);
}

确保lib.txt包含制表符,而不是空格。您应该验证您的编辑器是否正在用空格替换制表符。


有几点需要考虑:

  1. main()应该总是返回int,不是void
  2. 用于fgets()读取用户的输入并sscanf()对其进行解析。你应该尽量避免使用 scanf()

推荐阅读