从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),因为byp\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;到字符