转自:https://www.cnblogs.com/mq0036/p/3382732.html

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

数组指针(也称行指针)
定义 int (*p)[n];
()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。

如要将二维数组赋给一指针,应这样赋值:
int a[3][4];
int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组。
 p=a;        //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0]
 p++;       //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][]

所以数组指针也称指向一维数组的指针,亦称行指针。

指针数组
定义 int *p[n];
[]优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组,它有n个指针类型的数组元素。这里执行p+1时,则p指向下一个数组元素,这样赋值是错误的:p=a;因为p是个不可知的表示,只存在p[0]、p[1]、p[2]...p[n-1],而且它们分别是指针变量可以用来存放变量地址。但可以这样 *p=a; 这里*p表示指针数组第一个元素的值,a的首地址的值。
如要将二维数组赋给一指针数组:
int *p[3];
int a[3][4];
p++; //该语句表示p数组指向下一个数组元素。注:此数组每一个元素都是一个指针
for(i=0;i<3;i++)
p[i]=a[i]
这里int *p[3] 表示一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2]
所以要分别赋值。

这样两者的区别就豁然开朗了,数组指针只是一个指针变量,似乎是C语言里专门用来指向二维数组的,它占有内存中一个指针的存储空间。指针数组是多个指针变量,以数组形式存在内存当中,占有多个指针的存储空间。
还需要说明的一点就是,同时用来指向二维数组时,其引用和用数组名引用都是一样的。
比如要表示数组中i行j列一个元素:
*(p[i]+j)、*(*(p+i)+j)、(*(p+i))[j]、p[i][j]

优先级:()>[]>*

出处:http://www.cnblogs.com/hongcha717/archive/2010/10/24/1859780.html

=========================================================================

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

初学者总是分不出指针数组与数组指针的区别。其实很好理解:
指针数组:首先它是一个数组,数组的元素都是指针,数组占多少个字节由数组本身的大小决定,每一个元素都是一个指针,在32 位系统下任何类型的指针永远是占4 个字节。它是“储存指针的数组”的简称。
数组指针:首先它是一个指针,它指向一个数组。在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 的值又是多少?

上述几个问题,希望读者能仔细考虑考虑,并且上机测试看看结果。

测试结果:
(1).char (*p2)[5]=a;必须使用强制转换,如:char (*p2)[5]=(char (*)[5])a;
(2).把数组大小改变,都会编译不通过,提示:
error C2440: 'initializing' : cannot convert from 'char (*)[5]' to 'char (*)[3]'
error C2440: 'initializing' : cannot convert from 'char (*)[5]' to 'char (*)[10]'

(3).把以上程序测试代码如下:
int main()
{
   char a[5]={'a','b','c','d'};
   char (*p1)[5]= &a;
   char (*p2)[5]=(char (*)[5])a;

printf("a=%d\n",a);
   printf("a=%c\n",a[0]);
   printf("p1=%c\n",**p1);
   printf("p2=%c\n",**p2);
   printf("p1+1=%c\n",**(p1+1));
   printf("p2+1=%c\n",**(p2+1));

return 0;
}

输出:
a=1638208
a=a
p1=a
p2=a
p1+1=?
p2+1=?
Press any key to continue

结论:
根据指针类型及所指对象,表示指针大小,每次加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);//指向a数组后面的内存单元,&a+1表示向后移16个存储单元
   int *ptr2=(int *)((int)a+1);//表示a的存储单元的地址增加一个字节
   printf("%x,%x",ptr1[-1],*ptr2);//ptr1[-1]其实指向的是a数组的最后一个单元,*ptr1则表示a数组的地址后移一个字节之后的4个连续存储单元所存储的值
   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。
}

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

转载于:https://www.cnblogs.com/do-your-best/p/11140491.html

【转】数组指针指针数组相关推荐

  1. C++ 笔记(27)— 指针变量、数组和指针、指针数组、数组指针、指针常量与常量指针

    1. 什么是指针变量? 指针变量是专门有一个变量来存放指针. int main(int argc, char *argv[]) {int a = 10;int *p = &a; //通过取地址 ...

  2. C++二维数组名与数组指针的思考

    二维数组名和数组指针可以当做一个东西用,但两者之间的含义是不同的. 二维数组名是一个指向数组中所有元素的指针,而数组指针是一个行指针.体现在sizeof()上的不同. #include <ios ...

  3. C语言下标要求数组或指针,c语言改错 error C2109: 下标要求数组或指针类型怎么改?...

    /*魔方阵*/ #include int main() { int i,j,a,n; int arr[100][100]; printf("请输入n,n为100内奇数\n"); s ...

  4. c++ char数组初始化_c专题指针数组与指针的关联

    ----在今天开始写文章之前,让我不由的想起高中里面学的一篇文章中一段话语,是荀子写的<劝学>:积土成山,风雨兴焉:积水成渊,蛟龙生焉:积善成德,而神明自得,圣心备焉.故不积跬步,无以至千 ...

  5. C指针9:指针数组(即数组中的每个元素都是指针)

    前边已经讲过数组指针,强调的是指针,意思就是该指针指向的是数组(数组里边的元素一般为普通数据). 指针数组,强调的是数组,意思就是该数组里边的每个元素都是指针类型.即如果一个数组中的所有元素保存的都是 ...

  6. C指针4:数组指针(指向数组的指针)

    先明确两个概念:(1和2是两个完全不一样的东西) 1.数组指针:如果一个指针指向了数组(该数组就是普通定义的数组),我们就称它为数组指针(Array Pointer).(1强调的是指针) 2.指针数组 ...

  7. 多维数组与指针之间的关系详解

    先介绍一下简单的一维数组: 列如: int a[3] = {0,1,2}; [3]和类型int则明确表示编译器应该为这个栈分配多大的内存,也就是三个int大小! 在内存中示意图是: 在CPU看来内存是 ...

  8. char *a 和char a[] 的区别(指针和数组的区别)

    2019独角兽企业重金招聘Python工程师标准>>> 在C/C++中,指针和数组在很多地方可以互换使用,这使得我们产生一种错觉,感觉数组和指针两者是完全等价的,事实上数组和指针是有 ...

  9. 用指针查找数组中温度值为32的天数

    <程序设计基础实训指导教程-c语言> ISBN 978-7-03-032846-5 p92 5.1.2 上级实训内容 [实训内容4]假设一个数组用于存储一周7天,每天24小时温度的度数,数 ...

  10. 浅谈C中的指针和数组(一)

    本文转载地址:http://www.cnblogs.com/dolphin0520/archive/2011/11/09/2242138.html 在原文的基础上加入自己的想法作为修改. 指针是C/C ...

最新文章

  1. Struts2中Action接收参数
  2. .NET项目开发的几个非常重要的项目设置
  3. Novodex2.6.2 布料系统
  4. 豆瓣9.8分,周志明的《凤凰架构》,高屋建瓴,推荐(送书)
  5. linux如何更改默认内核,[linux 内核] 设置内核的默认启动版本
  6. 【零散积累】 vim常用操作
  7. goto语句_C语言goto语句
  8. android实现通知栏搜索功能,actionBar+SearchView实现搜索功能
  9. 年轻人找不到自己喜欢的工作,怎么办?
  10. 图片无损放大软件Topaz Gigapixel AI for Mac
  11. Day16:C++之STL应用篇(推箱子cxk限定)
  12. 初探可视化新秀PyG2Plot
  13. 双人小游戏—五子棋(c语言)
  14. 基于android手机实时监控ipcam视频之一:RTSP
  15. Delphi输出日志的方法
  16. NAS如何进行磁盘碎片整理?
  17. 补货中估计提前期不确定的需求分布公式推导
  18. 深耕怀旧经济,这个淘宝商家如何卖出3个金皇冠店铺?
  19. 算法优化专题A POJ-2352
  20. error while loading shared libraries: libnvinfer.so.8 |【TensorRT 依赖解决】

热门文章

  1. 新来的老大说,“公司以后禁止使用Lombok”,我表示反对~
  2. 如何打造高可伸缩的移动电商架构?
  3. 教你如何在Linux中通过expect工具实现脚本的自动交互
  4. 推荐10个趣味实战项目,从零入门人工智能和数据分析,看这篇就够了
  5. 2018年100个让程序员崩溃的瞬间!看到哪一个你哭了?
  6. Linux运维工程师,你能把iptables玩转麽?
  7. 应对互联网变局,这 8 件事必须要做。
  8. python calu()函数_酚酞指示剂是一类什么物质,它在PH=10时是什么颜色呢(     )...
  9. java resource放入的文件没有生成在classes中_Java的classpath到底指什么
  10. jenkins的安装与使用