首页 文章

调用isalpha导致分段错误

提问于
浏览
10

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

#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][k] 替换 argv[1] 解决了这个问题 .

但是,我觉得很奇怪程序导致分段错误,甚至没有打印 TEST . 我还希望 isalpha 函数错误地检查 char* 指针的低字节是否为 argv[1] ,但为了简洁起见,这里没有显示't seem to be the case. I have code to check for the number of arguments but isn't .

这里发生了什么事?

4 回答

  • 1

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

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

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

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

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

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

  • 19
    • printf 没有刷新

    • 从指针到整数的隐式转换应该至少生成约束违规的编译时诊断产生了一个超出 isalpha 范围的数字 . isalpha 作为查找表实现意味着您的代码访问了表格越界,因此未定义的行为 .

    • 为什么没有得到诊断可能是一部分,因为 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 ,这将使你的错误无声!


    我在这么多其他人之后发布这个答案的一个原因是 you didn't fix the code ,它仍然受到未定义的行为的影响,因为扩展字符和 char 被签名(在x86-32和x86-64上通常就是这种情况) .

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

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

  • 3

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

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

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

    isalpha 旨在使用单个字符 .

  • 6

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

    至于为什么"TEST"不是't printed, it could simply be because stdout isn' t . 你可以尝试在printf之后添加 fflush(stdout); ,看看这是否解决了这个问题 . 或者,在字符串的末尾添加换行符 \n .

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

相关问题