当我运行这个程序时,我收到警告“数组下标有'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();
}
答案 0 :(得分:63)
简单,改变
char j;
到
unsigned char j;
或只是普通(u)int
unsigned int j;
int j;
-Wchar-subscripts 如果数组下标的类型为char,则发出警告。这是错误的常见原因,因为程序员经常忘记这种类型 在某些机器上签名。 -Wall启用此警告。
编译器不希望您无意中指定负数组索引。因此警告!
答案 1 :(得分:6)
这是GCC在诊断中使用过分官僚和间接措词的典型情况,这使得很难理解此有用警告背后的真正问题。
// Bad code example
int demo(char ch, int *data) {
return data[ch];
}
根本问题是C编程语言为“字符”定义了几种数据类型:
char
可以包含“基本执行字符集中的字符”(至少包括A-Z,a-z,0-9和几个标点符号)。unsigned char
可以保存至少0到255之间的值。signed char
至少可以保存-127到127范围内的值。 C标准定义类型char
的行为与signed char
或unsigned char
相同。实际选择哪种类型取决于编译器和操作系统,并且必须由它们进行记录。
当arr[index]
表达式访问数组的元素时,GCC将index
称为下标。在大多数情况下,此数组索引是无符号整数。这是常见的编程风格,如果数组索引为负,则Java或Go之类的语言都会引发异常。
在C语言中,越界数组索引仅定义为调用未定义行为。由于以下代码完全有效,因此编译器不能在所有情况下都拒绝负数组索引:
const char *hello = "hello, world";
const char *world = hello + 7;
char comma = world[-2]; // negative array index
C标准库中有一个地方很难正确使用,那就是头文件<ctype.h>
中的字符分类函数,例如isspace
。表达式isspace(ch)
看起来好像将一个字符作为其参数:
isspace(' ');
isspace('!');
isspace('ä');
前两种情况都可以,因为空格和感叹号来自基本执行字符集,因此无论编译器是否定义{{1} }签名或未签名。
但是最后一种情况,变音符号char
是不同的。它通常位于基本执行字符集之外。在1990年代流行的字符编码ISO 8859-1中,字符'ä'
表示如下:
'ä'
现在想象一下unsigned char auml_unsigned = 'ä'; // == 228
signed char auml_signed = 'ä'; // == -28
函数是使用数组实现的:
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];
}
,假设编译器已将isspace('ä')
定义为char
,并且编码为ISO 8859-1。调用该函数时,字符的值为-28,并且将此值转换为signed char
,并保留该值。
这将导致表达式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]);
}
以上示例将字符值// 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
}
直接转换为-28
值int
,从而导致数组索引为负。
-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
}
直接转换为-28
。假定一个具有通常的二进制补码整数表示的32位平台,则通过重复加2 ^ 32直到值在unsigned int
范围内,来转换值-28
。在这种情况下,这将导致数组索引4_294_967_268太大。
答案 2 :(得分:0)
请注意,Roland Illig 的解释有些不完整;这些天,'ä'
甚至可能无法编译(或者它可能编译为不适合一个字节的东西,但这非常依赖于实现,甚至可能是 UB)。
如果您使用的是 UTF-8,则 "ä"
与 "\xc3\xa4"
相同。