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

时间:2018-06-29 13:42:04

标签: c file atoi

我有一个文本文件,其中只有数字(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

3 个答案:

答案 0 :(得分:4)

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

nb = atoi(&c);

c只是char。有时候这可能行得通,但是由于无法保证c之后的内存为空,因此您基本上遇到了未定义的行为。

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

nb = c - '0';

这取决于以下事实:在ASCII表中,数字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....
         }
    }

答案 1 :(得分:3)

看着

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

我知道

  

参数
  str-指向要解释的以空终止的字节字符串的指针

但使用

PS C:\Users\atroach\Documents\GitHub\OfficeShortcuts> .\OfficeShortcuts.ps1 -c

...

Select which items you would like placed on the desktop:
1: Word
2: Excel
3: PowerPoint
4: Outlook
5: Access
6: OneNote
7: Publisher
D: Press 'D' when done.
You have selected: Excel PowerPoint
Please make a selection: d
PS C:\Users\username\Documents\GitHub\OfficeShortcuts>

您正在使用指向单个char c; /* ... */ nb = atoi(&c); 的指针,后跟who-knows-what。
对于碰巧不是char的任何事物,您将从'\0'得到的结果是

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

第一个选项意味着您的代码需要修复。 第二个选项可以解释任何数字> 9。

答案 2 :(得分:0)

您使用指向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;
}