理解数组的概念

Understanding concept of array

main()
{
    char buffer[6]="hello";
    char *ptr3 = buffer +8; 
    char *str;   
    for(str=buffer;str <ptr3;str++)
        printf("%d \n",str);
}

此处,ptr3 指向数组边界之外。但是,如果我 运行 这个程序,我将获得连续的内存位置(例如 1000.....1007)。因此,根据 C 标准,指向超过数组边界的指针是明确未定义的行为。

我的问题是上述代码如何导致未定义的行为?

您看到的是指针的地址。如果您想要该值,则需要在 printf.

中使用取消引用 (*) 运算符

另一件事是,如果你想看到字符而不是 ASCII 码,你应该在 printf 中使用 %c

printf("%c\n",*str);

您的程序中多次出现未定义的行为。

对于初学者,您调用 printf 时没有要求 #include <stdio.h>main() 应该是 int main(void)。这不是你要问的问题,但你应该解决它。

char buffer[6]="hello";

没关系。

char *ptr3 = buffer +8; 

计算表达式 buffer +8 有未定义的行为。 N1570 6.5.6 指定了 + 加法运算符的行为,第 8 段说:

If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.

单独计算指针值具有未定义的行为,即使您从未取消引用它或访问它的值。

char *str;   
for(str=buffer;str <ptr3;str++)
    printf("%d \n",str);

您正在将 char* 值传递给 printf,但是 %d 需要 int 类型的参数。将错误类型的值传递给 printf 也有未定义的行为。

如果要打印指针值,需要这样写:

printf("%p\n", (void*)str);

这可能会以十六进制打印指针值,具体取决于实现。 (我删除了不必要的尾随 space。)

str指向buffer[5]时,str++有效;它导致 str 指向刚好超过 buffer 的末尾。 (在那之后取消引用 str 会有未定义的行为,但你不会那样做。)在那之后再次增加 str 有未定义的行为。比较 str < ptr3 也有未定义的行为,因为 ptr3 有一个无效值——但是你在初始化 ptr3 时已经触发了未定义的行为。所以这只是锦上添花。

请记住,"undefined behavior" 表示 C 标准未定义行为。这并不意味着程序会崩溃或打印错误消息。事实上,未定义行为的最坏可能后果是代码似乎 "work";这意味着你有一个错误,但很难诊断和修复它。

在 C 中,您始终可以将两个数字相加。您始终可以将一个整数与一个指针相加,或将两个指针相减。您将始终得到一个 "answer":编译器将生成代码并执行代码。这并不能保证答案是有效的、有用的,甚至是 定义的

C 标准定义了语言。在语法允许的范围内,它定义了什么是有效的——什么是绝对有意义的——什么是无效的。当您在这些行之外着色时,编译器可能会生成奇怪的代码或不生成代码。在 C 中,编译器的工作不是预测每一个奇怪的情况并得出合理的答案。编译器编写者假设程序员知道这些规则,并且不需要验证他是否遵守了这些规则。

有很多无意义或未定义的有效语法示例。在数学中,你不能取负数的对数,也不能除以零。除以零不会产生零或不为零;该操作是 未定义

在您的例子中,ptr3 的值经过适当计算,比 buffer 大 8。这是一些指针运算的结果。到目前为止,一切都很好。

但是仅仅因为你有一个指针,并不意味着它指向任何东西。 (void*) 0 明确保证不指向任何东西。同样,您的 ptr3 没有指向任何内容。它甚至不必是比 buffer 大 8 的值。 C标准的6.5.6节定义了一个整数与一个指针相加的结果,这样写:

If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.

当你说,我正在获取连续的内存位置(例如 1000.....1007),你看到的是行为。您必须看到 一些 行为。而且这种行为是不确定的。根据标准,您可能会看到一些其他行为,例如返回到 1000 或 0。

编译器接受的和标准定义的是两个不同的东西。