我有以下程序,它会导致分段错误。
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(int argc, char *argv[])
{
printf("TEST");
for (int k=0; k<(strlen(argv[1])); k++)
{
if (!isalpha(argv[1])) {
printf("Enter only alphabets!");
return 1;
}
}
return 0;
}我发现是这条线导致了这个问题
if (!isalpha(argv[1])) {而用argv[1]代替argv[1][k]解决了这一问题。
然而,我发现很奇怪的是,这个程序导致了一个分割错误,甚至没有打印TEST。我还期望isalpha函数不正确地检查指向argv[1]的char*指针的下字节是否正确,但情况似乎并非如此。我有代码来检查参数的数量,但这里没有简单显示。
这里发生了什么事?
发布于 2018-05-28 11:13:51
一般来说,讨论为什么未定义的行为会导致这样或那样的结果是毫无意义的。
但是,尝试理解某些事情发生的原因并不有害,即使它超出了规范的范围。
isalpha的实现使用一个简单的数组来查找所有可能的unsigned char值。在这种情况下,作为参数传递的值被用作数组的索引。当一个真正的字符被限制为8位时,整数就不是了。该函数以一个int作为参数。这也是为了允许输入不适合于EOF的unsigned char。
如果您将像0x7239482342这样的地址传递到您的函数中,这远远超出了所述数组的末尾,当CPU试图使用该索引读取条目时,它会从世界边缘掉下来。;)
使用这样的地址调用isalpha是编译器在将指针转换为整数时应该发出一些警告的地方。你可能忽略了..。
库可能包含检查有效参数的代码,但也可能只依赖于用户,而不是传递不应该传递的内容。
发布于 2018-05-28 11:37:12
printf没有脸红isalpha范围的数字。isalpha被实现为一个查找表,这意味着您的代码访问表超出了界限,因此没有定义行为。isalpha是如何作为宏实现的。在我使用Glibc 2.27-3 3ubuntu1 1的计算机上,isalpha被定义为定义isalpha(c) __isctype( (c),_ISalpha) # defined __isctype(c,type) \ ((*__ctype_b_loc ())(int) (C)&(无符号短int)类型)宏包含一个不幸的转换到int中,这将使您的错误安静下来!在这么多人之后我发布这个答案的原因之一是,您没有修复代码,它仍然存在给定扩展字符和char被签名的未定义行为(在x86-32和x86-64上通常就是这种情况)。
给isalpha的正确的论据是(unsigned char)argv[1][k]!C11 7.4
在所有情况下,参数都是
int,其值应表示为unsigned char或等于宏EOF的值。如果参数有任何其他值,则行为未定义.。
发布于 2018-05-28 11:05:09
我觉得很奇怪的是,这个程序在没有打印测试的情况下导致分割错误。
printf不会立即打印,但它会写入时态缓冲区。如果要将字符串刷新到实际输出,则使用\n结束字符串。
而用argv1代替argv1解决了这一问题。
isalpha用于处理单个字符。
https://stackoverflow.com/questions/50564810
复制相似问题