繁体   English   中英

为什么我的C程序无法正确计算和打印文本文件中的整数?

[英]Why is my C program not counting and printing integers from a text file properly?

祝大家好。 我想知道为什么我用C编写的程序无法正常工作。 我正在尝试从文本文件中读取整数并将其基于文本文件中整数的数量放入二维数组中。 我想计算整数并在控制台上打印它们,以确保一切正常。 我的代码可以在这里看到:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main()
{
    FILE *fp;
    fp = fopen("COSC450_P1_Data.txt", "r");
    char str[200];
    int words;
    int row, columns, count;
    if(fp == NULL)
    {
        printf("Could not open file %s", fp);
        return 2;
    }

    while(getc(fp) != EOF)
    {
        count++;
        fgets(str, 200, fp);
        puts(str);
    }
    printf("%d  ", count);
    fclose(fp);

    return 0;
}

该文件如下所示:

O123 34 -54 21 45 34 65 -54 21 45 34 65 -34 24 58

49 45 10 -57 20

57 39 20 58 23 10 20 58 -60 76 -82 28

  28 -37 49 358 47 -50 37 29 

57 -29 -20 47 69

93 57 23 49 -38 49 27 -40 48 39

56 -30 47 28 49

37 49

  27 26 10 20 58 -60 26 10 20 58 -60 76 -82 28 28 -37 49 -28 93 28 

73 47 27 83 37 -29 40 37 49 20

17 -26 12 17 17

18 38 29 39 -118

19 10 20 58 -60 76 -82 28

  28 -37 49 59 10 58 -60 76 -82 28 28 -37 49 59 10 20 58 -60 76 -82 28 28 -37 49 30 -58 58 38 49 30 -58 58 38 

49 30 -58 58 38

28 39

39 48 23 -50 28

48 29 39 40 29

下一个图像是输出的样子:

3 34 -54 21 45 34 65 -54 21 45 34 65 -34 24 58

49 45 10 -57 20

7 39 20 58 23 10 20 58 -60 76 -82 28

  28 -37 49 358 47 -50 37 29 

7 -29 -20 47 69

93 57 23 49 -38 49 27 -40 48 39

6 -30 47 28 49

7 49

  27 26 10 20 58 -60 26 10 20 58 -60 76 -82 28 28 -37 49 -28 93 28 

3 47 27 83 37 -29 40 37 49 20

7 -26 12 17 17

8 38 29 39 -118

9 10 20 58 -60 76 -82 28

  28 -37 49 59 10 58 -60 76 -82 28 28 -37 49 59 10 20 58 -60 76 -82 28 28 -37 49 30 -58 58 38 49 30 -58 58 38 

9 30 -58 58 38

8 39

9 48 23 -50 28

8 29 39 40 29

83

输出截断了某些数字,它给了我错误的整数总数。 请帮忙。 谢谢你,祝你有美好的一天。

更新:谢谢您的帮助。 不幸的是,将while循环while(getc(fp) != EOF)更改为while(fgets(fp) != NULL)会使程序跳过第一行,如下所示:

  49 45 10 -57 20 28 -37 49 358 47 -50 37 29 93 57 23 49 -38 49 27 -40 48 39 

37 49

  28 -37 49 -28 93 28 

17 -26 12 17 17

19 10 20 58 -60 76 -82 28

  28 -37 49 59 10 20 58 -60 76 -82 28 

49 30 -58 58 38

39 48 23 -50 28

48 29 39 40 29 73

但是,从while循环的主体中删除fgets(str, 200, fp)确实提供了更准确的输出,但不是我想要的:

23 34 -54 21 45 34 65 -54 21 45 34 65 -34 24 58

  49 45 10 -57 20 

57 39 20 58 23 10 20 58 -60 76 -82 28

  28 -37 49 358 47 -50 37 29 

57 -29 -20 47 69

  93 57 23 49 -38 49 27 -40 48 39 

56 -30 47 28 49

37 49

  27 26 10 20 58 -60 26 10 20 58 -60 76 -82 28 28 -37 49 -28 93 28 

73 47 27 83 37 -29 40 37 49 20

17 -26 12 17 17

18 38 29 39 -118

19 10 20 58 -60 76 -82 28

  28 -37 49 59 10 58 -60 76 -82 28 28 -37 49 59 10 20 58 -60 76 -82 28 28 -37 49 30 -58 58 38 49 30 -58 58 38 

49 30 -58 58 38

28 39

39 48 23 -50 28

48 29 39 40 29 83

如果您还有其他建议,请告诉我。 再次谢谢大家。

输出截断了某些数字,它给了我错误的整数总数。

当然可以。 您正在使用以下方法从输入流中读取和删除字符:

while(getc(fp) != EOF)
    ...

然后尝试读取整行数据,就好像什么都没有删除一样:

fgets(str, 200, fp);

fgets将读取多达(含)后'\\n'和包括'\\n'在它填补了缓冲区-让你的每一行基本上是切碎的第一个字符了。

读取一次,转换所有值

最好将输入的每一行读入缓冲区中(当您尝试使用str ,然后使用strtol (推荐)或sscanf带有已保存的偏移量或更新的指针)逐步进入缓冲区以挑选整数值)。因使用fgets面向行的方法而受到赞扬,这是正确的,您只是不能在调用每行之前删除第一个字符。

您还有其他注意事项。 有效整数也可以以+/-开头,因此您也需要考虑符号。 (除此之外,这是处理以o/O0x/0X 八进制十六进制值的问题)

使用strtol

strtol用于通过缓冲区工作并转换找到的数值。 strtol的原型是:

long int strtol(const char *nptr, char **endptr, int base);

其中nptr是一个指向转换的开始,关键的是, endptr将在数字的转换成功进行更新,以指向一个过去的最后一个数字转换后让你循环,并通过更新转换的下一个值nptr = endptr; 在您进行验证之后。

与任何代码一样, 验证是关键。 对于strtol ,必须检查nptr != endptr以确定是否转换了任何数字。 然后,您必须验证errno == 0并且由于转换错误而未设置(例如,值超出类型,溢出等范围)。

由于输入文件中整数值之间的空格可能包含空格以外的字符,因此您只需从endptr在缓冲区中向前扫描,直到找到下一个有效的起始字符(例如+/-和数字0-9 ,请注意)如果您要包含八进制值,则必须另外检查o/O

使用strtol处理十进制和十六进制并仅输出转换后的值的一个简短示例为:

#include <stdio.h>
#include <stdlib.h>     /* for strtol */
#include <string.h>     /* for strncpy */
#include <errno.h>      /* for errno */

#define MAXC 1024   /* constant - max chars in line */

int main (void) {

    char str[MAXC] = "";    /* str to hold line, initialized all zero */

    while (fgets (str, MAXC, stdin)) {  /* read each line of input */
        char *p = str,      /* pointer for strtol */
            *endptr = NULL; /* end pointer for strtol */

        while (*p) {    /* work down str parsing integer or hex values */
            long val = strtol (p, &endptr, 0);  /* convert from p */

            /* validate conversion */
            if (p != endptr) {  /* were digits converted? */
                if (!errno) {   /* if errno 0, successful conversion */
                    char ascii[MAXC] = "";  /* for string converted */

                    strncpy (ascii, p, endptr - p); /* copy to ascii */
                    ascii[endptr-p] = 0;    /* nul-terminate ascii */

                    /* test whether string begins "0x" or "0X", output */
                    if (*p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X'))
                        printf ("hex conversion:  %-10s %10lu  0x%lx\n",
                                ascii, val, val);
                    else
                        printf ("int conversion:  %-10s % ld\n",
                                ascii, val);
                }
                p = endptr; /* advance p to 1-past end of converted string */
            }

            /* find start of next valid number in str, including (+/-) */
            for (; *p; p++) {
                if ('0' <= *p && *p <= '9')  /* positive value */
                    break;          /* explicitly signed value */
                if ((*p == '+' || *p == '-') && '0' <= *(p+1) && *(p+1) <= '9')
                    break;
            }
        }
    }

    return 0;
}

注意:如果您将值存储为int ,则由于存储类型( int )与转换类型( long )不同,在进行赋值之前,必须进一步检查INT_MIN <= val && val <= INT_MAX

使用/输出示例

将数据文件放在integermess.txt然后将文件重定向到stdin您将得到以下输出:

$ ./bin/fgets_strtol_any <debug/dat/integermess.txt
int conversion:  123         123
int conversion:  34          34
int conversion:  -54        -54
int conversion:  21          21
int conversion:  45          45
int conversion:  34          34
int conversion:  -54        -54
int conversion:  21          21
...
int conversion:  48          48
int conversion:  29          29
int conversion:  39          39
int conversion:  40          40
int conversion:  29          29

共找到160个整数。

使用sscanf

使用sscanf您可以使用"%n"说明符来执行相同的操作,以确定数字转换所消耗的字符数,然后使用数字转换来更新缓冲区中的位置以进行下一次转换。

从仅作为十进制值的程序的第一个参数(如果没有给出参数,默认情况下从stdin读取文件名的示例可能类似于:

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

#define MAXC 1024

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

    char buf[MAXC] = "";    /* buffer to hold MAXC chars at a time */
    int nval = 0;           /* total number of integers found */
    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;
    }

    while (fgets (buf, MAXC, fp)) {

        char *p = buf;      /* pointer to line */
        int val,            /* int val parsed */
            nchars = 0;     /* number of chars read */

        /* while chars remain in buf and a valid conversion to int takes place
         * output the integer found and update p to point to the start of the
         * next digit.
         */
        while (*p) {
            if (sscanf (p, "%d%n", &val, &nchars) == 1) {
                printf (" %d", val);
                if (++nval % 10 == 0)     /* output 10 int per line */
                    putchar ('\n');
            }
            p += nchars;        /* move p nchars forward in buf */

            /* find next number in buf */
            for (; *p; p++) {
                if (*p >= '0' && *p <= '9') /* positive value */
                    break;
                if (*p == '-' && *(p+1) >= '0' && *(p+1) <= '9') /* negative */
                    break;
            }
        }
    }
    printf ("\n %d integers found.\n", nval);

    if (fp != stdin) fclose (fp);     /* close file if not stdin */

    return 0;
}

使用/输出示例

类似地,使用sscanf (和稍微不同的输出格式),您将获得:

$ ./bin/fgets_sscanf_int_any_ex <debug/dat/integermess.txt
 123 34 -54 21 45 34 65 -54 21 45
 34 65 -34 24 58 49 45 10 -57 20
 57 39 20 58 23 10 20 58 -60 76
 -82 28 28 -37 49 358 47 -50 37 29
 57 -29 -20 47 69 93 57 23 49 -38
 49 27 -40 48 39 56 -30 47 28 49
 37 49 27 26 10 20 58 -60 26 10
 20 58 -60 76 -82 28 28 -37 49 -28
 93 28 73 47 27 83 37 -29 40 37
 49 20 17 -26 12 17 17 18 38 29
 39 -118 19 10 20 58 -60 76 -82 28
 28 -37 49 59 10 58 -60 76 -82 28
 28 -37 49 59 10 20 58 -60 76 -82
 28 28 -37 49 30 -58 58 38 49 30
 -58 58 38 49 30 -58 58 38 28 39
 39 48 23 -50 28 48 29 39 40 29

 160 integers found.

您还有其他选择。 您可以使用fgetc 逐个字符地挑选出数字值并通过乘以10并加(如果是八进制十六进制 ,则乘以816来手动将字符转换为数字值,从而读取整个文件。 但是,使用经过良好测试的库函数要比您刚想到的函数要好得多。

仔细检查一下,如果您还有其他问题,请告诉我。 您基本上都处在正确的轨道上,只是还没有弄清楚转换结果,并且您正在砍掉每行的第一个字符。

您可能需要将循环更改为:

while(!feof(fp))

并将200更改为100。我认为每行200个字符有点太多。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM