`
womendu
  • 浏览: 1480793 次
  • 性别: Icon_minigender_2
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

一维数组和指针

阅读更多

声明: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 ***),对数组的引用操作上都没什么区别,只是在对所定义的指针操作上面存在差异

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics