【问题标题】:Read correctly a text file [duplicate]正确读取文本文件 [重复]
【发布时间】:2013-08-13 11:43:11
【问题描述】:

我应该读取以这种方式格式化的文件并将信息存储到结构中:

Johnny Rico A B A B C C C B B A
Ace Levy A A B A C A C A C A
Carmen Ibanez A B B B C C B B B B
Dizzy Flores B A A B C C C B B A
Zander Barcalow A B A B C C A B B A
Carl Jenkins A A A C B C A B B B

编辑

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

#define N 100

typedef struct _cad
{
    char nome[36], cognome[36];
    char risultati[50];
} Cadetto;

/*
 * 
 */
int main(int argc, char** argv)
{
    FILE *fp = NULL;
    int j = 0, count = 0, i, k;
    char riga[255];
    Cadetto cadetti[100];
    char *ptk;

    if(argc != 2)
    {
        fprintf(stderr, "Error: no parameter has been passed!\n");
        exit(1);
    }


    if((fp = fopen(argv[1], "r")) == NULL)
    {
        fprintf(stderr, "Error opening file %s\n", argv[1]);
        exit(1);
    }

    while (fgets(riga, sizeof(riga), fp) != NULL)
    {
        j = 0;

        ptk = strtok(riga, " ");
        strcpy(cadetti[count].nome, ptk);

        ptk = strtok(NULL, " ");
        strcpy(cadetti[count].cognome, ptk);

        while (ptk != NULL)
        {
            ptk = strtok(NULL, " ");
            cadetti[count].risultati[j] = *ptk;
            j++;
        }

        count++;
    }

    fclose(fp);

    for (i = 0; i < count; i++)
    {
        printf("%s %s", cadetti[i].nome, cadetti[i].cognome);

        for (k = 0; k < j; k++)
        {
            printf(" %c", cadetti[i].risultati[k]);
        }

        printf("\n");
    }

    return (EXIT_SUCCESS);
}

这是程序,但它不再工作了

【问题讨论】:

  • strcpy(cadetti[count].risultati[j], ptk); --> cadetti[count].risultati[j] = *ptk; 并通过fgets循环重置j
  • 程序可以运行,但不能正确打印字符
  • 您确实应该使用j 以外的变量来确定学生的成绩。它可能应该记录在Cadetti 结构中,因为每个学生可能有不同的成绩。
  • 您还应该修改while (ptk != NULL) { ptk = strtok(NULL, " "); ... 代码,以便在使用*ptk 之前测试是否为空,例如:while ((ptk = strtok(NULL, " ")) != NULL) { ...。这避免了取消引用空指针。对于调试,添加大量打印语句,以便您了解正在发生的事情以及每个阶段读取的内容。

标签: c file struct


【解决方案1】:

此代码适用于我:

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

#define N 100

typedef struct _cad
{
    char nome[36], cognome[36];
    char risultati[50];
    int nrisultati;
} Cadetto;

int main(int argc, char** argv)
{
    FILE *fp = NULL;
    int i, k;
    int count;
    char riga[255];
    Cadetto cadetti[N];
    char *ptk;

    if(argc != 2)
    {
        fprintf(stderr, "Error: no parameter has been passed!\n");
        exit(1);
    }

    if((fp = fopen(argv[1], "r")) == NULL)
    {
        fprintf(stderr, "Error opening file %s\n", argv[1]);
        exit(1);
    }

    for (count = 0; count < N && fgets(riga, sizeof(riga), fp) != NULL; count++)
    {
        int j = 0;
        printf("Input: %s", riga);

        ptk = strtok(riga, " ");
        strcpy(cadetti[count].nome, ptk);

        ptk = strtok(NULL, " ");
        strcpy(cadetti[count].cognome, ptk);
        printf("Name: %s %s\n", cadetti[count].nome, cadetti[count].cognome);

        while ((ptk = strtok(NULL, " ")) != NULL)
        {
            cadetti[count].risultati[j] = *ptk;
            printf("Grade %d: %c\n", j, *ptk);
            j++;
        }
        cadetti[count].nrisultati = j;
    }

    fclose(fp);

    for (i = 0; i < count; i++)
    {
        printf("%s %s", cadetti[i].nome, cadetti[i].cognome);

        for (k = 0; k < cadetti[i].nrisultati; k++)
        {
            printf(" %c", cadetti[i].risultati[k]);
        }

        printf("\n");
    }

    return (EXIT_SUCCESS);
}

nrisultati成员单独跟踪每个Cadetto的等级数,以防数据不一致。主读取循环受到保护以防止数组溢出。我没有保护名称读取代码不使用格式错误的数据(例如,单个单词)访问空指针。如果名称也过长,可能会出现问题。

主要变化是在等级扫描循环中; strtok() 的结果在使用前会被检查。

给定数据的示例输出:

Input: Johnny Rico A B A B C C C B B A
Name: Johnny Rico
Grade 0: A
Grade 1: B
Grade 2: A
Grade 3: B
Grade 4: C
Grade 5: C
Grade 6: C
Grade 7: B
Grade 8: B
Grade 9: A
Input: Ace Levy A A B A C A C A C A
Name: Ace Levy
Grade 0: A
Grade 1: A
Grade 2: B
Grade 3: A
Grade 4: C
Grade 5: A
Grade 6: C
Grade 7: A
Grade 8: C
Grade 9: A
Input: Carmen Ibanez A B B B C C B B B B
Name: Carmen Ibanez
Grade 0: A
Grade 1: B
Grade 2: B
Grade 3: B
Grade 4: C
Grade 5: C
Grade 6: B
Grade 7: B
Grade 8: B
Grade 9: B
Input: Dizzy Flores B A A B C C C B B A
Name: Dizzy Flores
Grade 0: B
Grade 1: A
Grade 2: A
Grade 3: B
Grade 4: C
Grade 5: C
Grade 6: C
Grade 7: B
Grade 8: B
Grade 9: A
Input: Zander Barcalow A B A B C C A B B A
Name: Zander Barcalow
Grade 0: A
Grade 1: B
Grade 2: A
Grade 3: B
Grade 4: C
Grade 5: C
Grade 6: A
Grade 7: B
Grade 8: B
Grade 9: A
Input: Carl Jenkins A A A C B C A B B B
Name: Carl Jenkins
Grade 0: A
Grade 1: A
Grade 2: A
Grade 3: C
Grade 4: B
Grade 5: C
Grade 6: A
Grade 7: B
Grade 8: B
Grade 9: B
Johnny Rico A B A B C C C B B A
Ace Levy A A B A C A C A C A
Carmen Ibanez A B B B C C B B B B
Dizzy Flores B A A B C C C B B A
Zander Barcalow A B A B C C A B B A
Carl Jenkins A A A C B C A B B B

将调试打印注释掉:

Johnny Rico A B A B C C C B B A
Ace Levy A A B A C A C A C A
Carmen Ibanez A B B B C C B B B B
Dizzy Flores B A A B C C C B B A
Zander Barcalow A B A B C C A B B A
Carl Jenkins A A A C B C A B B B

【讨论】:

    【解决方案2】:
    sscanf(riga, "%s %s %s", cadetti[count].nome,
                                     cadetti[count].cognome,
                                     result);
    

    ==>

    char * tmp = strtok( riga, " ");
    memcpy(cadetti[count].nome,tmp,strlen(tmp)+1);
    
    tmp= strtok (NULL " ");
    memcpy(cadetti[count].cognome,tmp,strlen(tmp)+1); 
    
    tmp= strtok(NULL,'\0');
    memcpy(result,tmp,strlen(tmp)+1);
    

    【讨论】:

    • 结果将包含数组单元格中的每个字符,还是包含空格?
    • 不会编译为 nomecognome 是数组,而不是指针。你需要一个额外的strcpy()
    • @lngo Leonhardt,你是对的。
    • @Mazzy cadetti[count].nome 和 cadetti[count].cognome 中没有空格,结果中保存了空格。
    • 我不喜欢这个解决方案,因为它引入了一个临时数组。我坚持这个解决方案,但出了点问题。
    猜你喜欢
    • 2020-10-20
    • 2019-04-01
    • 1970-01-01
    • 2015-01-22
    • 1970-01-01
    • 2018-07-09
    • 1970-01-01
    • 1970-01-01
    • 2017-06-24
    相关资源
    最近更新 更多