调用isalpha导致分段错误

时间:2018-05-28 10:57:31

标签: c pointers segmentation-fault

我有以下程序导致分段错误。

#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函数错误地检查char*指针的低字节是否argv[1],但似乎并非如此。我有代码来检查参数的数量,但为简洁起见,此处未显示。

这里发生了什么?

4 个答案:

答案 0 :(得分:19)

一般来说,讨论为什么未定义的行为导致这个结果或另一个结果是毫无意义的。

但是,尝试理解为什么会发生某些事情,即使它超出规范也许并不是一种伤害。

isalpha的实现使用简单数组来查找所有可能的unsigned char值。在这种情况下,作为参数传递的值将用作数组的索引。 虽然真实字符限制为8位,但整数不是。 该函数以int为参数。这也是为了允许输入不适合EOF的{​​{1}}。

如果你将一个像0x7239482342这样的地址传递给你的函数,这远远超出了所述数组的结尾,并且当CPU试图读取带有该索引的条目时,它就会脱离世界的边缘。 ;)

使用这样的地址调用unsigned char是编译器应该提出关于将指针转换为整数的警告的地方。你可能忽略了......

可能包含检查有效参数的代码,但它也可能只依赖于用户不传递不会传递的内容。

答案 1 :(得分:6)

  1. printf没有被冲洗
  2. 从指针到整数的隐式转换应该至少生成约束违规的编译时诊断,这会产生一个超出isalpha范围的数字。 isalpha被实现为查找表意味着您的代码访问了表格越界,因此未定义的行为。
  3. 为什么没有获取诊断信息可能属于一个部分,因为 isalpha如何实现为宏。在我的带有Glibc 2.27-3ubuntu1的计算机上,isalpha被定义为

    # define isalpha(c)     __isctype((c), _ISalpha)
    # define __isctype(c, type) \
        ((*__ctype_b_loc ())[(int) (c)] & (unsigned short int) type)
    

    宏中包含一个不幸的强制转换为int,这会使你的错误无效!

  4. 我在其他许多人之后发布此答案的一个原因是您没有修复代码,但是在给定扩展字符和char签名的情况下,它仍会受到未定义行为的影响(这通常是x86-32和x86-64的情况。

    提供给isalpha的正确参数是(unsigned char)argv[1][k]C11 7.4

      

    在所有情况下,参数都是int,其值应表示为unsigned char或等于宏EOF的值。 如果参数具有任何其他值,则行为未定义。

答案 2 :(得分:3)

  

我觉得很奇怪程序导致分段错误,甚至没有打印TEST

printf不会立即打印,但会写入临时缓冲区。如果要将其刷新为实际输出,请使用\n结束字符串。

  

用argv [1] [k]替换argv [1]解决了这个问题。

isalpha旨在使用单个字符。

答案 3 :(得分:1)

首先,符合标准的编译器必须在此处为您提供诊断消息。不允许从指针隐式转换为if(Page.IsValid) {} 期望的int参数。 (这违反了简单分配规则,6.5.16.1。)

至于为什么不打印“TEST”,可能只是因为没有刷新stdout。您可以尝试在printf之后添加isalpha,看看是否能解决问题。或者,在字符串末尾添加换行符fflush(stdout);

否则,只要没有副作用,编译器就可以自由地重新排序代码的执行。也就是说,允许在\n之前执行整个循环,只要它在可能打印printf("TEST");之前打印TEST。这种优化可能不会在这里发生,但在其他情况下它们可能会发生。