微妙的指针和数组的概念

问题描述:

我有一个非常奇怪的指针示例,它需要你的帮助。一般来说,指针用于指向一个变量(见下面的第一个例子),但是当它指向一个数组时。我不明白为什么它不再需要推理来获得阵列(参见下面的第二个例子)微妙的指针和数组的概念

printf("TEST: %i\n", x[i]);// I expect this should be *x[i] 

这确实很奇怪。它只是一个C约定,或者你如何解释这个?正如所有人提到x [i] = *(x + i),那么x [i]是什么意思呢?关于x [i] [j]为2维数组?它相当于什么?它需要解引用吗?

与正常的可变

int j = 4; 
int* pointerj=&j;//pointerj holds address of j or points to j 
printf("%d",*pointerj); returns the value that pointer j points to 

随着阵列:

#include <stdio.h> 
#include <stdlib.h> 

int *function(unsigned int tags) { 
    int i; 
    int *var; 

    var = (int*)malloc(sizeof(int)*tags); // malloc is casted to int* type , allocated dynamical memory, it returns a pointer! 
    //so now var holds the address to a dynamical array. 

    for (i = 0; i < tags; i++) { 
     var[i] = i; 
    } 

    return var; 
} 

int main() { 
    int *x; 
    int i; 

    x = function(10); 
    for (i = 0; i < 10; i++) { 
     printf("TEST: %i\n", x[i]);// I expect this should be *x[i] 
    } 

    free(x); x = NULL; 

    return 0; 
} 
+0

'x [i]'相当于'*(x + i)'。所以实际上,这意味着可以将'* x'写为'x [0]'。 –

+0

你可能想检查[this](https://stackoverflow.com/questions/381542/with-arrays-why-is-it-the-case-that-a5-5a) – Badda

+0

@OliverCharlesworth哦!作为一名Python程序员,我被这个公约误导了!干杯 –

不明白为什么它没有。不再需要解引用,获得数组(元素)

嗯,你提领,它只是不使用dereferen ce运营商*

数组下标运算符[]在此处作为取消引用的工作。引用C11,章§6.5.2.1

后缀表达式后跟表达式在方括号[]是一个数组对象的元素的下标 指定。下标运算符[] 的定义是E1[E2](*((E1)+(E2)))相同。因为 应用于二进制+操作者,如果E1是一个数组对象(等同于一个指针数组对象的 初始元件),并E2是整数的转换规则的,E1[E2]指定的第E2元件 E1(从零开始计数)。

这是一个语法糖。表达式x[i]*(x+i)是等效的。后者满足您的期望,而第一个则掩饰了解除引用操作符,但完成了与您期望的完全相同的工作。


也就是说,也要紧跟数据类型。你所期望的,沿着*x[i]这条线的东西将是明显无效的,因为它归结为像'(x + i))。现在,

  • xint []型的(整数阵列,它衰减到一个指向整数)
  • x+i给你一个指针int类型的结果。
  • 将内部解除引用运算符应用于它,结果为int
  • *,现在将尝试在int类型的操作数(不是指针)操作,并且,这个操作将是一个语法错误,因为,引用操作约束表示,

一元运算符*的操作数应具有指针类型。

in C11,chapter§6.5.3.2。


回答了另一个问题

让我用报价,再一次,这一次的从第2款,章§6.5.2.1

连续下标运算符指定的元素多维数组对象。 如果En维阵列(n ≥ 2)与尺寸i × j × . . . × k,然后E(用作 比左值除外)被转换为一个指向(n − 1)维阵列 尺寸j × . . . × k。如果明确地将一元运算符*应用于此指针,或者由于下标而隐式地应用 ,则结果为引用的(n − 1)维数组,其本身在被用作非左值的情况下转换为指针。它遵循 从这个数组存储行主要顺序(最后下标变化最快)。

考虑由该声明定义的阵列对象

int x[3][5]; 

这里x3 × 5阵列的int秒;更准确地说,x是一个由三个元素对象组成的数组,其中每个元素都是一个由5个整数组成的 数组。在相当于(*((x)+(i)))的表达式x[i]中,x首先被转换为 指向五个整数的初始数组的指针。然后i根据x的类型进行调整,其在概念上 需要将指针指向的对象的大小乘以i,即,对象的五个对象的数组。结果被添加并且间接被应用以产生五个整数的数组。当在 表达式x[i][j]中使用时,该阵列又被转换为指向第一个整数的指针,所以x[i][j] 产生int

+0

非常抱歉,您能否以简单的语言解释这部分内容?从第一个开始,x首先被转换为一个指向5个整数的初始数组的指针。我迷路了.. –

+0

@elpsyCongroo我一定会尝试,请允许我一些时间,我现在有点被占用了,我会回来一个非正式的解释。这就说得通了? –

这是确定。不在这里。

如果有指针int *a指向有效数据的阵列,例如:

int *a; 
int arr[5] = {1, 2, 3, 4, 5]; 
a = arr; 

通过使用a[0]您已经解除引用指针和*作为a[0]相同*(a + 0)不是必需的。


您可以为读者进一步甚至更复杂的代码。

您可以使用i[x]代替x[i]。为什么? x[i]等于*(x + i)但也相当于*(i + x)这正是数组是C.

它的工作原理,即使号码,如x[3]3[x]会给你同样的结果。

在C中,x [i]在i [x]上是等价的(是的,我知道)。你的编译器通过这样做来编译:

*(x + i),在这里你可以找到你喜欢的符号。

x +我是一个指针,你从x开始,由i前进。结果考虑到了指针的类型(0xff与char *不同,而不是int *)。

+0

这是什么:*是的,我知道*? – tilz0R

+0

只是为了表明,做我[x]很奇怪,但有效。 – Gaulois94

+0

@ Gaulois94对不起,我[x]是什么意思?它现在混淆了我..如何索引超出数组?我是数组元素的索引,对吗? –

你误会了数组的工作方式。事实上,使用一个变量,例如int时,你应该访问的地址通过

int x; int *p2x = &x

但使用数组时,这是一个有点不同。 int y[SOME_SIZE];是内存中的一大块字节,并且*y会将您带到该内存位置中的第一个元素,并将其解引用。 y[0]也会这样做。 *y[0]将首先采用y[0]中的值,然后尝试对其进行解引用...不是你平时想什么:(

简单回答你的问题是:

数组的名称是指向数组的第一个元素

+1

不是真的,你没有解释什么,只是一个经验法则...... –

+1

@elpsyCongroo肯定是真的。如果直接使用变量,则使用指向第一个元素的指针。 – tilz0R

+0

在尝试回答更多问题之前,请阅读[如何编写好的答案?](http://stackoverflow.com/help/how-to-answer)。 –