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

从C中的指针检索2D数组,c,pointers,multidimensional-array,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' 在堆栈溢出线程上 char (*p_arr2D)[m] = &arr2D //or arr2D 也是一种语法,用于衰减n*m2D数组arr2D,返回指向其第一个元素的指针,即m元素数组 p_arr[0]似乎是“反

我尝试了以下代码

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

    char (*p_arr2D)[m] = &arr2D //or arr2D
也是一种语法,用于衰减
n*m
2D数组
arr2D
,返回指向其第一个元素的指针,即
m
元素数组


p_arr[0]
似乎是“反向”数组衰减,从指向数组的指针检索2D数组。怎么会这样?在上面的代码片段中,
p_arr
是否被解释为
1*5
数组(从原始的具有5个元素的1D数组)?

首先,行
char(*p_arr)[1]=&arr不是有效的C。编译器必须给出诊断消息
p_arr
是指向1个字符数组的数组指针,但您将其指定给指向5个字符数组的指针

至于为什么看起来你有一个2D数组-你没有一个-是因为
p_arr[0]
的工作原理与任何其他指针算法一样,让你指向项“offset+0”。这就是数组。然后访问数组中的项目4

同样的指针算术原理的一个简单示例如下:

int a;
int* ptr = &a;
ptr[0] = whatever; // perfectly valid C
ptr[0]
保证等同于
*(ptr+0)


数组指针的正确用法应该是
printf(“%c\n”,(*p\u arr)[4])
。在本例中,它正好起作用,但在其他情况下,您可能会调用未定义的行为,因为
p\u arr
不允许指向分配的内存之外。

您将p\u 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]);
}
#包括
int main(){
char arr[]={“你好世界”};
char*p[3]={NULL,arr,NULL};
printf(“%s%c\n”,p[1],p[1][3]);
}

John

二维数组像一维数组一样存储在内存中

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

所以
printf(“%c\n”,p_arr[0][4])
打印第五个元素(U),因为by
p\U arr[0][4]
处理第1行中的第五个元素

printf(“%c\n”,p_arr[1][4])将给出一个错误

因此,该代码工作的原因是2D数组像1D数组一样存储在内存中

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;
然后表达式
*ptr
ptr[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_arr
p_arr[0]
产生
T
类型的引用对象,即
char[5]
类型

来自C标准(6.5.3.2地址和间接运算符)

4一元*运算符表示间接。如果操作数指向 函数,结果是函数指示符;如果它指向 对象,则结果是指定该对象的左值。如果 具有类型“”指向类型“”的指针,则结果具有类型“”类型“”。如果 为指针指定了无效值,该指针的行为 一元*运算符未定义

和(6.5.2.1阵列下标)

2后缀表达式后跟方括号[]中的表达式是数组对象元素的下标指定。下标运算符[]的定义是E1[E2]与(*(E1)+(E2)))相同。因为如果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]

My bad类型的元素,我把我原来的问题一分为二,忘了将
char(*p_arr)[1]=&arr;
更改为
char(*p_arr)[5]=&arr;
(*p_arr)[1]=&arr;
不会产生任何编译错误(请参阅my),我也不明白原因。(C编译器不会阻止您要执行的操作。)使用
-Wall
选项编译它。我对代码更改进行了回滚。请不要在答案发布后修复代码中的问题。通过修复它,您会使大多数答案变得无关紧要。相反,如果您有后续问题,请问一个新问题(就像您所做的那样)。糟糕的是,我将原始问题分成两半,忘了更改字符(*p_arr)[1]=&arr;到字符