C指针数组和数组指针

article/2025/9/22 3:14:57

一、指针数组和数组指针的内存布局

初学者总是分不出指针数组与数组指针的区别。其实很好理解:
指针数组:首先它是一个数组,数组的元素都是指针,数组占多少个字节由数组本身决定。它是“储存指针的数组”的简称。
数组指针:首先它是一个指针,它指向一个数组。在32 位系统下永远是占4 个字节,至于它指向的数组占多少字节,不知道。它是“指向数组的指针”的简称。


下面到底哪个是数组指针,哪个是指针数组呢:
A)
int *p1[10];
B)
int (*p2)[10];
每次上课问这个问题,总有弄不清楚的。这里需要明白一个符号之间的优先级问题。

“[]”的优先级比“*”要高。p1 先与“[]”结合,构成一个数组的定义,数组名为p1,int *修饰的是数组的内容,即数组的每个元素。那现在我们清楚,这是一个数组,其包含10 个指向int 类型数据的指针,即指针数组。至于p2 就更好理解了,在这里“()”的优先级比“[]”高,“*”号和p2 构成一个指针的定义,指针变量名为p2,int 修饰的是数组的内容,即数组的每个元素。数组在这里并没有名字,是个匿名数组。那现在我们清楚p2 是一个指针,它指向一个包含10 个int 类型数据的数组,即数组指针。我们可以借助下面的图加深理解:

二、int (*)[10] p2-----也许应该这么定义数组指针

这里有个有意思的话题值得探讨一下:平时我们定义指针不都是在数据类型后面加上指针变量名么?这个指针p2 的定义怎么不是按照这个语法来定义的呢?也许我们应该这样来定义p2:
   int (*)[10] p2;
int (*)[10]是指针类型,p2 是指针变量。这样看起来的确不错,不过就是样子有些别扭。其实数组指针的原型确实就是这样子的,只不过为了方便与好看把指针变量p2 前移了而已。你私下完全可以这么理解这点。虽然编译器不这么想。^_^

三、再论a 和&a 之间的区别

既然这样,那问题就来了。前面我们讲过a 和&a 之间的区别,现在再来看看下面的代码:
int main()
{
   char a[5]={'A','B','C','D'};
   char (*p3)[5] = &a;
   char (*p4)[5] = a;
   return 0;
}
上面对p3 和p4 的使用,哪个正确呢?p3+1 的值会是什么?p4+1 的值又会是什么?毫无疑问,p3 和p4 都是数组指针,指向的是整个数组。&a 是整个数组的首地址,a是数组首元素的首地址,其值相同但意义不同。在C 语言里,赋值符号“=”号两边的数据类型必须是相同的,如果不同需要显示或隐式的类型转换。p3 这个定义的“=”号两边的数据类型完全一致,而p4 这个定义的“=”号两边的数据类型就不一致了。左边的类型是指向整个数组的指针,右边的数据类型是指向单个字符的指针。在Visual C++6.0 上给出如下警告:
   warning C4047: 'initializing' : 'char (*)[5]' differs in levels of indirection from 'char *'。
还好,这里虽然给出了警告,但由于&a 和a 的值一样,而变量作为右值时编译器只是取变量的值,所以运行并没有什么问题。不过我仍然警告你别这么用。

既然现在清楚了p3 和p4 都是指向整个数组的,那p3+1 和p4+1 的值就很好理解了。

但是如果修改一下代码,会有什么问题?p3+1 和p4+1 的值又是多少呢?
int main()
{
   char a[5]={'A','B','C','D'};
   char (*p3)[3] = &a;
   char (*p4)[3] = a;
   return 0;
}

甚至还可以把代码再修改:
int main()
{
   char a[5]={'A','B','C','D'};
   char (*p3)[10] = &a;
   char (*p4)[10] = a;
   return 0;
}
这个时候又会有什么样的问题?p3+1 和p4+1 的值又是多少?

上述几个问题,希望读者能仔细考虑考虑。

四、地址的强制转换

先看下面这个例子:
struct Test
{
   int Num;
   char *pcName;
   short sDate;
   char cha[2];
   short sBa[4];
}*p;

假设p 的值为0x100000。如下表表达式的值分别为多少?
   p + 0x1 = 0x___ ?
   (unsigned long)p + 0x1 = 0x___?
   (unsigned int*)p + 0x1 = 0x___?
我相信会有很多人一开始没看明白这个问题是什么意思。其实我们再仔细看看,这个知识点似曾相识。一个指针变量与一个整数相加减,到底该怎么解析呢?

还记得前面我们的表达式“a+1”与“&a+1”之间的区别吗?其实这里也一样。指针变量与一个整数相加减并不是用指针变量里的地址直接加减这个整数。这个整数的单位不是byte 而是元素的个数。所以:p + 0x1 的值为0x100000+sizof(Test)*0x1。至于此结构体的大小为20byte,前面的章节已经详细讲解过。所以p +0x1 的值为:0x100014。

(unsigned long)p + 0x1 的值呢?这里涉及到强制转换,将指针变量p 保存的值强制转换成无符号的长整型数。任何数值一旦被强制转换,其类型就改变了。所以这个表达式其实就是一个无符号的长整型数加上另一个整数。所以其值为:0x100001。

(unsigned int*)p + 0x1 的值呢?这里的p 被强制转换成一个指向无符号整型的指针。所以其值为:0x100000+sizof(unsigned int)*0x1,等于0x100004。

上面这个问题似乎还没啥技术含量,下面就来个有技术含量的:在x86 系统下,其值为多少?
intmain()
{
   int a[4]={1,2,3,4};
   int *ptr1=(int *)(&a+1);
   int *ptr2=(int *)((int)a+1);
   printf("%x,%x",ptr1[-1],*ptr2);
   return 0;
}
这是我讲课时一个学生问我的题,他在网上看到的,据说难倒了n 个人。我看题之后告诉他,这些人肯定不懂汇编,一个懂汇编的人,这种题实在是小case。下面就来分析分析这个问题:

根据上面的讲解,&a+1 与a+1 的区别已经清楚。

ptr1:将&a+1 的值强制转换成int*类型,赋值给int* 类型的变量ptr,ptr1 肯定指到数组a 的下一个int 类型数据了。ptr1[-1]被解析成*(ptr1-1),即ptr1 往后退4 个byte。所以其值为0x4。
ptr2:按照上面的讲解,(int)a+1 的值是元素a[0]的第二个字节的地址。然后把这个地址强制转换成int*类型的值赋给ptr2,也就是说*ptr2 的值应该为元素a[0]的第二个字节开始的连续4 个byte 的内容。

其内存布局如下图:
好,问题就来了,这连续4 个byte 里到底存了什么东西呢?也就是说元素a[0],a[1]里面的值到底怎么存储的。这就涉及到系统的大小端模式了,如果懂汇编的话,这根本就不是问题。既然不知道当前系统是什么模式,那就得想办法测试。大小端模式与测试的方法在第一章讲解union 关键字时已经详细讨论过了,请翻到彼处参看,这里就不再详述。我们可以用下面这个函数来测试当前系统的模式。
int checkSystem( )
{
   union check
   {
      int i;
     char ch;
   } c;
   c.i = 1;
   return (c.ch ==1);
}

如果当前系统为大端模式这个函数返回0;如果为小端模式,函数返回1。也就是说如果此函数的返回值为1 的话,*ptr2 的值为0x2000000。如果此函数的返回值为0 的话,*ptr2 的值为0x100。

补充1:


补充2:





http://chatgpt.dhexx.cn/article/sLymNdeI.shtml

相关文章

c++数组指针和指针数组详解

指针数组: 指针数组可以说成是”指针的数组”,首先这个变量是一个数组,其次,”指针”修饰这个数组,意思是说这个数组的所有元素都是指针类型,在32位系统中,指针占四个字节。 数组指针&#xf…

C语言指针数组

一、指针数组概念回顾: 一个数组,其元素均为指针类型数据,称为指针数组。即:指针数组中每一个元素都是指针变量。 指针数组的定义格式: 类型标识符 *数组名(数字长度说明); 如: int *p[4]; //每个数组元素都可以看…

指针数组概念

一个数组,其元素均为指针类型数据,称为指针数组。 即:指针数组中每一个元素都是指针变量。 指针数组的定义格式: 类型标识符 *数组名(数字长度说明); 如: int *p[4]; //每个数组元素都可以看成是一个指针变量,都可…

数组指针与指针数组

一、数组指针 数组指针,即是指向数组的指针,数组指针中存放的应该是数组的地址。 1. 数组名的区分 数组名:数组名就是数组的最大存储单元的首地址,指向第一个元素,所以数组名的类型为元素类型的指针 &数组名[0]&…

c++指针数组(入门)

指针数组的本质是数组,只是每个数组的元素为指针 32位平台: char*arr1[4]; int *arr2[4]; short *arr3[4];sizeof(arr1)168; sizeof(arr2)168; sizeof(arr3)168; 8.4.1 数值的指针数组 int *arr[4]; 指针数组 int *arr[4]{&num1,&num2,&…

指针数组、数组指针、数组的区别与联系

指针数组、数组指针、数组的区别与联系! 一:基本定义 1.指针数组 char *arr[4] {"hello", "world", "shannxi", "xian"}; //arr就是我定义的一个指针数组,它有四个元素,每个元素是一…

指针数组的用法

指针数组 1、学习目标 掌握指针数组的用法总结与思考 2、指针数组 所谓指针数组是指由若干个具有相同存储类型和数据类型的指针变量构成的集合。 指针数组的一般说明形式&#xff1a; <存储类型> <数据类型> *<指针数组名> [<大小>]指针数组名表示…

数组指针 和 指针数组 的区别

目录 0. 引言1. 数组指针2. 指针数组3. 小结 本文使用运行环境如下&#xff1a; 操作系统&#xff1a;Ubuntu Linux 18.04 64 bit 编译环境&#xff1a;gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04) 0. 引言 数组指针和指针数组且听之类似&#xff0c;实际完全不同。数组…

C语言(函数指针数组)详解

要了解函数指针数组&#xff0c;可以从三个角度来分析。所谓函数指针数组&#xff0c;从字面意思上来解析&#xff0c;函数指针数组的组成有三个点&#xff0c;函数&#xff0c;指针&#xff0c;数组。首先我们知道&#xff0c;函数指针数组&#xff0c;是一个数组&#xff0c;…

c语言 指针数组

文章目录 前言一、指针数组的定义声明,赋值&#xff1a;二、指针数组的应用&#xff1a;总结 前言 今天我们讲解一下什么是指针数组。 一、指针数组的定义声明,赋值&#xff1a; 什么是指针数组呢&#xff1f; 指针数组 &#xff1a;就是首先定义一个数组&#xff0c;数组里面…

c语言之——指针数组与数组指针

一、指针数组和数组指针的定义 1. 指针数组&#xff1a;是指一个数组里面装着指针&#xff0c;也即指针数组是一个数组&#xff1b; 定义形式&#xff1a;int *a[10]&#xff1b; 说明&#xff1a;[]的优先级高于*&#xff0c;该定义形式应该理解为&#xff1a;int * (a[10]…

关于指针数组与数组指针详解(知识点全面)

1.目录 1.指针数组 2.数组指针 2.它们的区别 1.指针数组 如果一个数组中的所有元素保存的都是指针&#xff0c;那么我们就称它为指针数组。其一般形式为&#xff1a; 数据类型 *数组名[常量表达式][常量表达式]...... ; 它是一个数组&#xff0c;数组的元素都是指针&…

指针数组(指针类型的数组)

顾名思义&#xff1a;指针类型的数组&#xff0c;首先是一个数组&#xff0c;数组元素存储的是指针。(中国的修饰词往往都在前面&#xff0c;而西方修饰词往往是放在后面) 语法如下&#xff1a; 目标类型 数组名称[元素个数] 如&#xff1a;int * p[3] 数组p有3个元素&#x…

数组指针和指针数组的区别

文章目录 前言 一、什么是指针数组&#xff1f; 1.定义 2.声明 3.指针数组的内存示意图 二、什么是数组指针&#xff1f; 1.定义 2.声明 3.内存示意图 三、如何区别指针数组和数组指针&#xff1f; 四、实践理解 总结 前言 这几天老师有问到指针数组和数组指针的区别&#xff…

C语言—指针数组与数组指针

前言&#xff1a; 看到标题的小伙伴可能会有点疑惑&#xff0c;什么是指针数组&#xff0c;数组指针&#xff1f;&#xff1f;傻傻分不清楚&#xff0c;不怕&#xff0c;听我慢慢道来。 正文&#xff1a; 要想弄清楚这两个概念&#xff0c;我们不妨举几个例子&#xff1a; …

指针数组和数组指针的区别及其详解

引言 对于指针数组和数组指针的概念&#xff0c;相信很多人经常会感到迷惑&#xff0c;见到二者一时不能分辨究竟对应哪一个才是对的。接下来我们来分析一下二者区别。 我们来看一下这个示例代码&#xff1a; int *ptr1[10]; int (*ptr2)[10];对于上述代码语句&#xff0c;你…

C语言学习—数组指针和指针数组的区别

前言 本文章对指针数组和数组指针的区别进行了分析介绍 一、数组指针和指针数组的定义 1.数组指针&#xff1a;定义 int (*p)[n]; 由于()的优先级高&#xff0c;首先说明p是一个int类型指针&#xff0c;它是指向一个整型(int)的一维数组&#xff0c;这个一维数组的长度是n&a…

指针数组和数组指针

1.什么是指针数组和数组指针 顾名思义&#xff1a;指针数组是“存放指针的数组”&#xff0c;这个变量是一个数组&#xff0c;用指针修饰&#xff0c;数组中的每个元素都是指针。 数组指针是“指向数组的指针”&#xff0c;这个变量是一个指针&#xff0c;用数组修饰&#xf…

指针数组和数组指针(非常易懂)

指针数组与数组指针 目录&#xff1a; 1.指针与一维数组 2.指针与二维数组 3.指针数组与数组指针 1.指针与一维数组 当定义一个一维数组时&#xff0c;系统会在内存中为改数组分配一个储存空间&#xff0c;其数组的变量名就是数组的首地址。若定义一个指针变量&#xff0c;并…

数组指针和指针数组

首先&#xff0c;理解一下数组指针和指针数组这两个名词&#xff1a; “数组指针”和“指针数组”&#xff0c;只要在名词中间加上“的”字&#xff0c;就知道中心了—— 数组的指针&#xff1a;是一个指针&#xff0c;什么样的指针呢&#xff1f;指向数组的指针。 指针的数…