C++ 指向数组第[-1]个索引的指针

C++ 指向数组第[-1]个索引的指针,c++,c,arrays,pointers,C++,C,Arrays,Pointers,指向数组第[-1]个索引的指针如何每次生成合法输出。指针赋值中实际发生了什么 #include<stdio.h> int main() { int realarray[10]; int *array = &realarray[-1]; printf("%p\n", (void *)array); return 0; } 编辑:如果此方案有效,那么我可以使用它定义一个索引从1开始而不是从0开始的数组,即:数组[

指向数组第[-1]个索引的指针如何每次生成合法输出。指针赋值中实际发生了什么

#include<stdio.h>
int main()
{
        int realarray[10];
        int *array = &realarray[-1];

        printf("%p\n", (void *)array);
        return 0;
}

编辑:如果此方案有效,那么我可以使用它定义一个索引从1开始而不是从0开始的数组,即:数组[1],数组[2],…

它只指向内存中数组前面的项地址


数组可以简单地看作是一个指针。然后简单地递减1。

您得到的只是一个指针,其中包含该“虚拟”位置的地址,即第一个元素
&realarray[0]
的位置减去一个元素的大小


例如,如果您的机器有一个分段内存体系结构,那么这可能会非常糟糕。它之所以能够工作,是因为编译器编写者选择了实现上述算法;这种情况随时可能发生变化,而另一个编译器的行为可能完全不同。

该行为未定义。


您所观察到的可能发生在特定的编译器和配置中,但任何事情都可能发生在不同的情况下。您根本无法依赖此行为。

array
指向
realarray
起始地址之前的一个位置。然而,让我困惑的是,为什么编译时没有任何警告。

行为未定义。您只能计算指向数组中任何元素的指针,或一个过去的指针,但仅此而已。只能取消引用指向数组中任何元素的指针(而不是过去的指针)。看看你的变量名,看起来你在问一个问题。我认为FAQ上的答案非常好

在这里,您只需执行指针算法,它将获得relarray的第一个索引地址

请参见,如果使用&relarray[+1],则将获得数组的第二个元素地址。自

&relarray[0]指向第一个索引地址


虽然,正如其他人所指出的,在这种情况下它是未定义的行为,但它编译时没有警告,因为通常,
foo[-1]
可能是有效的

例如,这很好:

int realarray[10] = { 10, 20, 30, 40 };
int *array = &realarray[2];

printf("%d\n", array[-1]);

a[b]
定义为
*(a+b)

因此
a[-1]
*(a-1)


<> > <代码> A-1 < /COD>是一个有效的指针,因此引用的有效性取决于代码使用的上下文。

< P>您指向的是数组前面的4个字节。

< P> C和C++,数组索引在运行时没有检查。您正在执行指针算术,它可能会给出定义的结果,也可能不会给出定义的结果(此处不提供)

<>但是,在C++中,您可以使用提供边界检查的数组类,例如:“代码> Boo::数组< /COD>或<代码> STD:::Tr1::数组< /C> >(将添加到C++ 0x的标准库):

#包括
#包括
int main()
{
试一试{
boost::数组realarray;
int*p=&realarray.at(-1);
printf(“%p\n”,(void*)p);
}捕获(const std::exception&e){
放置(例如what());
}
}
输出:

数组:索引超出范围

还会生成编译器警告:

8测试。cpp[警告]通过阴性 用于转换1的值
-0x000000001
of
T&boost::array::at(大小\u T) [T=int,无符号int N=10u]'


这是非常明确的定义。您的代码保证被所有编译器接受,并且在运行时不会崩溃C/C++指针是一种数字数据类型,遵循算术规则。加法和减法有效,括号符号[]只是加法的一种奇特语法。NULL实际上是整数0

这就是为什么C/C++是危险的。编译器将允许您创建指向任何位置的指针,而无需抱怨取消引用示例中的野生指针,
*array=1234将产生未定义的行为,从细微的损坏到崩溃


是的,您可以使用它从1索引。别这样!C/C++习惯用法是总是从0开始索引。看到代码从1开始索引的其他人可能会尝试将其“修复”为从0开始索引。

如果是以下情况,实验可能提供了更多的线索。而不是将指针值打印为

printf("%p\n", (void *)array);
,打印数组元素值

printf("%d\n", *array);

这是因为打印带有%p的指针总是会产生一些输出(没有任何错误行为),但无法从中推断出任何结果。

为什么gcc没有对这种类型的赋值发出任何警告?它应该对
int*p=realarray+5;int*q=p-6?在C语言中,必须进行边界检查。:-)@Manav:对于动态分配的数据,这些程序在返回数据之前和之后分配一些字节,并将它们设置为可预测的值。如果值更改,则表示程序正在写入不应该写入的位置。但是这种技术不适用于您的示例,因为您的示例没有动态分配,甚至没有写入数组的任何元素。哦,1索引数组作为一个重载运算符[]()的类是完全可行的。@SF。在C.,如果C++中的重载是好的,那么它是有争议的。虽然您的注释对于编译器/实现/配置是正确的,但是它并不是定义为总是如此。(参见Daniel的回答)是的,但问题是指针赋值中发生了什么,而不是应该发生什么;)正如一本教科书令人难忘地说,按照标准,它很有可能对怀特岛发动核攻击……有没有办法事先检查数组边界,特别是在使用指针算法时。虽然编译器在这个简单的场景中查找可能看起来微不足道,但一般来说并不简单。只需假设数组(作为指针)被传递到函数中,并且算法是在f中完成的
printf("%p\n", (void *)array);
printf("%d\n", *array);