【问题标题】:C Problems with fscanffscanf 的 C 问题
【发布时间】:2022-04-28 22:46:10
【问题描述】:

感谢所有答案,更正后代码因愚蠢的错误而无效...我用相同的文件指针“数据库”打开了两个文件...

我已经阅读了几十个这样的问题,但我无法摆脱它,我快疯了。 我必须做的练习要求我在文件 .txt 中组织列表中的项目,该文件具有以下类型的元素:姓名 姓 年龄 工资,按照姓氏的字母顺序排列。 我已经创建了一个将元素插入文件的函数,它运行良好。 然后我转到函数来组织它们,但过程在 fscanf 之后停止,并进行了一些测试 printf 我看到没有为字符串分配值或分配了荒谬的数字。 请帮忙...谢谢。

这是代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX 64
#define MAXFILE 100

void insert();
int fullcheck();
void sort();

typedef struct {
    char name[MAX];
    char surname[MAX];
    int age;
    double wage;
} data;

int main() {
    insert();
    return EXIT_SUCCESS;
}

void insert() {
    char c;
    int i;
    data tmp;
    FILE* database;
    if ((fullcheck())>MAXFILE-1)
        printf("Errore: database pieno.\n");
    else {
        database=fopen("database.txt", "a");
        printf("Nome: ");
        fgets(tmp.name, MAX, stdin);
        tmp.name[strlen(tmp.name)-1]='\0';
        printf("Cognome: ");
        fgets(tmp.surname, MAX, stdin);
        tmp.surname[strlen(tmp.surname)-1]='\0';
        for (i=0; i<strlen(tmp.surname); i++) {
            if (tmp.surname[i]==' ')
                tmp.surname[i]='#';
        }
        printf("Eta': ");
        scanf("%d", &tmp.age);
        printf("Salario: ");
        scanf("%lf", &tmp.wage);
        while((c=getchar())!='\n');
        fprintf(database, "%s %s %d %.0lf \n", tmp.name, tmp.surname, tmp.age, tmp.wage);
        fflush(database); fclose(database);
        if ((fullcheck())>1)
            sort();
    }
}

int fullcheck() {
    char c;
    int r=0;
    FILE* database;
    if ((database=fopen("database.txt", "r"))==NULL) {
        return 0;
    }
    else {
        while((c=getc(database))!=EOF) {
            if(c=='\n')
                r++;
        }
        return r;
    }
}

void sort() {
    char tmpstr[MAX];
    int len=fullcheck(), i, a, b;
    data tmp[len];
    FILE* database;
    FILE* sorted;
    database=fopen("database.txt", "r");
    database=fopen("sorted.txt", "w");
    for (i=0; i<=len; i++) {
        fscanf(database, "%s %s %d %lf \n", &tmp[i].name, &tmp[i].surname, &tmp[i].age, &tmp[i].wage);
    }
    for (a=0 ; a<(len-1); a++) {
        for (b=0; b<(len-1); b++) {
            if ((tolower(tmp[b].surname[0]))>(tolower(tmp[b+1].surname[0]))) {
                strcpy(tmpstr, tmp[b].surname);
                strcpy(tmp[b].surname, tmp[b+1].surname);
                strcpy(tmp[b+1].surname, tmpstr);
            }
        }
    }
    for (a=0; a<(len-1); a++) {
        fprintf(sorted, "%s %s %d %.0lf \n", tmp[a].name, tmp[a].surname, tmp[a].age, tmp[a].wage);
    }
    fflush(database); fclose(database); remove("database.txt");
    fflush(sorted); fclose(sorted); rename("sorted.txt", "database.txt");
} 

【问题讨论】:

  • 混合fgetsscanf 只是自找麻烦。通过使用fgets 读取每一行来修复它,然后使用sscanfstrtol 转换一行上的数字。
  • fullcheck() 打开文件后不会关闭它。此外,在 fullcheck 中,c 应该是 int
  • 贴一些database.txt的示例行。
  • @user3386109 确实,混合fgets() 和 scanf()` 通常是不好的,但这里的 OP 代码不会因此而失败。
  • @chux-ReinstateMonica 是的,你是对的。这里有更多的答案。打印排序列表的循环太短了。并且排序本身只看每个名字的第一个字母,应该使用strcmp

标签: c


【解决方案1】:

关闭 1

代码尝试读入tmp[]len+1 元素。

data tmp[len];
for (i=0; i<=len; i++) {  // too many
    fscanf(database, "%s %s %d %lf \n", &tmp[i].name, &tmp[i].surname, &tmp[i].age, &tmp[i].wage);
}

我看到没有为字符串分配任何值(OP)

更好的代码将使用宽度限制并在使用扫描的数据之前测试fscanf() 结果。

//         v---- < not <=
for (i=0; i<len; i++) { 
    if (fscanf(database, "%63s %63s %d %lf",  
        &tmp[i].name, &tmp[i].surname, &tmp[i].age, &tmp[i].wage) != 4) {
        //                                                        ^^^^ test!
      break;
    }

更好的代码会将带有fgets() 读入stirng,然后尝试解析字符串。

关闭 2

如果最后一个不以'\n'结尾,则代码查找行数的尝试可以减1。

另类

size_t fullcheck(void) {
    FILE* database = fopen("database.txt", "r");
    if (database == NULL) {
        return 0;
    }
    int previous = '\n';
    int c;
    size_t r=0;
    while((c=getc(database))!=EOF) {
      if (previous == '\n') r++;
      previous = c;
    }
    fclose(database);
    return r;
}

缺少fclose()

fullcheck() doesn't close the file after opening it.

int

使用int 来区分fgetc() 通常有257 个不同的返回值。注意当char`是unsinged时,OP的代码是一个无限循环。

更多的麻烦

打印排序列表的循环太短了。而且排序本身只看每个名字的第一个字母,应该使用strcmp@user3386109

也许更多?

【讨论】:

    【解决方案2】:

    确保在每次返回之前关闭此处的文件:

    int fullcheck() {
        char c;
        int r=0;
        FILE* database;
        if ((database=fopen("database.txt", "r"))==NULL) {
            fclose(database);
            return 0;
        }
        else {
            while((c=getc(database))!=EOF) {
                if(c=='\n')
                    r++;
            }
            fclose(database);
            return r;
        }
    }
    

    这里还对 loop_counters 进行了一些修复:

    void sort() {
        char tmpstr[MAX];
        int len=fullcheck(), i, a, b;
        data tmp[len];
        FILE* database;
        FILE* sorted;
        database=fopen("database.txt", "r");
        sorted=fopen("sorted.txt", "w+");
        for (i=0; i<len; i++) {
            fscanf(database, "%s %s %d %lf \n", &tmp[i].name, &tmp[i].surname, &tmp[i].age, &tmp[i].wage);
            printf("%s", tmp[b+1].surname);
                    system("pause");
        }
        for (a=0 ; a<(len); a++) {
            for (b=0; b<(len); b++) {
                if ((tolower(tmp[b].surname[0]))>(tolower(tmp[b+1].surname[0]))) {
                    strcpy(tmpstr, tmp[b].surname);
                    strcpy(tmp[b].surname, tmp[b+1].surname);
                    strcpy(tmp[b+1].surname, tmpstr);
                    printf("%s", tmp[b+1].surname);
                    system("pause");
                }
            }
        }
        for (a=0; a<(len); a++) {
            fprintf(sorted, "%s %s %d %.0lf \n", tmp[a].name, tmp[a].surname, tmp[a].age, tmp[a].wage);
        }
        fclose(sorted); 
        fclose(database); 
    } 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-06
      • 1970-01-01
      • 1970-01-01
      • 2021-10-19
      相关资源
      最近更新 更多