【问题标题】:C - reading multiple integers and floats with sscanfC - 使用 sscanf 读取多个整数和浮点数
【发布时间】:2013-11-09 06:43:40
【问题描述】:

我正在为我的 C 编程课做一个练习题,它告诉我编写一个从文件中读取变量的程序。在第一行,它应该读入一个整数 N。

从那里,它应该读取一个整数,然后每行有五个浮点数,共 N 行。它应该计算文件中所有浮点数的总和并将其写入另一个文件。

我编写了一个程序,该程序应该使用 fgets 将一行复制到一个字符串,并使用 sscanf 对其进行剖析并将段分配到不同的数组位置。但是,我在通过 sscanf 获取无关信息时遇到了一些问题(可能是空值或换行符)。它没有正确存储整数 N(它会产生大的随机值并通过无限循环创建运行时错误),并且它可能也无法在循环内部工作。

我怎样才能完善它以使其正确读取整数并浮动?

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

#define MAX_STRING 30
#define MAX_LINE_SIZE 200

int main(void)
{
    FILE *f1, *f2;
    char filename[MAX_STRING];
    char fileline[MAX_LINE_SIZE];
    int N, eN;
    float totalwage = 0;
    int* ssn;
    float** wage;

    printf ("Enter a file name for data analysis: ");
    scanf ("%s", &filename); //get file name from user input for reading

    f1 = fopen (filename, "r");

    fgets (fileline, MAX_LINE_SIZE, f1); //read first line
    sscanf (fileline, "%d", &N); //pull integer from first line to determine how many lines follow

    for (eN = 0; eN < N; eN ++) //read N lines following the first
    {
        // VVV read single line from file
        fgets (fileline, MAX_LINE_SIZE, f1);
        // VVV record data from line
        sscanf (fileline, "%d, %f, %f, %f, %f, %f", &ssn[eN], &wage[eN][0], &wage[eN][1], &wage[eN][2], &wage[eN][3], &wage[eN][4]);
        // VVV add the 5 wages on each line to a total
        totalwage += wage[eN][0] + wage[eN][1] + wage[eN][2] + wage[eN][3] + wage[eN][4];
    }

    fclose (f1);

    printf ("Enter a file name for the result: ");
    scanf ("%s", &filename); //get file name from user input for writing

    f2 = fopen (filename, "w");

    fprintf (f2, "%f", totalwage); //store total of wages in file specified by user

    printf ("\nThe information has been stored. Press any key to exit.\n");
    getchar();
}

正在读取的文件是'wages.txt',其内容如下:

10
1, 10, 20, 30, 40, 50
2, 11, 12, 13, 14, 15
3, 21, 23, 25, 27, 29
4, 1, 2, 3, 4, 5
5, 30, 60, 90, 120, 150
6, 37, 38, 39, 40, 41
7, 40, 50, 60, 70, 80
8, 5, 10, 15, 20, 25
9, 80, 90, 100, 110, 120
10, 1000, 2000, 3000, 4000, 2000

回顾一下,问题在于存在运行时错误,其中程序由于某种无限循环而崩溃。通过一些调试,我看到它在第一行中没有正确读取为整数。它存储的不是值 10,而是像读取空字符一样存储大值。


我已添加代码以尝试为 ssn 和工资分配内存。但是,我不确定它是否正确完成,并且程序仍然存在崩溃的运行时错误。

ssn = malloc (N*MAX_STRING);
wage = malloc (N*MAX_STRING);
for (eN = 0; eN < N; eN ++)
{
    wage[eN] = malloc (N*MAX_STRING);
}

【问题讨论】:

  • "C - 使用 sscanf 读取多个整数和浮点数" - 不,使用 fgets()strtol()strtod()。此外,scanf ("%s", &amp;filename); 是基于类型不匹配的 UB。涉及wage 指针的长sscanf() 行也是UB,因为该指针不指向任何地方,它是未初始化的。
  • 这些库调用中的 any 没有一个返回值检查。你想知道可能出了什么问题?
  • 我已经成功为ssn和工资分配了内存。我仍然从 sscanf 获得不可预测的值。
  • 如果你除了对工资求和之外什么都不做,那么你不需要一个足够大的数组来保存所有的工资。您可能需要一个大到足以容纳一行工资的数组(因此,对sscanf() 的一次调用会将数据读入数组,然后将数组相加到总数中。您甚至可以编写代码,这样您只需要一个用于读取值的float 变量,加上一个用于保存工资总和的变量,尽管这有点困难,而且可能不值得努力。

标签: c file integer fgets scanf


【解决方案1】:

您没有为工资分配任何内存。它被声明为指向浮点数的指针;没关系,但是指针不指向任何地方。

ssn 也是如此。

在这一行之后:

sscanf (fileline, "%d", &N); //pull integer from first line to determine how many lines follow

你需要为ssn和工资分配内存。

由于这是作业,我不会告诉你如何分配内存;你需要自己弄清楚。

【讨论】:

  • scanf ("%s", &amp;filename); 也是 UB。
  • 感谢您的帮助!我会继续研究。此外,这不是家庭作业,而是考试准备的练习题。
  • 这样分配内存? ssn = malloc (NMAX_STRING);工资 = malloc (NMAX_STRING); for (eN = 0; eN
  • @River - ssn 需要是 N 个整数的数组;工资需要是 N 的数组(5 个浮点数的数组)。你的代码很接近,但不完全。
  • 喜欢这个? ssn = malloc (N);工资 = malloc (N); for (eN = 0; eN
【解决方案2】:

正如其他人指出的那样

scanf ("%s", &filename);

应该是:

scanf ("%s", filename);

注意sscanf如果列数发生变化是个大问题

修改为与strtod 一起使用:

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

#define MAX_STRING 30
#define MAX_LINE_SIZE 200
#define COLS 5

int main(void)
{
    FILE *f1, *f2;
    char filename[MAX_STRING];
    char fileline[MAX_LINE_SIZE];
    int N, eN, i;
    float totalwage = 0;
    float (*wage)[COLS];
    char *p;

    printf ("Enter a file name for data analysis: ");
    scanf ("%s", filename); //get file name from user input for reading
    f1 = fopen (filename, "r");
    fgets (fileline, MAX_LINE_SIZE, f1); //read first line
    sscanf (fileline, "%d", &N); //pull integer from first line to determine how many lines follow
    wage = malloc((sizeof(float) * COLS) * N);
    /* check malloc ... */
    for (eN = 0; eN < N; eN ++) //read N lines following the first
    {
        // VVV read single line from file
        p = fgets (fileline, MAX_LINE_SIZE, f1);
        strtol(p, &p, 10); /* skip first column */
        for (i = 0; i < COLS; i++) {
            wage[eN][i] = strtod(p + 1, &p); /* p+1 skip comma, read a float */
            totalwage += wage[eN][i]; /* sum */
        }
    }
    free(wage);
    fclose (f1);
    printf ("Enter a file name for the result: ");
    scanf ("%s", filename); //get file name from user input for writing
    f2 = fopen (filename, "w");
    fprintf (f2, "%f", totalwage); //store total of wages in file specified by user
    printf ("\nThe information has been stored. Press any key to exit.\n");
    getchar();
    fclose(f2); /* you forget to close f2 */
    return 0;
}

另外请注意,您读取的浮点数仅用于求和,不需要存储它们,因此可以避免malloc,并在现实世界中检查fopenfgets 的结果...

【讨论】:

  • 这可以无缝运行,这是可以理解的。谢谢!我正在阅读它,所以我可以学习这些概念。不过,有两件事让我感到困惑。首先是 N 和相关行的 sscanf 没有改变,但在我的中它没有正确读取。你知道为什么吗?另一个是我不确定 strtol 中以 10 为底的值是多少。
  • 你sscanf的问题? N 的扫描是正确的,在您尝试将值存储在未分配块中的行扫描中(使用 malloc 解决)。以 10 为底表示您正在以十进制表示法读取(八进制可能是 8,十六进制可能是 16)
  • 另一件事:你不需要存储文件中的行数来确定后面有多少行,阅读fgets的文档。如果流处于文件末尾,则应设置流的文件结束指示符,并且 fgets() 应返回空指针。
  • 很多这些我不需要做的事情都是练习题的一部分,我应该在其中存储数据,并读取行数。现在一切正常。我成功地为工资和 ssn 分配了内存,并像你说的那样切换到 strtol() 和 strtod() 函数。 char *p 是否将位置存储在它在第二个参数中停止的文件中?
  • 不,p 指向文件行的开头(在每个迭代中,strtod 将此位置更改为字符串中的下一个逗号)
【解决方案3】:

当您分配内存来存储一个浮点数时,您需要了解一个浮点值由四个字节组成,因此当您调用 malloc 时需要考虑到这一点,存储一个浮点数:malloc( sizeof(float ) ) 存储一个数组大小 N float malloc( N*sizeof(float ) ) 对于 int 是 sizeof(int)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-22
    • 2016-10-12
    • 2012-02-11
    • 2013-10-15
    • 2022-01-09
    • 2016-01-03
    相关资源
    最近更新 更多