Ras*_*yak 39 c codeblocks
当我运行这个程序时,我收到警告"数组下标有类型'char'".请帮帮我哪里出错了.我正在使用code :: blocks IDE
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
void NoFive()
{
long long int cal;
char alpha[25];
char given[100] = "the quick brown fox jumped over the cow";
int num[25];
int i, k;
char j;
j = 'a';
k = 26;
cal = 1;
for(i = 0; i <= 25; i++)
{
alpha[i] = j++;
num[i] = k--;
// printf("%c = %d \n", alpha[i], num[i]);
}
for(i = 0; i <= (strlen(given) - 1); i++)
{
for(j = 0; j <= 25; j++)
{
if(given[i] == alpha[j]) ***//Warning array subscript has type char***
{
cal = cal * num [j]; ***//Warning array subscript has type char***
}
else
{
}
}
}
printf(" The value of cal is %I64u ", cal);
}
main()
{
NoFive();
}
Run Code Online (Sandbox Code Playgroud)
Pav*_*ath 71
简单,改变
char j;
Run Code Online (Sandbox Code Playgroud)
至
unsigned char j;
Run Code Online (Sandbox Code Playgroud)
或者只是一个平原 (u)int
unsigned int j;
int j;
Run Code Online (Sandbox Code Playgroud)
来自GCC警告
-Wchar-subscripts如果数组下标的类型为char,则发出警告.这是导致错误的常见原因,因为程序员经常忘记这种类型是在某些机器上签名的.-Wall启用此警告.
编译器不希望您无意中指定负数组索引.因此警告!
这是一个典型的案例,海湾合作委员会在其诊断中使用了过于官僚和间接的措辞,这使得很难理解这个有用警告背后的真正问题。
// Bad code example
int demo(char ch, int *data) {
return data[ch];
}
Run Code Online (Sandbox Code Playgroud)
根本问题是 C 编程语言为“字符”定义了几种数据类型:
char
可以容纳一个“来自基本执行字符集的字符”(其中至少包括 AZ、az、0-9 和几个标点字符)。unsigned char
可以保存至少 0 到 255 范围内的值。signed char
可以保存至少 -127 到 127 范围内的值。C 标准定义该类型的char
行为方式与signed char
or 或相同unsigned char
。实际选择这些类型中的哪一种取决于编译器和操作系统,并且必须由它们记录。
当arr[index]
表达式访问数组元素时,GCC 调用index
a 下标。在大多数情况下,这个数组索引是一个无符号整数。这是常见的编程风格,如果数组索引为负数,Java 或 Go 等语言会抛出异常。
在 C 中,越界数组索引被简单地定义为调用未定义的行为。编译器不能在所有情况下都拒绝负数组索引,因为以下代码完全有效:
const char *hello = "hello, world";
const char *world = hello + 7;
char comma = world[-2]; // negative array index
Run Code Online (Sandbox Code Playgroud)
C标准库中有一个地方很难正确使用,那就是来自header的字符分类函数<ctype.h>
,比如isspace
. 该表达式isspace(ch)
看起来好像将一个字符作为其参数:
isspace(' ');
isspace('!');
isspace('ä');
Run Code Online (Sandbox Code Playgroud)
前两种情况是可以的,因为空格和感叹号来自基本执行字符集,因此被定义为表示相同,无论编译器定义char
为有符号还是无符号。
但最后一种情况,元音变音'ä'
,是不同的。它通常位于基本执行字符集之外。在 1990 年代流行的字符编码 ISO 8859-1 中,字符'ä'
表示如下:
unsigned char auml_unsigned = 'ä'; // == 228
signed char auml_signed = 'ä'; // == -28
Run Code Online (Sandbox Code Playgroud)
现在想象该isspace
函数是使用数组实现的:
static const int isspace_table[256] = {
0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 0, 0, 1, 0, 0,
// and so on
};
int isspace(int ch)
{
return isspace_table[ch];
}
Run Code Online (Sandbox Code Playgroud)
这种实现技术是典型的。
回到调用isspace('ä')
,假设编译器已定义char
为signed char
并且编码为 ISO 8859-1。调用该函数时,字符的值为 -28,并将该值转换为int
,保留该值。
这导致表达式isspace_table[-28]
,它访问数组边界之外的表。这会调用未定义的行为。
编译器警告所描述的正是这种情况。
从头<ctype.h>
文件调用函数的正确方法是:
// Correct example: reading bytes from a file
int ch;
while ((ch = getchar()) != EOF) {
isspace(ch);
}
// Correct example: checking the bytes of a string
const char *str = "hello, Ümläute";
for (size_t i = 0; str[i] != '\0'; i++) {
isspace((unsigned char) str[i]);
}
Run Code Online (Sandbox Code Playgroud)
还有几种方法看起来很相似,但都是错误的。
// WRONG example: checking the bytes of a string
for (size_t i = 0; str[i] != '\0'; i++) {
isspace(str[i]); // WRONG: the cast to unsigned char is missing
}
// WRONG example: checking the bytes of a string
for (size_t i = 0; str[i] != '\0'; i++) {
isspace((int) str[i]); // WRONG: the cast must be to unsigned char
}
Run Code Online (Sandbox Code Playgroud)
上面的示例将字符值-28
直接转换为int
value -28
,从而导致数组索引为负。
// WRONG example: checking the bytes of a string
for (size_t i = 0; str[i] != '\0'; i++) {
isspace((unsigned int) str[i]); // WRONG: the cast must be to unsigned char
}
Run Code Online (Sandbox Code Playgroud)
本示例将字符值-28
直接转换为unsigned int
. 假设使用通常的二进制补码整数表示的 32 位平台,-28
通过重复添加 2^32 来转换该值,直到该值在 范围内unsigned int
。在这种情况下,这会导致数组索引 4_294_967_268,它太大了。