对文件内容使用 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;
}
我有一个文本文件,其中只有数字(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;
}