指针数组和数组指针详解

指针数组和数组指针

1.定义

int *p[4]; //定义了一个指针数组p,p一共有4个单元,每个单元都是一个int型的指针

int (*p)[4]; //定义了一个数组指针p,p可以指向一个拥有4个单元的int型数组

2.指针数组的用法

#include <stdio.h>

int main()

{

int *p[4];

int a=1, b=2, c=3, d=4;

p[0] = &a;

p[1] = &b;

p[2] = &c;

p[3] = &d;

printf("%d %d %d %d\n", *p[0], *p[1], *p[2], *(p[3]));

return 0;

}

程序输出:1 2 3 4

分析:指针数组的用法比较简单,注意一点*p[0]和*(p[0])是一样的,因为在C语言中[]的优先级要高于*运算符。

3.数组指针的用法

数组指针的用法比较复杂,理解相对来说也比较困难,还是需要结合一些实际的例子来一步步的理解。

例子1:

int main()

{

int a[8] = {1, 2, 3, 4, 5, 6, 7, 8};

int *p = a;

printf("%d\n", p[2]);

return 0;

}

程序输出结果:3

分析1:这是平时在写程序时经常用到的一种写法,但是却隐藏着一些知识点可能平时都没有太注意到。这里p是一个int型的指针,然而在程序中却将p类似于数组来使用,这个怎么理解呢?其实这样写的话,就相当于将p作为基址[2]表示的是相对于基址的偏移,这里是偏移两个p指向类型的单元,也就是得到的a的第三个单元(单元从1开始计数)的值也就是3。同时记住:a的理解有两种:第一种a表示这8个int单元的总称,体现在&a的时候,这个时候&a的类型为int (*)[8];第二种理解a的值代表的是一个int类型的指针,体现在a[1]=*(a+1)这种操作中。

例子2

#include <stdio.h>

int main()

{

int a[8] = {1, 2, 3, 4, 5, 6, 7, 8};

int (*p)[8] = &a;

printf("%p  %p ", p, a); //这里是用的a的值,所以a体现的是指针的性质

printf("%d ", ((*p)[3]));

printf("%d\n", *p[3]);

return 0;

}

程序输出:0012FF60 0012FF60 4 1245120

分析2:可以看到p和a的值输出是一样的,但是要记住这里的p和a的类型可是完全不一样的,所以在赋值的时候没有直接将a赋值给p而是用了&a。这里的a是一个int类型的指针,而p是一个int (*)[8]类型的指针,两者直接赋值编译器会报错。第3个输出的数为4,也就是a[3]的值,但是第四个输出的数明显是一个错误的数据,同时记住不一定每次都是这个数。这个如何理解呢?p是一个数组指针,所以*p代表的才是a(尽管它们值是一样的),然而由于[]的优先级高于*,所以((*p)[3])才可以取到a[3]的值。然而p[3]根据上面的理解,是以p为基址,偏移3个p指向的单元,然而p此时指向的是数组,所以p指向的是一个8个int单元的数组,所以p[3]表示的就是内存区域往后的第4个数组(每个数组拥有8个int单元)的首地址,*p[3]取到的就是第四个数组的第一个单元的值,虽然这样操作越界了,但是编译器检查不出来。

例子3:一个更加复杂的例子

#include <stdio.h>

int main()

{

int p[3][4][5];

int *q = (int *)p;

int (*s)[5] = &p[1][0];

int i,m;

for(i = 0; i < 60; i++)

q[i] = i;

printf("%d ",p[1][7][1]);

printf("%d ",(*(s+1)[3]));

printf("%d\n",p[1][7][1]*(*(s+1)[3]));

return 0;

}

程序输出:56 40 2240

分析3:这个输出可能乍一看确实比较奇怪,但是认真分析的话还是可以得到正确结果的。首先看for循环的赋值语句,p数组一个3*4*5=60个单元,而这个for循环分别将这60个单元依次赋值为0~59。再看p[1][7][1],操作越界了这个很明显,但是来分析一下这个具体取的是哪个单元的值:1*20+7*5+1=56,也就是说相当于取的是q[56]的值,这个值就是56。比较难理解的就是(*(s+1)[3]),不过根据前面的讲解,理解这个也是不难的,s是一个int (*)[5]类型的指针,所以s+1就会指向下一个数组(每个数组包含5个int单元),s+1的值也就相当于是&p[1][1]了,然而[]运算相当于将前面的作为基址进行偏移,偏移3个单元(每个单元又是一个数组),所以就相当于&p[1][4],然而由于p的第二维只有最多3的下标,所以更为准确的说法就是&p[2][0],然后取这个地址的值,也就是取p[2][0][0]的值,这个值就是40。

时间: 2024-11-05 19:01:06

指针数组和数组指针详解的相关文章

后缀数组学习笔记【详解|图】

后缀数组学习笔记[详解] 老天,一个后缀数组不知道看了多少天,最后终于还是看懂了啊! 最关键的就是一会儿下标表示排名,一会用数值表示排名绕死人了. 我不知道手跑了多少次才明白过来.其实我也建议初学者手跑几遍,但是一定要注意数组的意义,否则就是无用功. 数组含义: s[ ]:输入的字符串,预处理的时候会在末尾加上一个0 sa[ ]:它的下标就是后缀排名 x[ ] = t[ ]:用来保存第一关键字排名,注意!它的数值是排名.初始时恰好是字符串的ASCII码.字典序嘛! y[ ] = t2[ ]:它的

【转载】C++ 值传递、指针传递、引用传递详解

原文链接:http://www.cnblogs.com/yanlingyin/ 值传递: 形参是实参的拷贝,改变形参的值并不会影响外部实参的值.从被调用函数的角度来说,值传递是单向的(实参->形参),参数的值只能传入, 不能传出.当函数内部需要修改参数,并且不希望这个改变影响调用者时,采用值传递. 指针传递: 形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作 引用传递: 形参相当于是实参的“别名”,对形参的操作其实就是对实参的操作,在引用传递过程中,被调函数的形式参数

C++ 值传递、指针传递、引用传递详解

写在前头: 本文摘抄字博客:http://www.cnblogs.com/yanlingyin/archive/2011/12/07/2278961.html 自己的理解: 关于指针和引用的区别在于: 指针是对地址的一份拷贝,虽然对其的使用,可以通过地址来改变实参的值, 但如果对这个指针的拷贝,做出改变,那么这种改变将不影响实参. 而引用,是一种间接的操作,对形参的所有改变,都会通过间接的操作,映射到实参中,引用本身就是一种别名, 所以对这个别名的操作,就是对实参的操作. 还有一些其他的区别,就

C语言数组空间的初始化详解

数组空间的初始化就是为每一个标签地址赋值.按照标签逐一处理.如果我们需要为每一个内存赋值,假如有一个int a[100];我们就需要用下标为100个int类型的空间赋值.这样的工作量是非常大的,我们就想到了让编译器做一些初始化操作,初始化操作是第一次赋值,第二次赋值就不能再这样赋值了. int a[10]=空间: 我需要给它一个空间,让它对这里面的值进行批量处理:比如int a[10]={10,20,30}; //a[1]=10,a[2]=20,a[3]=30,a[4]=-=a[9]=0所以实际

后缀数组 DC3构造法 —— 详解

学习了后缀数组,顺便把DC3算法也看了一下,传说中可以O(n)复杂度求出文本串的height,先比较一下倍增算法和DC3算法好辣. DC3 倍增法 时间复杂度 O(n)(但是常数很大)   O(nlogn)(常数较小) 空间复杂度   O(n)    O(n) 编程复杂度    较高   较低 由于在时间复杂度上DC3的常数比较大,再加上编程复杂度比较高,所以在解决问题的时候并不是最优选择.但是学到了后缀数组还是补充一下的好点. DC3算法的实现: 1:先把文本串的后缀串分成两部分,第一部分是后

JAVA中list,set,数组之间的转换详解

JAVA的list,set,数组之间的转换,主要是使用Apache Jakarta Commons Collections,具体的方法如下:import org.apache.commons.collections.CollectionUtils; String[] strArray = {"aaa", "bbb", "ccc"};    List strList = new ArrayList();    Set strSet = new Ha

JavaScript入门之数组:Array类型详解

数组应该是每个语言中都用得极度频繁的数据类型,JavaScript也不例外. 个人认为,Js中的Array类型非常强大. 首先没有C/C++等语言需要在数组初始化时指定数组长度(并不可变)的要求. 也不需要指定特定的基本数据类型(Number,String,Boolean,Null,Undefined,Object),也就意味着,一个数组中可以存多种数据类型的值. 我想总结一下Array的常用方法,在这之前,先介绍一下Array的基本用法: 基本用法: 1.创建数组: //创建空数组 var a

OC中数组类NSArray的详解(二)

数组类的便利 1.for循环(大家都会的...) 2.NSEmunerator 3.for in 首先重点说下 第二种NSEmunerator枚举器,系统声明是 1 @interface NSEnumerator : NSObject <NSFastEnumeration> 2 3 - (id)nextObject; 4 5 @end 6 7 @interface NSEnumerator (NSExtendedEnumerator) 8 9 @property (readonly, copy

js数组的sort排序详解

<body> <div> sort()对数组排序,不开辟新的内存,对原有数组元素进行调换 </div> <div id="showBox"> 1.简单数组简单排序 <script type="text/javascript"> var arrSimple=new Array(1,8,7,6); arrSimple.sort(); document.writeln(arrSimple.join()); <

poj 3581 Sequence(后缀数组,离散化)详解

题目链接:http://poj.org/problem?id=3581 题目大意:给一个数列,要求将其分成三段,每段进行翻转后形成后合并成新数列,求按字典顺序最小的新数列. 思路: 注意到题目中数列a0,a2,a3...an-1, a0是最大的,因此将原数列翻转后an-1,an-2,...,a1,a0,求后缀数组, sa[0]所代表的后缀即为所求第一段翻转后的数列,注意到要分成三份,因此sa[0]<2时不可取,此时找sa[1], sa[2]看是否可取.找第一个位置后,设剩下 数列是an-1,an