调用isalpha导致分段错误

Moh*_*han 10 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;
}
Run Code Online (Sandbox Code Playgroud)

我已经发现正是这条线导致了这个问题

if (!isalpha(argv[1])) {
Run Code Online (Sandbox Code Playgroud)

并替换argv[1]argv[1][k]解决问题.

但是,我觉得很奇怪程序会导致分段错误而不打印TEST.我还希望isalpha函数错误地检查char*指针的低字节是否argv[1],但似乎不是这种情况.我有代码来检查参数的数量,但为简洁起见,此处未显示.

这里发生了什么事?

Ger*_*rdh 19

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

但也许尝试理解为什么会发生某些事情并不会有害,即使它不符合规范.

有一些实现isalpha使用一个简单的数组来查找所有可能的unsigned char值.在这种情况下,作为参数传递的值将用作数组的索引.虽然真实字符限制为8位,但整数不是.该函数采用intas参数.这是为了允许进入EOF不适合的进入unsigned char.

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

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

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


Ant*_*ala 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)
    
    Run Code Online (Sandbox Code Playgroud)

    宏包含一个不幸的演员int,它将使你的错误沉默!


我在这么多人之后发布这个答案的一个原因是你没有修复代码,它仍然受到扩展字符和char签名的未定义行为的影响(在x86-32和x86-64上通常都是这种情况) ).

正确的论据isalpha(unsigned char)argv[1][k]!C11 7.4:

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