指针如何指向[-1]数组的索引每次产生合法输出。指针赋值实际发生了什么?
#include<stdio.h>
int main()
{
int realarray[10];
int *array = &realarray[-1];
printf("%p\n", (void *)array);
return 0;
}
代码输出:
manav@workstation:~/knr$ gcc -Wall -pedantic ptr.c
manav@workstation:~/knr$ ./a.out
0xbf841140
编辑:如果这种情况有效,那么我可以用它来定义索引从1开始而不是0的数组,即:array [1],array [2],..
答案 0 :(得分:13)
您只需获取一个包含该“虚构”位置地址的指针,即第一个元素&realarray[0]
的位置减去一个元素的大小。
这是undefined behavior,如果您的机器具有分段内存架构,可能会破坏性。这是有效的,因为编译器编写者选择实现上面概述的算法;随时都可能发生变化,而另一个编译器可能表现完全不同。
答案 1 :(得分:9)
a[b]
定义为*(a+b)
因此a[-1]
为*(a-1)
a-1
是否是有效指针,因此取消引用有效取决于使用代码的上下文。
答案 2 :(得分:3)
行为未定义。
您所观察到的内容可能发生在您的特定编译器和配置中,但任何情况都可能发生在不同的情况。你完全不能依赖这种行为。
答案 3 :(得分:3)
行为未定义。您只能计算指向数组中任何元素的指针,或者只能计算一个指针,但就是这样。您只能取消引用指向数组中任何元素的指针(而不是指针的过去)。查看您的变量名称,看起来就像是在问this C FAQ的问题。我认为FAQ的答案非常好。
答案 4 :(得分:3)
虽然正如其他人所说,在这种情况下它是未定义的行为,但它会在没有警告的情况下编译,因为一般,foo[-1]
可能有效。
例如,这很好:
int realarray[10] = { 10, 20, 30, 40 };
int *array = &realarray[2];
printf("%d\n", array[-1]);
答案 5 :(得分:2)
在C和C ++中,不会在运行时检查数组索引。您正在执行指针运算,这可能会或可能不会最终给出定义的结果(不在此处)。
但是,在C ++中,您可以使用提供边界检查的数组类,例如boost::array
或std::tr1::array
(将被添加到C ++ 0x中的标准库中):
#include <cstdio>
#include <boost/array.hpp>
int main()
{
try {
boost::array<int, 10> realarray;
int* p = &realarray.at(-1);
printf("%p\n", (void *)p);
} catch (const std::exception& e) {
puts(e.what());
}
}
输出:
array&lt;&gt ;: index超出范围
还会产生编译器警告:
8 test.cpp [警告]传递否定 价值
-0x000000001' for converting 1 of
T&amp;升压::阵列::在(为size_t) [使用T = int,unsigned int N = 10u]'
答案 6 :(得分:1)
它只是指向内存中数组前面的项目地址。
可以简单地将数组视为指针。然后简单地将其减1。
答案 7 :(得分:1)
这里你只是执行指针算术,它将获得relarray的第一个索引地址
请注意,如果你和&amp; relarray [+1],你将得到数组的第二个元素地址。从那以后
&amp; relarray [0]指向第一个索引地址。
答案 8 :(得分:0)
array
指向realarray
起始地址之前的一个位置。然而,令我感到困惑的是为什么在没有任何警告的情况下进行编译。
答案 9 :(得分:0)
你只是指向阵列前面的4个字节。
答案 10 :(得分:0)
这是完全明确的定义。您的代码保证被所有编译器接受,并且永远不会在运行时崩溃。 C / C ++指针是一种符合算术规则的数字数据类型。加法和减法工作,括号表示法[]只是一种奇特的加法语法。 NULL实际上是整数0。
这就是C / C ++危险的原因。编译器将允许您创建指向任何地方的指针而无需投诉。 解除引用示例中的野生指针,*array = 1234;
会产生未定义的行为,从细微的损坏到崩溃。
是的,您可以使用它从1开始索引。不要这样做! C / C ++习语总是从0开始索引。其他看到代码索引从1开始的人会试图“修复”它从0开始索引。
答案 11 :(得分:0)
实验可以提供更多线索,如果是以下内容。而不是将指针值打印为
printf("%p\n", (void *)array);
,打印数组元素值
printf("%d\n", *array);
多数民众赞成因为打印带有%p的指针总会产生一些输出(没有任何不当行为),但是没有任何内容可以从中推断出来。