对文件内容使用 atoi() 时出现意外结果,按字符读取字符

Unexpected result when using atoi() on content of file, read char by char

我有一个文本文件,其中只有数字(0、1、2 和 3),我想处理数据以了解每个数字出现了多少次。

以下程序适用于小文本文件(<100 个数字),但适用于更大的文件(我最终需要处理数千个数据)程序读取不在文本文件中的数字。

这是我的代码:

FILE *file;
char c;
int nb;
int th0 = 0, th1 = 0, th2 = 0, th3 = 0;

file = fopen("../data", "r");

if (file == NULL) {
    printf("ERROR FILE: %s", strerror(errno));
    return EXIT_FAILURE;
}

while (1) {
    if (fscanf(file, "%c", &c) == EOF)
        break;

    nb = atoi(&c);

    printf("%d", nb);

    switch (nb) {
      case 0:
        th0++;
        break;

      case 1:
        th1++;
        break;

      case 2:
        th2++;
        break;

      case 3:
        th3++;
        break;

      default:
        break;
    }
}

如有任何建议,我将不胜感激。

编辑,输入文本与输出:

数据文件(181个号码):

001110120101010102012012021201021202102012012012012010210210210120120230103120130230123201320310231023102302301231203213210131032103210230120320310320213202301320123120312302321023

输出: The end of the reading is not what is in the data file and count 156 numbers

正在看

https://en.cppreference.com/w/c/string/byte/atoi

明白了

Parameters
str - pointer to the null-terminated byte string to be interpreted

但是

char c;
/* ... */
nb = atoi(&c);

您正在使用指向单个 char 的指针,后跟谁知道是什么。
对于任何恰好不是 '[=12=]' 的东西,您将从 atoi() 得到一个结果,即

a) 基于超出预期变量的访问
b) 对于后面的数字,是两位数或更高的数字

第一个选项表示您的代码需要修复。 第二个选项可以解释任何大于9的数字。

你的问题是 atoi 需要一个字符串,而你是这样调用它的:

nb = atoi(&c);

c 只是一个 char。有时这可能有效,但你基本上遇到了未定义的行为,因为你不能保证 c 之后的内存是空的。

相反,您想以不同的方式计算 nb

nb = c - '0';

这依赖于这样一个事实,即在 ASCII table 中,数字 0 到 9 在一个块中。从 c 中减去 '0' 的值将得到该字符的数值...假设它是一个数字。

为了确保它是一个数字,您应该将此 if 语句包裹在您的代码中

if(isdigit(c)) // Check if c is a digit
    {
    nb = c - '0';

    switch(nb) {
        case 0: th0++;
        break;
    // rest of switch goes here....
         }
    }

您调用 atoi 时使用了指向 char 的指针,该指针未指向正确的 C 字符串,因此您的代码具有未定义的行为,有时看起来像预期的那样工作,有时却行为不端...

由于您处理的是数字,因此可以通过简单的减法计算数字所代表的值 c - '0'

您还可以使用数组简化代码:

#include <stdio.h>

int main() {
    FILE *file;
    int c, i;
    int count[10] = { 0 };

    file = fopen("../data", "r");
    if (file == NULL) {
        printf("ERROR FILE: %s", strerror(errno));
        return EXIT_FAILURE;
    }

    while ((c = getc(file)) != EOF) {
        if (c >= '0' && c <= '9')
            count[c - '0']++;
    }
    fclose(file);

    printf("counts:\n");
    for (i = 0; i < 10; i++) {
        printf("%d: %d\n", i, count[i]);
    }
    return 0;
}