我正在阅读K& R,目前正在阅读第1章。在阅读了一节并尝试解决问题之后,我想在线查看其他解决方案,只是看到了解决同一问题的不同方法。
练习1-14说我们需要在输入中打印不同字符频率的直方图。我发现这个解决方案只考虑字母字符:
#include <stdio.h>
#define MAX 122
#define MIN 97
#define DIFF 32
int main(){
int c = EOF;
int i, j;
int array[MAX - MIN];
printf("%d ", MAX - MIN);
for (i = MIN; i <= MAX; i++){
array[i] = 0;
printf("%d ", i);
}
while ((c = getchar()) != EOF){
if (c >= MIN)
++array[c];
else {
++array[c + DIFF];
}
}
for (i = MIN; i <= MAX; i++){
printf("|%c%c|", i - DIFF, i);
for (j = 1; j <= array[i]; j++){
putchar('*');
}
putchar('\n');
}
return 0;
}
虽然我理解这段代码背后的逻辑,但我并不了解array[]
数组的工作原理或原因。声明数组时,它的大小为25 (MAX - MIN).
此数组应从0到24建立索引。但在第一个循环中,使用97
到122
的值对数组建立索引。但是,如果索引从一个更大的值开始,那么如何访问该数组呢?不应该循环
for (i = 0, i < MAX - MIN; i++)
对我来说,如何从
索引数组是没有意义的array[97] ... array[122]
编辑:
我自己在第一个循环中添加了printf("%d ", MAX - MIN);
和printf("%d ", i);
,以尝试查看它是否实际上是从97
开始索引数组。
答案 0 :(得分:2)
25
此处,数组的大小为197-97 = 25
,因为 for (i = MIN; i <= MAX; i++){
array[i] = 0;
。
array[i]
此处,25
的索引超出范围,因为数组的大小为MIN
,而值97
为++array[c];
。
此外,j <= array[i];
和source_file.c: In function ‘main’:
source_file.c:14:10: warning: array subscript is above array bounds [-Warray-bounds]
array[i] = 0;
^
source_file.c:20:12: warning: array subscript is above array bounds [-Warray-bounds]
++array[c];
^
source_file.c:20:12: warning: array subscript is above array bounds [-Warray-bounds]
source_file.c:28:27: warning: array subscript is above array bounds [-Warray-bounds]
for (j = 1; j <= array[i]; j++){
^
未定义,因为超出范围。
GCC编译器生成警告:
a[1][7]
C11 J.2未定义的行为
将指针加到或减去数组对象和整数类型会产生一个指向超出范围的结果 数组对象,并用作一元*运算符的操作数 评估(6.5.6)。
数组下标超出范围,即使对象显然也是如此 可以使用给定的下标访问(如左值表达式)
a[4][5])
给出声明int {{1}}(6.5.6)。
答案 1 :(得分:2)
实际上,for循环访问数组越界,调用 Undefined Behavior ,这意味着你的程序可能会崩溃。
MAX - MIN
给出25并且您使用[97,122]中的索引访问数组,这是完全错误的。
同样,++array[c]
和for (j = 1; j <= array[i]; j++)
也会调用Undefined Behavior,因为它们也会超出界限。
PS:你需要声明你的数组大小为MAX - MIN + 1
,因为英文字母有26个字母。
答案 2 :(得分:0)
数组有no boundary checking in C
,程序员有责任负责处理它。
所以当你将数组声明为
时int array[ MAX - MIN ] ;
您不仅限于使用sizeof( int ) * (MAX - MIN)
,但如果您不在此范围内使用,则行为非常不稳定。
还有其他编程语言可以强制执行数组边界检查,但不能执行c,除非它经过严格的编译步骤,包括字符串警告检查。
所以在这种情况下即使程序工作也不正确。
或许要理解的底线是
“工作代码可能并不总是正确的代码”