大家好。我想知道为什么我用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
749个
    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
八十三
输出切断了某些数字,它给了我不正确的整数总数。请帮忙。谢谢你,祝你今天愉快。
更新:谢谢你的帮助。不幸的是,将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
七十三
然而,从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
八十三
如果你有更多的建议,请告诉我。再次感谢大家。

最佳答案

输出切断了某些数字,它给了我不正确的
整数总数。
当然有。您正在读取并从输入流中删除一个字符:

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_MIN <= val && val <= INT_MAX,因为存储类型(int)与转换类型(long)不同。)
示例使用/输出
当您的数据文件位于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和加法(或在八进制和十六进制情况下乘以108将字符手动转换为数值)。然而,使用一个经过良好测试的库函数要比一个偶然出现的库函数好得多。。。
再看一遍,如果你还有问题,请告诉我。你基本上是在正确的轨道上,你只是还没有找到转换,你正在削减每行的第一个字符。

关于c - 为什么我的C程序无法正确计算和打印文本文件中的整数?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53137072/

10-12 22:58