【问题标题】:C - Reading from a file and using a multi dimensional arrayC - 从文件中读取并使用多维数组
【发布时间】:2018-05-08 23:47:15
【问题描述】:

第一次使用这个网站。有人推荐我来这里。所以,我有一个任务很快就要到期了,我正在努力编写代码。我尽我所能完成了它,一切似乎都是为了我,但是当我运行程序时,无论我输入什么结果都不会改变。作业是:

编写一个 C 程序,从名为“input.txt”的文件中读取有关 5 个工人的信息。每行输入将 分别包含两个值,员工 ID 和员工的月薪。

假设输入文件中的数据以本例所示的格式存储。注意:出于测试目的,可能不一定使用以下数据。这只是为了让您了解数据的格式:

input.txt 的示例内容: 10 2000 20 6800 30 9700 40 1500 50 8000

将员工信息存储到二维数组中。假设数据类型如下:id(整数数据类型)和income(整数数据类型)。

读取信息,将5条员工记录存入二维数组。

使用打印工人所有收入总和的函数。

创建另一个函数,打印收入超过 5000 美元的工人数量,同时 每个收入超过 5000 美元的工人的身份证和收入。

而我的代码如下:

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

int employeeID, salary;
int id[5][2], income[5][2];
int sum();
int greater();
FILE *worker;

int main()
{


    worker=fopen("input.txt", "w");
        printf("Enter Employee ID and Salary:\n");
    for(employeeID=0;employeeID<5;employeeID++){
        for(salary=0;salary<2;salary++){
            scanf("%d", &id[employeeID][salary]);
        }
    }
    for(employeeID=0;employeeID<5;employeeID++){
        for(salary=0;salary<2;salary++){
            fprintf(worker,"%d", &id[employeeID][salary]);
        }       
    }
        fclose(worker);

    worker=fopen("input.txt", "r");
        while(!feof(worker)){
            for(employeeID=0;employeeID<5;employeeID++){
                for(salary=0;salary<2;salary++){
                    fscanf(worker,"%d", &income[employeeID][salary]);

                }
            }
        }
    sum();
    greater();
}
int sum()
{
    int totalincome, totalsum;
    int income[5][2];

totalsum=income[0][1]+income[1][1]+income[2][1]+income[3][1]+income[4][1];
totalincome=printf("\nSum of all workers incomes:$%d\n");
    return totalincome;
}
int greater()
{
    int employeeID, salary;
    int income[5][2];
    int num=0;
    for(employeeID=0;employeeID<5;employeeID++){
        for(salary=0;salary<2;salary++){
            if(income[employeeID][salary+1]>5000){
                num++;
            }
        }
    }
    printf("\nWorkers that have income greater than $5000:\t");

        if(income[0][1]>5000)
        {
            printf("\nEmployee ID:%d  Salary: $%d", income[0][0], income[0][1]);
        }

        if(income[1][1]>5000)
        {
            printf("\nEmployee ID:%d  Salary: $%d", income[1][0], income[1][1]);
        }       

        if(income[2][1]>5000)
        {
            printf("\nEmployee ID:%d  Salary: $%d", income[2][0], income[2][1]);
        }

        if(income[3][1]>5000)
        {
            printf("\nEmployee ID:%d  Salary: $%d", income[3][0], income[3][1]);
        }

        if(income[4][1]>5000)
        {
            printf("\nEmployee ID:%d  Salary: $%d", income[4][0], income[4][1]);
        }

    return 0;   //End of Program
}

我知道要阅读的内容很多,但我真的很感谢任何人的帮助。我真的很挣扎。谢谢。

【问题讨论】:

标签: c arrays file multidimensional-array


【解决方案1】:

这里不需要两个二维数组。你只需要一个,也许叫它employeeInfo,维度:5个员工和2条信息[一行是员工ID号,另一行是收入] employeeInfo[ numberOfEmployees ][ infoTypes ]

| id0 | id1 | id2 | id3 | id4 |

| $s0 | $s1 | $s2 | $s3 | $s4 |

(抱歉格式不好^)

所以现在我们想将文件中的数字读入其中,因此我们需要通过将r 传递给 fopen() 函数来打开文件进行读取:

worker = fopen("input.txt", "r");  //open file for reading
// Since we know exactly how many employees there are
// we can read precisely that many times in a double for loop: 
//  but the hardcoded literals work better as variables in the future
//  (see the comments in the greater() function below for ideas)          
for (int employee = 0; i < 5; employee++) //five employees
{
    for (int infoType = 0; info < 2; infoType++) //two pieces of info per employee
    {
        int info; // for storing the ID/SALARY
        fscanf(worker, " %d", &info); // read the next value  
        employeeInfo[employeeID][infoType] = info ; // store in 2d array(our table)
    }
} 
fclose(worker);

好的,现在我们的employeeID 数组(或表)已满!我们现在可以总结收入并打印总数:

int sum() # or void sum() unless you have future plans for this
{
    //int income[5][2]; this is empty and not needed. 
    int totalsum; //second variable not needed

    // global scope of the first 2d array means that you can access it here.

    totalsum = 0; // start at 0 and add incomes as we go
    for(int employee = 0; employee < 5; employee++)
    { 
      totalsum += employeeInfo[employee][1];
    }
    // the above for loop has the advantage that we can easily sum for more
    // employees
    //totalsum=income[0][1]+income[1][1]+income[2][1]+income[3][1]+income[4][1];
    //now we're printing totalsum
    printf("\nSum of all workers incomes:$%d\n", totalsum); 

    return totalsum; // this is not used but this is returning the sum
}

sum() 函数做错了三件事:

  1. 忘记作用域的工作原理: 它声明了一个新的 empty 数组 income,其值与全局范围的“income”数组无关。由于您在主函数之外声明了第一个“收入”数组,因此它位于 全局范围 中,这意味着可以从任何地方访问它。无需重新声明。

  2. Printf() 错误:

    围绕 printf() 的代码实际上有两个错误。首先,您已将要打印的变量的名称与格式说明符(如%d)按照它们在引号中出现的顺序用逗号分隔。像这样:printf("some text: %d %c", myInteger, myChar)

    要注意的另一件事是 printf() 将打印到标准输出(大多数情况下是控制台),但是如果您将其存储在变量中,就像您所做的那样,您将存储它的内部返回值,这实际上是它打印的字符数。看到这个问题:Return value of printf() function in C

  3. 不返回总和:

    我猜你认为 totalincome 会包含 totalsum,但如前所述 printf() 不会返回它打印的内容。另外,请注意 sum() 返回的内容并未在主函数中存储或使用。在这种情况下,它也可以是 void 函数。

greater() 函数应该可以工作——但值得一提的是,没有必要编写 if 语句。您可以在 for 循环中进行检查并从那里使用 printf(),类似于在 sum() 函数中重新格式化代码的方式。

另外,greater() 函数的结尾不是程序的结尾。逻辑流驻留在 main() 的主体中。当 main() 结束(返回)时,程序结束。

int greater()
{
    // int income[5][2] is empty and not needed
    // all the info is read into the globally declared 2D array (employeeInfo)
    // by the time greater() is called
    int employeeID; // , salary <<--not needed 
                    // but it is good style to avoid "magic numbers"
                    // like the hard-coded '5' or '1' in the loop below
                    // we could instead define static constants before main
                    // for example:
                      // static const int HIGH_SALARY= 5000
                    // or if you need to use the "magic numbers" as an array dimension:
                      // enum {MAX_EMPLOYEES = 5, ID_TYPE = 0, SALARY_TYPE = 1 }

    int totalHighSalaryEmployees= 0;
    // Start building output:
    printf("\nWorkers that have income greater than $5000:\t"); 
    for(employeeID=0;employeeID<5;employeeID++){ // For each employee
        if(income[employeeID][1]>5000){  //check their salary
            totalHighSalaryEmployees++;  // Increment our count of the wealthy
            printf("\nEmployee ID:%d  Salary: $%d", employeeInfo[employeeID][0], employeeInfo[employeeID][1]); 

        }
    } //Done -- 
    // Now print number of high salary employees 
    printf("\nNumber of Workers that have income greater than $5000:%d", totalHighSalaryEmployees);
    return totalHighSalaryEmployees;
}

【讨论】:

    【解决方案2】:

    对于初学者,避免使用全局变量,除非绝对必要(当您第一次学习 C 时几乎从不这样做)。相反,在main() 中声明所需的变量并作为参数传递给任何函数。

    您最初邀请未定义的行为是通过未能验证返回或者:

    worker=fopen("input.txt", "w");
    

            scanf("%d", &id[employeeID][salary]);
    

    您必须验证代码的所有输入方面。否则,您不知道您是否实际上是从文件(或NULL 流指针)中读取数据并且无法验证scanf 的返回,这会让您完全不知道是否发生了有效转换或 输入或匹配失败。

    你从你的文件中读入一个二维数组,然后你执行以下操作??

    for(employeeID=0;employeeID<5;employeeID++){
        for(salary=0;salary<2;salary++){
            fprintf(worker,"%d", &id[employeeID][salary]);
        }       
    }
    

    您不能使用"%d" 格式说明符打印id[employeeID][salary]地址,这会调用未定义行为。 (&amp; 不应该在那里......)此外,为什么您要尝试将值写回您刚刚从 scanf 的前一组嵌套循环中读取它们的文件?这样做会删除值之间的所有空格,留下一长串数字。

    您只需要一个 2D 数组。它将在每一行的第一列中保存employeeid,在第二列中保存salary

    让我们看看如何正确地做到这一点,首先,不要在代码中使用幻数硬编码文件名

    /* if you need constants, #define them or use an enum */
    enum { SALCOL = 1, NCOL = 2, NROW = 5, HISAL = 5000 };
    

    main() 接受参数的正确定义是:

    int main (int argc, char **argv) {
    

    您可以将文件名作为第一个参数传递给程序,避免在代码中硬编码"input.txt"

    main() 中定义你的变量,打开你的文件(如果没有给出文件名,这个代码也默认从stdin 读取)并且总是验证文件是开放的以供读取。

    int main (int argc, char **argv) {
    
        int rows = 0,   /* row index */
            cols = 0,   /* col index */
            wrkrs[NROW][NCOL] = {{0}};  /* 2d array for workers */
        FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
    
        if (!fp) {  /* validate file open for reading */
            fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
            return 1;
        }
        ...
    

    您必须跟踪读取的数据行数。您不能仅仅依赖于文件中的常量数量恰好与您在代码中输入的常量相匹配。跟踪列索引和行索引并根据需要重置以填充您的二维数组:

        /* read values while rows < NROW */
        while (rows < NROW && scanf ("%d", &wrkrs[rows][cols]) == 1)
            if (++cols == NCOL) {   /* increment and check col = NCOL */
                cols = 0;           /* reset col to zero */
                rows++;             /* increment row index */
            }
    

    剩下的就是关闭你的文件并输出所有工人,然后是那些薪水超过HISAL (5000) 的工人:

        if (fp != stdin) fclose (fp);   /* close file if not stdin */
    
        prnwrkrs (wrkrs, rows);             /* output all workers */
        prnhighwrkrs (wrkrs, rows, HISAL);  /* output workes making HISAL */
    
        return 0;
    }
    

    对于您的打印功能,您需要传递 worker 二维数组和数据行数(这可能比您预期的要少)。 注意:您可以将二维数组传递为int array[][NCOL],它将被转换为指向NCOL 数组的指针,这意味着您也可以将worker 传递为int (*array)[NCOL],以反映函数的实际作用收到。一种处理方法是:

    /* print all workers in 2d array 'a' with `rows' rows.
     * note: a can be passed as 'a[][NCOL] as well
     */
    void prnwrkrs (int (*a)[NCOL], int rows)
    {
        printf ("\nAll workers:\n");        /* print heading */
        for (int i = 0; i < rows; i++) {    /* loop over each row */
            printf ("  worker[%d] : ", i);  /* output worker[] label */
            for (int j = 0; j < NCOL; j++)  /* loop over each col */
                printf (" %6d", a[i][j]);   /* output integer value */
            putchar ('\n');                 /* tidy up with '\n' */
        }
    }
    

    要处理HISAL 工人,您只需传递一个附加参数,即用于比较工人工资的薪水(注意: 因为您已声明常量,所以您可以省略传递薪水并使用要比较的常数,但为什么不让函数有用以显示工人的收入高于您可能希望传递给函数的任何薪水,例如

    /* print worker earning more than 'sal'
     * same as prnwrkrs, but passes additional parameter 'sal'
     * for comparison. Compre to salary and print if greater.
     */
    void prnhighwrkrs (int (*a)[NCOL], int rows, int sal)
    {
        printf ("\nWorkers earning %d or more:\n", sal);
        for (int i = 0; i < rows; i++) {
            if (a[i][SALCOL] >= sal) {          /* compare with 'sal' */
                printf ("  worker[%d] : ", i);  /* output if greater */
                for (int j = 0; j < NCOL; j++)
                    printf (" %6d", a[i][j]);
                putchar ('\n');
            }
        }
    }
    

    总而言之,您可以执行以下操作:

    #include <stdio.h>
    
    /* if you need constants, #define them or use an enum */
    enum { SALCOL = 1, NCOL = 2, NROW = 5, HISAL = 5000 };
    
    /* print all workers in 2d array 'a' with `rows' rows.
     * note: a can be passed as 'a[][NCOL] as well
     */
    void prnwrkrs (int (*a)[NCOL], int rows)
    {
        printf ("\nAll workers:\n");        /* print heading */
        for (int i = 0; i < rows; i++) {    /* loop over each row */
            printf ("  worker[%d] : ", i);  /* output worker[] label */
            for (int j = 0; j < NCOL; j++)  /* loop over each col */
                printf (" %6d", a[i][j]);   /* output integer value */
            putchar ('\n');                 /* tidy up with '\n' */
        }
    }
    
    /* print worker earning more than 'sal'
     * same as prnwrkrs, but passes additional parameter 'sal'
     * for comparison. Compre to salary and print if greater.
     */
    void prnhighwrkrs (int (*a)[NCOL], int rows, int sal)
    {
        printf ("\nWorkers earning %d or more:\n", sal);
        for (int i = 0; i < rows; i++) {
            if (a[i][SALCOL] >= sal) {          /* compare with 'sal' */
                printf ("  worker[%d] : ", i);  /* output if greater */
                for (int j = 0; j < NCOL; j++)
                    printf (" %6d", a[i][j]);
                putchar ('\n');
            }
        }
    }
    
    int main (int argc, char **argv) {
    
        int rows = 0,   /* row index */
            cols = 0,   /* col index */
            wrkrs[NROW][NCOL] = {{0}};  /* 2d array for workers */
        FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
    
        if (!fp) {  /* validate file open for reading */
            fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
            return 1;
        }
    
        /* read values while rows < NROW */
        while (rows < NROW && scanf ("%d", &wrkrs[rows][cols]) == 1)
            if (++cols == NCOL) {   /* increment and check col = NCOL */
                cols = 0;           /* reset col to zero */
                rows++;             /* increment row index */
            }
    
        if (fp != stdin) fclose (fp);   /* close file if not stdin */
    
        prnwrkrs (wrkrs, rows);             /* output all workers */
        prnhighwrkrs (wrkrs, rows, HISAL);  /* output workes making HISAL */
    
        return 0;
    }
    

    输入文件示例

    $ cat dat/workers.txt
     10 2000 20 6800 30 9700 40 1500 50 8000
    

    使用/输出示例

    $ ./bin/workers <dat/workers.txt
    
    All workers:
      worker[0] :      10   2000
      worker[1] :      20   6800
      worker[2] :      30   9700
      worker[3] :      40   1500
      worker[4] :      50   8000
    
    Workers earning 5000 or more:
      worker[1] :      20   6800
      worker[2] :      30   9700
      worker[4] :      50   8000
    

    C 不是一门语言,你只能猜测代码应该是什么,编译它,失败,根据你的下一次猜测稍微改变它,再次编译,失败......你必须花时间来验证每一部分在这个谜题中,了解您正在处理的值、它们所在的索引以及如何正确使用代码中的每个函数。你可以通过检查man function 来了解你使用的每个标准库函数,直到你知道它们是冷的——然后你仍然查看man function 来确定。

    把事情看一遍。了解代码为什么会这样做,并询问您是否还有其他问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-05
      • 1970-01-01
      • 1970-01-01
      • 2023-04-09
      相关资源
      最近更新 更多