我似乎无法解决这个问题。以下是我的代码:
#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))’
答案 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
类型是带符号的类型,那么你可能会传递一个负数的索引。 char
,getchar()
或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的计数是否相同