C编程警告:数组下标的类型为'char'[-Wchar-subscripts]

时间:2014-05-07 00:49:48

标签: c arrays gcc char subscript

我似乎无法解决这个问题。以下是我的代码:

#include<stdio.h>
#include<ctype.h>
#include<string.h>

_Bool are_anagrams (const char *word1, const char *word2);

int main (void)
{
    char an1[30], an2[30];
    int j;
    printf("Enter first word: ");
    scanf("%s", an1);
    printf("Enter second word: ");
    scanf("%s", an2);
    printf("The words are");

    j = are_anagrams (an1, an2);

    if (j == 0)
    {
        printf(" not anagrams. \n");
    }else
        printf(" anagrams. \n");

    return 0;
}

_Bool are_anagrams (const char *word1, const char *word2)
{
    int i;
    int check[26] = {0};
    for(i=0; i<30; i++)
        if(word1[i] == '\0')
            i=40;
        else
        {
            word1[i] = toupper(word1[i]);
            check[word1[i]-65]++;
        }

    for(i=0; i<30; i++)
        if(word2[i] == '\0')
            i=40;
        else
        {
            word2[i] = toupper(word2[i]);
            check[word2[i]-65]--;
        }

    for(i=0; i<26; i++)
        if(check[i] != 0)
        {
            return 0;
        }

    return 1;
}

这些是错误消息:

anagram1.c:38:3: warning: array subscript has type ‘char’ [-Wchar-subscripts]
   word1[i] = toupper(word1[i]);
   ^
anagram1.c:38:3: error: assignment of read-only location ‘*(word1 + (sizetype)((long unsigned int)i * 1ul))’
anagram1.c:46:4: warning: array subscript has type ‘char’ [-Wchar-subscripts]
    word2[i] = toupper(word2[i]);
    ^
anagram1.c:46:4: error: assignment of read-only location ‘*(word2 + (sizetype)((long unsigned int)i * 1ul))’

3 个答案:

答案 0 :(得分:5)

警告:

warning: array subscript has type ‘char’

是&#39; toupper()&#39;的结果。需要一个&#39; int&#39;键入作为参数,而问题代码提供一个&#39; char&#39;类型。

word1[i] = toupper(word1[i]);
...
word2[i] = toupper(word2[i]);

要消除警告,请给toupper()&#39; int&#39;值:

word1[i] = toupper((unsigned char)word1[i]);
...
word2[i] = toupper((unsigned char)word2[i]);

要彻底,您可以投放&#39; toupper()&#39;返回的值。来自&#39; int&#39;回到&#39; char&#39;:

word1[i] = (char)toupper((unsigned char)word1[i]);
...
word2[i] = (char)toupper((unsigned char)word2[i]);

错误:

error: assignment of read-only location

是尝试使用&#39; const&#39;修改值的结果。标志:

_Bool are_anagrams (const char *word1, const char *word2)

如果合适,您可以通过消除&#39; const&#39;来消除错误。国旗:

_Bool are_anagrams (char *word1, char *word2)

或者,您可以制作&#39; const&#39;的本地工作副本。字符串:

_Bool are_anagrams (const char *I__word1, const char *I__word2)
   {
   int rCode = 0;
   int i;
   int check[26] = {0};
   char *word1 = strdup(I__word1);
   char *word2 = strdup(I__word2);

   for(i=0; i<30; i++)
      if(word1[i] == '\0')
         i=40;
      else
         {
         word1[i] = toupper(word1[i]);
         check[word1[i]-65]++;
         }

   for(i=0; i<30; i++)
      if(word2[i] == '\0')
         i=40;
      else
         {
         word2[i] = toupper(word2[i]);
         check[word2[i]-65]--;
         }

   for(i=0; i<26; i++)
      if(check[i] != 0)
        goto CLEANUP;

   rCode=1;

CLEANUP:
   free(word2);
   free(word1);

   return(rCode);
   }

注意:上面的代码使用了问题代码正文,这可能是准确的,也可能是不准确的。这个答案无意解决问题代码中的其他问题;只是为了展示一种适当的方法来解决这个问题。通过创建非&#39; const&#39;来标记参数。参数的副本

答案 1 :(得分:2)

toupper中声明的tolower<ctype.h>函数(以及is*()函数)期望int类型的参数。

类型不是问题所在,因为char会隐式转换为int。问题是他们期望的必须在unsigned char 范围内EOF(通常为-1) 。我们可以忽略EOF案例。

普通char是签名或未签名的,是您编译器开发人员的心血来潮(由您的系统的ABI指导)。如果普通char已签名,并且您传递给toupper的值恰好具有负值(不等于EOF),那么您有未定义的行为。

解决方案是将参数显式转换(强制转换)为unsigned char

而不是:

word1[i] = toupper(word1[i]);

你需要写:

word1[i] = toupper((unsigned char)word1[i]);

是的,不幸的是你必须这样做。如果toupper()只使用char类型的参数并返回char结果,那会更好。但事实就是这样,我们一直坚持下去。

那么为什么你会收到关于char类型的数组下标的警告? toupper函数通常实现为扩展为数组索引操作的宏。在预处理器扩展宏调用之后,它不再像函数调用那样查找(对编译器的其余部分)。 (任何标准库函数都可以实现为宏,只要宏具有与实际函数调用相同的行为。)

答案 2 :(得分:2)

正如Mahonri Moriancumer answer正确识别Keith Thompson(实际上,answer正确识别并在C isupper() function中解释),{{3}}调用问题{{3}} 1}}您传递的类型是toupper(),但函数期望char。但由于int可以包含int可以包含的任何值,为什么会抱怨?

答案是有效char值的范围受到标准(ISO / IEC 9888:2011)的限制:

  

7.4字符处理int

     

在所有情况下,参数都是<ctype.h>,其值应为。{1}}   可表示为int或等于宏EOF的值。如果   参数有任何其他值,行为未定义。

编译器警告你的是,如果你将unsigned char传递给这个函数,并且char类型是带符号的类型,那么你可能会传递一个负数的索引。 chargetchar()getc()的结果与函数的参数类型的规范相匹配(这不是偶然的)。编译器假设您使用fgetc()时不会超出边界值,但如果使用普通int来保存“Å”等字符(U + 00C5,LATIN CAPITAL LETTER A WITH RING ABOVE)和普通char已签名,那么您将传递一个超出有效值范围的负值。

如果是我的代码,我会转向char

unsigned char

简单地将签名后的word1[i] = toupper((unsigned char)word1[i]); 投射到char并不能正确处理该符号。

您可以查看{{3}}以了解有关范围设置原因的详细信息。


另一对错误是因为您修改了一个常量字符串。您可以使用以下命令避免该错误(对于非重音字符)

int

这可以避免输入中的空格,数字和标点符号出现问题。但是,如果您需要在输入中处理重音字符,那么最好的办法是将unsigned char uc = word1[i]; if (isalpha(uc)) check1[toupper(uc) - 'A']++; 变为256的数组,然后检查整个范围0..255的计数是否相同