簡體   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