【问题标题】:Wrong atoi() output in some parts of an array数组某些部分的 atoi() 输出错误
【发布时间】:2019-10-24 21:50:23
【问题描述】:

我正在读取一个输入文件并将其写入一个二维整数数组。文件中的所有数字都有两个字符。

效果很好,但在所有 [48]-[57] 元素中,整数都有一个冗余数字(例如,30、871、447 而不是 3、87、44)。 strtol() 也有同样的问题。输入文件的十六进制代码在这些部分看起来完全正常。

for (int a = 0; a < d; a++)
{
    for (int b = 0; b < d; b++)
    {
        //read two chars
        uint16_t num;
        fread(&num, sizeof(char) * 2, 1, inptr);

        //convert to int and put to the array (it makes wrong int in 48 <= b <= 57)
        arr[a][b] = atoi((char*)&num);

        //skip space or line break in the input file
        fseek(inptr, sizeof(char), SEEK_CUR);
    }
}

有什么问题?为什么只有 [48]-[57] 工作不正确?

【问题讨论】:

  • 您应该提供minimal reproducible example。在这种情况下,您应该创建一个简单的 main 函数并删除 fread 并仅使用无效的数字加载 num。如果您找不到这样的号码,那么您可以创建一个不带atoiminimal reproducible example
  • 此外,sizeof(char) 只是1 的一种奇特写作方式;)
  • 另外,你的文件编码是什么?似乎 l 似乎您希望每个数字都由恰好一个字符分隔,但情况可能并非如此,尤其是对于新行
  • 对于您描述的数据,由于atoi() 执行越界访问,您的程序表现出未定义的行为,结果,反过来,您正在输入的数据它没有在num 的范围内以空值结尾。从技术上讲,“未定义”意味着无需解释为什么某些输入数据会出现不当行为,而其他数据不会发生不当行为,但在实践中,我怀疑修复该问题不会解决观察到的不当行为。
  • atoi 需要空终止符,但您的 fread 不添加空终止符。它只是从文件中读取两个字符,这两个字符都不可能是\0。 (也不清楚你为什么要输入uint16_t。为什么不读入一个字符数组?)

标签: c atoi strtol


【解决方案1】:

感谢所有 cmets,尤其是那些提到 atoi 所需的 \0 的人。

使用char str[3] 而不是uint16_t 可以解决问题,并且可以正确转换所有数字。

for (int a = 0; a < d; a++)
{
    for (int b = 0; b < d; b++)
    { 
        char str[3];
        str[2] = '\0';
        fread(&str, 2, 1, inptr);
        arr[a][b] = atoi(str);
        fseek(inptr, 1, SEEK_CUR);
    }
}

【讨论】:

  • 除了(char*)&amp;num 不是字符串之外,atoi 还提供零错误检测和零验证转换的方法——因此您在原始代码中对atoi 的无效使用不可能是检测到。这就是为什么生产代码应该始终使用 strtolstrtoul 并完全验证 (1) 数字已转换,(2) 转换未设置 errno 以及结果类型是否小于转换的大小(3) 该值在最终使用的类型的范围内。
  • @DavidC.Rankin 非常正确,但考虑到他使用fseek(inptr, 1, SEEK_CUR) 盲目地跳过可能是空格、换行符或可能意外成为另一个数字的字符,这有点没有意义。 ..
  • 同意,示例输入在这种情况下会很有帮助。尽管atoistrtol 等的使用将保持不变。
猜你喜欢
  • 1970-01-01
  • 2017-10-12
  • 2017-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-19
  • 1970-01-01
相关资源
最近更新 更多