声明:1. 文章如有不妥的地方,请您指正,谢谢.
2.另外文中有些细节可能引用您的内容却未给出参考,请原谅我的疏忽,你的共享我不会忘记.
3. Email:lizhiguo0532@163.com 李枝果/lizgo
4.转载请保留该部分信息
对一维数组的指针的理解很关键,这个清楚之后,会对多维数组和指针的理解,复杂指针声明分析都有很大的帮助。
里面涉及的代码都很简单,这里不外乎就是要打印出相关的地址来验证。
#include <stdio.h>
int main(void)
{
int a[10]={1,2,3,4,5,6,7,8,9,10};
int *p;
int **pp;
int ***ppp;
int (*ap)[10];
int i;
p=&a[1];
pp=&p;
ppp=&pp;
ap=&a;
printf("\n");
printf("p=&a[1];\npp=&p;\nppp=&pp;\nap=&a;\n");
printf("\n");
printf("&ap_%%p=%p, &ap_%%x=%x, ap_%%p=%p, ap_%%x=%x\n",&ap,(int)(&ap),ap,(int)ap);
printf("\n");
printf("&a_%%p=%p, &a_%%x=%x, a_%%p=%p, a_%%x=%x\n",&a,(int)(&a),a,(int)a);
printf("\n");
printf("&a[0]_%%x=%x, &a[0]_%%p=%p, a[0]_%%d=%d\n",(int)(&a[0]),&a[0],a[0]);
printf("\n");
printf("&a[1]_%%x=%x, &a[1]_%%p=%p, a[1]_%%d=%d\n",(int)(&a[1]),&a[1],a[1]);
printf("\n");
//1.%p是指打印出指针变量的内容,而不是打印某个变量在内存中的地址,如果强行用%p去打印一个普通变量的内存地址时,编译器会报错。
//2.从利用typedef来定义数组的角度看,数组名就如同一个普通变量名一样,可以对变量名求地址运算,运算结果就是该特殊类型(数组类型)所占据的内存
// 空间的首字节地址,其基类型很容易看出来,就是对应的数组类型(占据40字节空间)
//3.单单看数组名的话,c语言里有这样的两句很重要的话:数组名的内容就是其首元素的首地址;数组名的类型就是其元素类型的指针。从这两句话,是不是又可以看出
// 数组类型和普通类型的差别来吧!至少在名字上就有这两个很大的差别
// 从2.3点说明可以看出为什么在printf("&a_%%x=%x, a_%%p=%p, a_%%x=%x\n",(int)(&a),a,(int)a);的语句执行后,打印的结果都一样来吧!
//4.还需要说明一点的是:为什么我们给printf传参数时,传送的明明是一个用&运算得到的地址值,然后用%p打印的时候就可以原样打出地址来呢?%p不是打印出
// 指针变量的内容吗?这个就是和printf这个函数的实现有关了,简单的说,在printf函数体内部,会创建同类型的指针变量,然后将求地址运算的结果赋值给该指针变量
// 最后打印
//
//
printf("&p_%%p=%p, &p_%%x=%x, p_%%p=%p, p_%%x=%x\n",&p,(int)(&p),p,(int)p);
printf("\n");
printf("&pp_%%p=%p, &pp_%%x=%x, pp_%%p=%p, pp_%%x=%x\n",&pp,(int)(&pp),pp,(int)pp);
printf("\n");
printf("&ppp_%%p=%p, &ppp_%%x=%x, ppp_%%p=%p, ppp_%%x=%x\n",&ppp,(int)(&ppp),ppp,(int)ppp);
printf("\n");
printf("p+1=%x\npp+1=%x\nppp+1=%x\nap+1=%x\n",(int)(p+1),(int)(pp+1),(int)(ppp+1),(int)(ap+1));
p=&a[0];
printf("\n");
for(i=0;i<10;i++)
{
printf("a[%d]=%d\n",i,*((*pp)+i));//利用二级指针引用数组内容,也可以三级指针引用*((*(*ppp))+i) 一级指针引用
}
printf("\n");
for(i=0;i<10;i++)
{
printf("a[%d]=%d\n",i,(*ap)[i]);//利用数组指针引用数组内容(*ap)<---->a数组名,甚至可以这样写*((*ap)+i)<--->*(a+i)
}
return 0;
}
/*
一个int型变量b ,假设在内存中占据一块空间,4个字节,内容位100,这个变量的内存地址是0xbffff300。
于是&b=0xbffff300,b=100.
这个是理所当然的,每个c人都很熟悉,但是
如果我现在定义了一个数组:int a[10];
这个你怎么看呢?其实c语言中,a也是有其类型的,和int char float double 等类型定义的变量一样,只不过这种类型比较特殊
是数组类型,这里数组类型其实是一个统称了,其实再细分还有一维数组类型,二维数组类型,三维数组类型等,之后还可以细分,有
一维int型数组,一维char型数组,一维float型数组,二维int型数组,二维char型数组等等,在之后呢?这样就可以来吗?no,比如在
一维int型数组之上,还有更细的类型可以区分,你的一维int型数组具有几个元素呢?这个也应该说明。所以到最后,上面数组a就可以说成是
这样的类型:具有10个int型元素的一维数组类型,可以这样表示int [10](在c语言中,从语法的角度来说,在一个定义变量的表达式中,只要
将变量名去掉,剩下的部分就是这个变量的类型来)。
数组类型在内存中也是占据来一段连续的地址空间的,上面的a就是占据来40个自己的空间,我们就可以说a这种数组类型的特殊变量具有40个字节的
空间,那现在来和我们的b比较看看呢?是不是本质是一样的?我们同样可以像对普通变量b一样对其取地址,然后赋值给某个指针变量,对于b来说我
们需要定义一个int *pb=&b就可以来,但是对于数组,我们的数组指针变量该如何定义呢?其实方法一样。
我这里就引出一个很的关键字:typedef
这个关键字以前只知道是类型定义,就是不知道怎么去用,用在那里。不过现在知道了
typedef int A[10];
A a;
这两句等价于什么呢?int a[10];
这里看似简单,可后面它的作用就大了
从A a;从形式上看起来是不是和 int b;一样了
现在就可以通过A这种类型来定义数组指针了
A *p;
那这一句等价于什么呢?int (*p)[10];
这就是定义了一个数组指针,有的人可能会疑惑,问这里为什么要加括号呢?
这个就涉及到了[]和*的优先级的问题,[]的优先级高于*。如果是这样 int *p[10];那么[]先与p结合组成一个数组,然后数组p
中的每个元素再和*结合组成指针,什么指针呢?当然就是int *(int指针)了。
而在这里我们的本意是想定义一个指针,而不是一个数组,所以必须得让*与p先结合,这里就只有用括号了,之后再和[]结合来说明
该指针所指向的类型。所以加上()就是必须的了。
p=&a;这个表达式就成立了,因为他们的类型(基类型)一样。
说具体一点,&a就相当于对数组这种特殊的变量取地址运算(和对普通变量取地址运算是一样的),那么在赋值之后p就成了一个指向具有
10个int型元素的数组的指针变量。(通常在不影响语法的情况下,地址,指针,指针变量我们都不区分)
*/
//执行结果如下:
lzg@lzg-desktop:~/array_test$ vim array_1.c
lzg@lzg-desktop:~/array_test$ gcc -g -o array_1 array_1.c
lzg@lzg-desktop:~/array_test$ ./array_1
p=&a[1];
pp=&p;
ppp=&pp;
ap=&a;
&ap_%p=0xbf86c9f0, &ap_%x=bf86c9f0, ap_%p=0xbf86c9c4, ap_%x=bf86c9c4
//&ap是ap数组指针变量的地址,ap是数组指针的内容(指向的空间首地址)
&a_%p=0xbf86c9c4, &a_%x=bf86c9c4, a_%p=0xbf86c9c4, a_%x=bf86c9c4
//&a是取数组a这个特殊类型变量的地址,和普通变量取址一样,后面两者就要考虑数组名的特殊性了。上面程序注释里的两句重要的话
&a[0]_%x=bf86c9c4, &a[0]_%p=0xbf86c9c4, a[0]_%d=1
//证实了数组名的内容是其首元素的首地址,数组名是一个指针的事实,可以通过a_%p=0xbf86c9c4里面的%d得到证实
&a[1]_%x=bf86c9c8, &a[1]_%p=0xbf86c9c8, a[1]_%d=2
&p_%p=0xbf86c9fc, &p_%x=bf86c9fc, p_%p=0xbf86c9c8, p_%x=bf86c9c8
&pp_%p=0xbf86c9f8, &pp_%x=bf86c9f8, pp_%p=0xbf86c9fc, pp_%x=bf86c9fc
&ppp_%p=0xbf86c9f4, &ppp_%x=bf86c9f4, ppp_%p=0xbf86c9f8, ppp_%x=bf86c9f8
//多级指针的关系
p+1=bf86c9cc //
pp+1=bf86ca00 //pp的基类型是int *,arm平台下占据4字节,所以+1操作,就只加上4
ppp+1=bf86c9fc
ap+1=bf86c9ec //ap的基类型是具有10个int型元素的数组,这个+1操作就是加上了40
//指针的操作,p+/-n,这个在数值上实际上是增加或者减少了 n*sizeof(p的基类型) 这么多。
a[0]=1
a[1]=2
a[2]=3
a[3]=4
a[4]=5
a[5]=6
a[6]=7
a[7]=8
a[8]=9
a[9]=10
a[0]=1
a[1]=2
a[2]=3
a[3]=4
a[4]=5
a[5]=6
a[6]=7
a[7]=8
a[8]=9
a[9]=10
lzg@lzg-desktop:~/array_test$
//无论是定义数组指针int (*)[10]还是数组元素类型的指针int *(int **或者int ***),对数组的引用操作上都没什么区别,只是在对所定义的指针操作上面存在差异
分享到:
相关推荐
C++一维数组和指针的关系总结
二维数组a由若干个一维数组组成在C语言中定义的二维数组实际上是一个一维数组,这个一维数组的每一个成员又是一个一维数组。如以上定义的a数组,则可视a数组由a[0]、a[1]、a[2]等三个元素组成,而a[0]、a[1]、a[2]等...
详细分析二维数组与指针关系,并利用指针 实现二维数组和一维数组的相互转换!
指针的概念 一维数组与指针PPT学习教案.pptx
用C++语音实现一维数组二维数组写入txt,从txt中读取数据存到一维数组、二维数组,数组用指针表示
指针和一维数组的讲解,本人觉得挺好的,给大家分享下,适合一些小白
指针的概念一维数组与指针学习教案.pptx
vc+ 用指针实现二维数组的转置,通过指针实现对二维数组的转置操作
所以数组指针也称指向一维数组的指针,亦称行指针。 指针数组 定义 int *p[n]; []优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组,它有n个指针类型的数组元素。这里执行p+1是错误的,这样赋值...
p为指向整型二维数组的指针变量,二维数组的列数为n int *p() p为返回指针值的函数,该指针指向整型量 int (*p)() p为指向函数的指针,该函数返回整型量 int **p p为一个指向另一指针的指针变量,该指针指向一个...
另外,a[0]也可以看成是a[0]+0,是一维数组a[0]的0号元素的首地址,而a[0]+1则是a[0]的1号元素首地址,由此可得出a[i]+j则是一维数组a
数据结构-3期(KC002) 指向一维数组的指针.docx 学习资料 复习资料 教学资源
指针含义、指针&和*运算符、*p++ *p— (*p)++ (*p)-- *++p *--p、二维数组的访问、指向二维数组的指针元素及指针指向二维数组的一维数组的指针、数组指针作为函数参数的四种形式以及字符数组与指针的关系 区别和拷贝
在c++中,经常调用函数,而子函数经常要返回的值是数组,无论一维数组还是二维数组都需要运用到指针的知识。一维数组不再过多叙述,给了一个实例如何返回二维数组,希望对大家有帮助(主要用到指针的知识,看不懂的...
一维数组和指针: 对于一位数组和指针是很好理解的: 一维数组名: 对于这样的一维数组:int a[5]; a作为数组名就是我们数组的首地址, a是一个地址常量 . 首先说说常量和变量的关系, 对于变量来说, 用箱子去比喻再...
C语言程序设计-有一个一维数组score,内放10个学生的成绩,用一个函数来求平均成绩;
C语言程序设计(第2版)-2期 拓展知识7-3 指向一维数组的指针变量.pdf 学习资料 复习资料 教学资源
第9章 指针和数组——指针和一维数组之间的关系C语言程序设计第9章 指针和数组一维数组元素的引用数组名代表数组的首地址&a[0]a+1不是加上1个字节,取决于a
labview读取二维数组中所有数据,涉及到labview中数组VI的熟练使用。
指针的概念 指针变量 指针与数组 指针的算术运算 行指针与列指针 练习1 二维数组的指针变量 指向一维数组的指针变量 指针与字符串 返回指针值的函数 指针数组 练习2