【问题标题】:C Reading records from text file in C using structureC使用结构从C中的文本文件中读取记录
【发布时间】:2021-11-10 18:03:04
【问题描述】:

我正在尝试从名为 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

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

【问题讨论】:

  • “未生成所需的输出”是指没有输出、输出乱码、输出未对齐、崩溃还是...?
  • fflush(pb); 有两个编译器警告(两个相同的事件),即'function': incompatible types - from 'char *' to 'FILE *'
  • ...所以提高警告级别,因为这是一个严重错误。
  • 关于输出,它就像打印除记录之外的所有内容
  • if feof(fp) 是错误的。 stackoverflow.com/questions/5431941/…

标签: c struct stdin file-handling file-pointer


【解决方案1】:

我会这样做:

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

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()

【讨论】:

  • 非常感谢。你不知道这对我有多大帮助。并感谢您提供这些建议。他们真的有帮助。谢谢。
  • 你能解释一下 sscanf() 在缓冲区中用于整数的用途吗?
  • 好的,很抱歉打扰你,我知道了@Zakk。非常感谢。
  • 嗯,很抱歉打扰您@Zakk,但 readstr 给出的错误类型冲突
猜你喜欢
  • 2013-12-25
  • 2023-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-08
  • 1970-01-01
相关资源
最近更新 更多