从C中的指针检索2D数组

时间:2017-10-11 10:33:00

标签: c pointers multidimensional-array

我尝试了以下代码

    char arr[5] = {'A', 'E', 'I', 'O', 'U'};
    char (*p_arr)[1] = &arr;
    printf("%c\n", p_arr[0][4]); //returns 'U'

this stackoverflow线程上,

    char (*p_arr2D)[m] = &arr2D //or arr2D

也是n*m 2D数组arr2D衰减的语法,返回指向其第一个元素的指针,即m个元素的数组。

p_arr[0]似乎是“反向”数组衰减,从指向数组的指针中检索2D数组。怎么会发生这种情况?在上面的代码段中,p_arr被解释为1*5数组(来自原始的1D数组,包含5个元素)?

4 个答案:

答案 0 :(得分:1)

首先,行char (*p_arr)[1] = &arr;无效C.您的编译器必须提供诊断消息。 p_arr是指向1个char的数组的数组指针,但是您将其指定为指向5个char的数组。

至于为什么看起来你有一个2D数组 - 你有一个 - 是因为p_arr[0]的工作方式与任何其他指针算法一样,给你指向的项目“偏移+ 0“。哪个是阵列。然后访问数组中的第4项。

同一指针算术原理的一个简单例子是:

int a;
int* ptr = &a;
ptr[0] = whatever; // perfectly valid C

ptr[0]保证等同于*(ptr+0)

正确使用数组指针应为printf("%c\n", (*p_arr)[4])。在这种情况下,它恰好工作,但在其他情况下,您可能会调用未定义的行为,因为p_arr不允许指向超出分配的内存。

答案 1 :(得分:1)

2D数组像1D数组https://www.ibm.com/support/knowledgecenter/en/SSEQTP_liberty/com.ibm.websphere.wlp.doc/ae/cwlp_sharedlibrary.html

一样存储在内存中

char (*p_arr)[1] = &arr;创建一个指向char指针数组的指针,指针包含一个元素((*p_arr)[1]),并通过赋值&arr指针获取已存在的地址包含5个元素的数组

所以printf("%c\n", p_arr[0][4]);打印第5个元素(U),因为p_arr[0][4]通过第1行的第5个元素

printf("%c\n", p_arr[1][4]);会出错

所以这段代码的工作原理是2D数组像1D数组一样存储在内存中

答案 2 :(得分:1)

此声明

char (*p_arr)[1] = &arr;

不正确,因为声明的指针和初始化程序具有不兼容的类型。没有从类型char ( * )[5](初始值设定项的类型)到类型char ( * )[1]的隐式转换,即已声明指针的ty [e]。因此,您需要显式转换以将一种类型的指针重新解释为另一种类型的指针,例如

char (*p_arr)[1] = ( char ( * )[1] )&arr;

至于你的问题,那么如果你有T类型的对象,其中T是某种类型

T obj;

和指向对象的指针,如

T *ptr = &obj;

然后表达式*ptrptr[0]产生T类型的引用对象。

因此,我们假设您有以下声明

char arr[5] = {'A', 'E', 'I', 'O', 'U'};
char (*p_arr)[5] = &arr;

对于作为变量char[5]类型的类型arr,您可以引入typedef名称。

typedef char T[5];

然后声明看起来像

T arr = {'A', 'E', 'I', 'O', 'U'};
T *p_arr = &arr;

正如上面提到的,表达式*p_arrp_arr[0]产生T类型的引用对象,其类型为char[5]

来自C标准(6.5.3.2地址和间接操作符)

  

4一元*运算符表示间接。如果操作数指向a   功能,结果是功能指示符;如果它指向一个   对象,结果是指定对象的左值。如果是操作数   有类型''指向类型'',结果类型''类型''。如果   无效值已分配给指针,行为   unary *运算符未定义。

和(6.5.2.1数组下标)

2后缀表达式后跟方括号[]中的表达式是数组对象元素的下标名称。 下标operator []的定义是E1 [E2]与(*((E1)+(E2)))相同。由于适用于binary +运算符的转换规则,如果E1是数组对象(等效地,指向数组对象的初始元素的指针)并且E2是整数,则E1 [E2]指定E1的第E2个元素(从零开始计数)。

最后(6.5.6添加运算符)

  

7出于这些运算符的目的,指向对象的指针   不是数组的元素行为与指向的指针相同   长度为1的数组的第一个元素,对象的类型为   其元素类型

所以在这个宣言中

char arr[5] = {'A', 'E', 'I', 'O', 'U'};
char (*p_arr)[5] = &arr;

指针p_arr未指向数组元素。但是它可以表现为它指向长度为1的数组的第一个元素。您可以通过以下方式想象它

char arr[1][5] = { {'A', 'E', 'I', 'O', 'U'} };
char (*p_arr)[5] = arr;

因此表达式p_arr[0]给出了想象的二维数组的第一个元素,它是char[5]类型的元素。

答案 3 :(得分:0)

您声明p_arr是指向字符数组的指针(该数组长度为1,这是问题的确定标志)。

您可能需要更简单的语法:

char *p_arr = arr;

或者也许:

#include <stdio.h>

int main() {
    char arr[] = {"Hello world"};
    char *p[3] = {NULL, arr, NULL};

    printf("%s %c\n", p[1], p[1][3]);
}

约翰