【问题标题】:Strings and array of structures字符串和结构数组
【发布时间】:2016-04-11 18:35:15
【问题描述】:

***用新代码更新 我正在尝试使用未知数量的数据行加载文件数据。 数据组织为 last, first:score1:score2:score3:score5:lettergrade

我正在将文件(某种程度上)加载到数组中并打印。 打印数据时,它不打印名字,只打印第一个。除了最后一个数据元素外,它为所有数据元素打印相同的整数,结果为 0。此外,它不会刷新不返回 8 个元素的数据。 请帮忙! 提前致谢。

    #include <stdio.h>
    #include <string.h>
#include <stdlib.h>
    #define FFLUSH while(fgetsc(fp) != '\n')
    #define MAX_STUDENTS 45

        typedef struct aStudent
        {
            char name[26];
            int id[7];
            int test1[4];
            int test2[4];
            int proj1[4];
            int proj2[4];
            int proj3[4];
            char grade[4];
        } aStudent;

        int main(void)
        {

        char file_name[FILENAME_MAX];
        FILE* fp;
        int i;
        int rc;
        int dc;
        aStudent studentArray[MAX_STUDENTS];

        printf("Enter File Name:    ");
        rc = scanf("%s", &file_name);
        if (rc == 0)
        {
            printf("\n\nError: No file name entered.");
            exit(0);
        }

        fp = fopen(file_name, "r");

        if (fp == NULL)
        {
            printf("Error: Could not open file %s for read", file_name);
            exit(0);
        }

            for(int i=0; i< 45; i++)
            {

            dc = (fscanf(fp, "%s[^:]%d[^:]%d[^:]%d[^:]%d[^:]%d[^:]%d[^:]%f[^:]%c[^:\n]", studentArray[i].name, studentArray[i].id, studentArray[i].test1, studentArray[i].test2, studentArray[i].proj1, studentArray[i].proj2, studentArray[i].proj3, studentArray[i].grade));

            if (dc != 8)
            {
                FFLUSH;
            }

                printf("%s %d %d %d %d %d %d %.2f %c", studentArray[i].name, studentArray[i].id, studentArray[i].test1, studentArray[i].test2, studentArray[i].proj1, studentArray[i].proj2, studentArray[i].proj3, studentArray[i].grade);

        }

      return 0;
    }

【问题讨论】:

  • “令牌前的预期表达式”错误。好的。哪一个。线。是。这。错误。开。
  • FFLUSH 宏在您使用它的末尾需要一个分号
  • 抱歉,第 53 行。在 FFLUSH 下仅包含 } 的行。
  • 并非如此。该宏需要死亡。摆脱它。做一个适当的功能。
  • 谢谢矢野!我还在第 48 行收到警告,说我的 fgets 从不兼容的指针类型传递参数。我的任务对我来说似乎是正确的?

标签: c arrays string structure


【解决方案1】:

STUDENT 是一种类型。你不能进入一个类型。没有数组 STUDENT。试试这个;

typedef struct aStudent
{
    char name[26];
    int id[7];
    int test1[4];
    int test2[4];
    int proj1[4];
    int proj2[4];
    int proj3[4];
    int ave[4];
    char grade[4];
} aStudent;

和;

 aStudent studentArray[MAX_STUDENTS];

并将 gGets 替换为 fscanf。

【讨论】:

  • 当我说 }STUDENT[MAX_STUDENTS]; 时,我以为我在结构的末尾创建了一个结构 INSIDE 数组 student
  • 我认为你所拥有的是一个数组类型。您声明“学生学生”;你得到一个数组[45]....?
  • @MartinJames 您介意详细说明一下吗?你是什​​么意思得到一个数组[45]?
  • 问 john - 我只是猜测您可以使用 typedef 来定义数组类型,例如。 STUDENT 是一个由 45 个结构组成的数组。我认为。也许。如果我错了,有人纠正我。我从来没有像这样使用过 typedef,我只对单个结构进行了 typedeff,如果我需要一个数组,我会使用 var 声明,例如:'myType myVars[45];'
【解决方案2】:

看来您的结构设置不正确,无法处理要从文件中读取的数据。您的数据是:

name:score1:score2:score3:score5:lettergrade

一个有意义的结构(给定多个分数)是:

typedef struct {
    char name[MAXNM];
    int id;
    int scores[NGRDS];
    float ave;
    char grade;
} student;

(你从来没有考虑过id 的来源,我会留给它用来将name 拆分为firstlast,因为你的原始问题指定了name 和你最近的编辑已添加firstlast)

很明显,您希望将数据文件读入struct,并根据读取的成绩计算ave(平均值)(应该是浮点类型而不是int)。鉴于您的文件格式,使用scanf 系列函数读取每一行数据可能比使用fgets/strtok 读取/标记每一行更明智。

fgetsfscanf 语法的混合将不起作用,这说明了尝试将混合数据硬塞到 scanf 类型格式字符串中的困难。您必须小心制作字符串以处理输入缓冲区中留下的空白和任何尾随换行符。对于您的数据集,以下内容将与其他任何内容一样有效:

char *fmt = " %[^:]:%d:%d:%d:%d:%c";

另一种解释尾随换行符的方法是使用赋值抑制运算符来读取并丢弃尾随换行符。使用时,丢弃的转换不会添加到返回的匹配计数中。例如

char *fmt = "%[^:]:%d:%d:%d:%d:%c%*c";

如果您正确地制作格式字符串,则不需要宏来刷新输入缓冲区。

拼凑起来,把你迟来的从 namelastfirst 的变化留给你,你可以做如下的事情:

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

/* constants for:
        NGRDS  - max number of grades per student.
        MAXNM  - max length of student name.
        MAXSTD - max number of students in array.
        MAXFN  - max filename length.
*/
enum { NGRDS = 4, MAXNM = 26, MAXSTD = 45, MAXFN = 128 };

typedef struct {
    char name[MAXNM];
    int id;
    int scores[NGRDS];
    float ave;
    char grade;
} student;

int main (void) {

    char filename[MAXFN];   /* initialize variables */
    char *fmt = " %[^:]:%d:%d:%d:%d:%c";
    FILE* fp = NULL;
    size_t i = 0, nstudents = 0;
    student students[MAXSTD] = {{ {""}, 0, {0}, 0.0, 0 }};

    printf ("\nEnter File Name:  ");
    if (scanf("%s", filename) != 1) {   /* validate filename read */
        fprintf (stderr, "error: invalid file name entered.\n");
        return 1;
    }

    if (!(fp = fopen (filename, "r"))) {    /* validate file open */
        fprintf (stderr, "error: file open failed '%s'\n.", filename);
        return 1;
    }

    /* read each line in file */
    while (fscanf (fp, fmt, students[i].name, &students[i].scores[0],
                    &students[i].scores[1],&students[i].scores[2],
                    &students[i].scores[3], &students[i].grade) == 6) {
        int j;  /* compute sum/average */
        for (j = 0; j < NGRDS; j++) students[i].ave += students[i].scores[j];
        students[i].ave /= (float)NGRDS;
        if (++i == MAXSTD) {    /* check against max */
            fprintf (stderr, "warning: students array full.\n");
            break;
        }
    }
    fclose (fp);    /* close file */
    nstudents = i;  /* save number of students */

    for (i = 0; i < nstudents; i++) {   /* output student data */
        size_t j;
        printf ("\n Student[%2zu]\n  name   : %s\n  scores :", 
                i, students[i].name);
        for (j = 0; j < NGRDS; j++) printf (" %d", students[i].scores[j]);
        printf ("\n  average: %.2f\n  grade  : %c\n", 
                students[i].ave, students[i].grade);
    }

    return 0;
}

示例数据

$cat dat/studentgrades.txt
Joe Cool:80:77:63:88:c
Nancy Smart:96:93:97:99:a
Dwane Dumb:61:60:67:50:f
Al Smith:75:77:78:73:c

使用/输出示例

$ ./bin/studentstruct

Enter File Name:  dat/studentgrades.txt

 Student[ 0]
  name   : Joe Cool
  scores : 80 77 63 88
  average: 77.00
  grade  : c

 Student[ 1]
  name   : Nancy Smart
  scores : 96 93 97 99
  average: 96.25
  grade  : a

 Student[ 2]
  name   : Dwane Dumb
  scores : 61 60 67 50
  average: 59.50
  grade  : f

 Student[ 3]
  name   : Al Smith
  scores : 75 77 78 73
  average: 75.75
  grade  : c

(注意:您的字母等级应该根据平均值计算,而不是简单地从文件中读取——如果等级发生变化怎么办?还要注意您的输入文件格式是固定且不灵活的。如果字段数或其以任何方式更改格式,您必须考虑 fmt 格式字符串中的更改。)

查看一下,如果您有任何问题,请告诉我。

【讨论】:

  • 我现在在另一个班,等我回家我真的希望你能回答问题!就像我说的,我需要编写这段代码,但我也想知道我在做什么。复制代码是学生考试成绩不佳的原因。
  • 我会在的。我已经准备好明天的 depo 准备工作了,欢迎休息。
  • 好吧,所以我基本上把你提供给我的代码分开了,我理解其中的大部分......实际上比我预期的要多得多。感谢您标记了很多代码。
  • 很高兴我能帮上忙。如果您要学习 C,所涉及的全部技巧就是放慢速度。了解每一行的每个字符是干什么用的,在手册页中查找每个函数,了解它的参数返回,没有什么技巧。使用 C,您负责管理您分配的所有内存。 (这就是为什么 C 的加载和执行速度通常比 Java 或 C++ 快 4 倍,只分配代码所需的资源,并且它背后没有庞大的类结构来检查你所做的一切)这是一种严格的思维方式,但有很大的好处.
猜你喜欢
  • 2011-08-04
  • 2021-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-09
  • 1970-01-01
  • 1970-01-01
  • 2014-01-20
相关资源
最近更新 更多