const数组 - pointer array c++




对于数组,为什么会出现[5]== 5[a]? (12)

正如Joel在Stack Overflow podcast#34中指出的那样,在C编程语言 (又名:K&R)中,提到了C: a[5] == 5[a]

乔尔说这是因为指针算术,但我仍然不明白。 为什么a[5] == 5[a]


C标准定义[]运算符如下:

a[b] == *(a + b)

因此a[5]将评估为:

*(a + 5)

5[a]将评估为:

*(5 + a)

a是指向数组的第一个元素的指针。 a[5]是距a更远的5个元素的值,与*(a + 5) ,并且从小学数学我们知道这些数学是相等的(加法是commutative )。


不是一个答案,而只是一些思考的食物。 如果类有重载的索引/下标操作符,则表达式0[x]将不起作用:

class Sub
{
public:
    int operator [](size_t nIndex)
    {
        return 0;
    }   
};

int main()
{
    Sub s;
    s[0];
    0[s]; // ERROR 
}

由于我们无法访问int类,因此无法完成此操作:

class int
{
   int operator[](const Sub&);
};

因为数组访问是根据指针定义的。 a[i]被定义为意味着*(a + i) ,它是可交换的。


C数组中arr[3]3[arr]是相同的,它们的等价指针符号是*(arr + 3)*(3 + arr) 。 但相反, [arr]3[3]arr不正确,会导致语法错误,因为(arr + 3)*(3 + arr)*不是有效的表达式。 原因是解引用运算符应放置在由表达式产生的地址之前,而不是在地址之后。


在C语言中, 指针和数组非常接近,可以用pointer的形式分割数组。 数组的名称是指向其第一个元素的指针。 所以如果acData是一个字符数组,那么“acData”将是它的第一个元素的地址。 你也可以说“acData”类似于&acData [0]。

根据C标准,我们可以用指针的形式表示一维数组。

看下面的表达式,

acData [i] = *(acData + i); --------->指针形式的1D数组

所以如果我= 5;

cData [5] = *(acData +5);

我们也可以用下面的形式表示表达式,

cData [5] = *(5 + acData);

所以现在,我们可以写

cData [5] = 5 [cData];

看下面的代码,

#include <stdio.h>

int main(int argc, char *argv[]) {

 char cData  [] = {'w', 'o', 'r', 'l' ,'d' }; // character array

 int index = 0;

 for(index = 0; index < sizeof(cData ); ++index)
 {
     printf("Array element access by pointer = %c\n\n",cData[index]);

     printf("Array element access by   array = %c\n\n",index[cData]);
 }


    return 0;
}

参考资料, https://aticleworld.com/array-in-c/


在c编译器中

a[i]
i[a]
*(a+i)

是不同的方式来引用数组中的元素! (不在所有WEIRD)


对于C中的指针,我们有

a[5] == *(a + 5)

并且

5[a] == *(5 + a)

因此,确实a[5] == 5[a].


很好的问题/答案。

只是想指出C指针和数组是不一样的 ,尽管在这种情况下差异并不重要。

考虑以下声明:

int a[10];
int* p = a;

a.out中 ,符号a位于数组开头的地址处,符号p位于存储指针的地址处,并且该存储位置处的指针值是数组的开始处。


我知道这个问题已经得到解答,但我无法拒绝分享这个解释。

我记得编译器设计的原理,我们假设a是一个int数组, int大小是2个字节, a基地址是1000。

a[5]如何工作 - >

Base Address of your Array a + (5*size of(data type for array a))
i.e. 1000 + (5*2) = 1010

所以,

同样,当c代码分解为3地址代码时, 5[a]将变为 - >

Base Address of your Array a + (size of(data type for array a)*5)
i.e. 1000 + (2*5) = 1010 

所以基本上这两个陈述都指向了记忆中的相同位置,因此, a[5] = 5[a]

这个解释也是为什么数组中的负指数在C中工作的原因。

即如果我访问a[-5]它会给我

Base Address of your Array a + (-5 * size of(data type for array a))
i.e. 1000 + (-5*2) = 990

它会在990处返回对象。


我认为其他答案错过了某些东西。

是的, p[i]在定义上相当于*(p+i) ,它(因为加法是可交换的)相当于*(i+p) ,它(同样是由[]运算符定义的)是等价的到i[p]

(在array[i] ,数组名称被隐式转换为指向数组第一个元素的指针。)

但是在这种情况下加法的交换性并不是那么明显。

当两个操作数具有相同类型时,或者甚至是提升为常见类型的不同数值类型时,交换性都非常合理: x + y == y + x

但在这种情况下,我们正在专门讨论指针算术,其中一个操作数是指针,另一个是整数。 (整数+整数是不同的操作,而指针+指针是无稽之谈。)

C标准对+运营商的描述( N1570 6.5.6)说:

另外,两个操作数都应该有算术类型,或者一个操作数应该是一个指向完整对象类型的指针,另一个应该是整数类型。

它可以很容易地说:

另外,两个操作数都应具有算术类型,或者操作数应该是指向完整对象类型的指针, 右操作数应该具有整数类型。

在这种情况下, i + pi[p]都是非法的。

用C ++术语来说,我们确实有两套重载的+运算符,可以粗略地描述为:

pointer operator+(pointer p, integer i);

pointer operator+(integer i, pointer p);

其中只有第一个是真正必要的。

那么为什么这样呢?

C ++继承了C语言中的这个定义,它从B获得(数组索引的交换性在1972年的用户参考文献中明确提到),它从BCPL (1967年的手册)中得到它,它很可能已经从较早的语言(CPL?Algol?)。

因此,数组索引是以加法的形式定义的,而且,即使是指针和整数,也是可交换的,可以追溯到C的祖先语言几十年。

这些语言的类型比现代C语言的类型弱得多。 特别是,指针和整数之间的区别经常被忽略。 (早期的C程序员有时在将unsigned关键字添加到语言之前使用指针作为无符号整数)。因此,由于操作数具有不同类型而使得添加不可交换,所以这些语言的设计者可能不会出现这种想法。 如果用户想要添加两个“东西”,无论这些“东西”是整数,指针还是别的东西,它都不符合该语言来防止它。

多年来,任何对该规则的改变都会破坏现有的代码(虽然1989年的ANSI C标准可能是一个很好的机会)。

将C和/或C ++更改为需要将指针放在左侧并且右侧的整数可能会破坏一些现有代码,但不会损失真正的表现力。

所以现在我们有arr[3]3[arr]意思完全一样的东西,尽管后一种形式不应该出现在IOCCC之外。


而且当然

 ("ABCD"[2] == 2["ABCD"]) && (2["ABCD"] == 'C') && ("ABCD"[2] == 'C')

主要原因是在70年代C设计时,计算机没有太多的内存(64KB很多),所以C编译器没有做太多的语法检查。 因此,“ X[Y] ”被相当盲目地翻译成“ *(X+Y)

这也解释了“ += ”和“ ++ ”语法。 “ A = B + C ”形式的所有内容都具有相同的编译形式。 但是,如果B与A相同,则可以实现装配级别优化。 但是编译器不够明白,所以开发人员必须( A += C )。 同样,如果C1 ,则可以获得不同的汇编级别优化,并且开发人员必须再次明确说明,因为编译器不会识别它。 (最近编译器也这样做,因此这些语法在很大程度上是不必要的)


那么,这是一个功能,因为语言支持才有可能。

编译器a[i]解释为*(a+i) ,并将表达式5[a]评估为*(5+a) 。 由于加法是可交换的,所以两者相等。 因此表达式评估为true







pointer-arithmetic