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

先介绍一下数组,数组是一种数据结构,是同一类型的元素的集合,在内存上是线性排列的,例如:int a[10]={1,2,3,4,5};int b[10];

a和b都是整型数组,大小为10,a数组声明了并且初始化了,前五个元素为{}中的值,剩余元素全部初始化为0;b数组仅仅声明,每一个元素都是随机值。

数组名与指针的杂七杂八

数组也是一种数据类型,所以上面的int a[10],实际上可以这样理解,数据类型为int [10],变量名为a,因此可以对这个变量取地址,&a。如果是一个int型变量,如int c=10;那么&c可以用一个int*变量来接,如int* p=&c,那么&a该怎么接呢,既然数据类型是int[10],那么是不是就应该用(int [10])* p1=&a;这个思路是没错的,不过在c++里是另一种表达方式,int (*p1)[10]=&a;即指向数组的指针,可以通过*p1来代表整个数组,所以可以通过(*p1)[索引]的方式访问数组元素。这种方式访问数组元素可能使用起来比较繁琐,实际上可以这样,int* p2=a;这时p2指向数组的首元素,然后通过p2[索引]、*(p2+索引)都可以访问数组元素,这种方式难以理解,怎么能把一个数组变量赋值给一个指针,如果是int *p2=(int *)&a的话倒是很容易理解的,但是这种方式确实是可用而又简便的,这恐怕是编译器在背后帮我们做了很多工作。编译器做的工作确实是很多的,比如上面图中的a,a+1,a+2...表示数组各个元素的地址假设首元素地址为0x40000000,那么第二个元素的地址并不是0x40000001,a,a+1,a+2这样的方式只是方便让我们知道是第几个元素的地址,编译器会帮我们把它们转成真正的地址,第二个元素的首地址实际上为0x40000000+sizeof(元素的数据类型)*1,这里是int,那么就是0x40000004,第三个元素地址为0x40000008,以此类推。

二维数组

二维数组虽然叫二维数组,但是在内存上还是一维的,即所有元素线性排列,可以用下面这个程序验证一下:

#include <iostream>
using namespace std;
void main()
{
	int c[][3] = { { 1, 2, 3 }, {4,5,6} };
	int *p1 = (int*)&c;
	for (int i = 0; i < 6;i++)
	{
		cout << *(p1 + i) << endl;
	}
	system("pause");
}

这个程序能证明上面的说法,不过我这边初始化时候用的int c[][3],为什么不用int c[2][3]呢,int c[2][3]显然是可以的,我只是想说明编译器会推导出是“二行三列”的数组,不信在我代码的基础上加一句cout<<sizeof(c)<<endl;答案肯定是24的。那么如果int c[2][]代替可以吗,答案是不可以,如果是int c[]={1,2,3,4,5};这样是可以确定元素个数为5的,这里元素类型为int;而int c[][3]={{1,2,3},{4,5,6}},其实可以这样理解,元素类型为int [3],也就是(int [3]) c[]={{1,2,3},{4,5,6}},所以能推导出来是2,这里元素类型必须定下来,所以第二维不能省略。

然后说一下二维数组元素地址的表示方法,在一维数组中,int a[10]={......};要获取第i个元素的地址,可以是a+i,也可以是&a[i]。在二维数组中,表示第“i行j列”元素的地址也是类似的,先看看下面这张图:

正如之前所说,我们可以把int c[2][3]这个二维数组看成是一维数组,元素类型为int[3],这样一来的话只有c[0]和c[1]两个元素,每个元素都是一个一维数组,要访问一维数组中第j个元素的地址,就可以用(数组名+i)的方式,所以c数组第一行第j列的元素地址为c[0]+j,第2行第j列就是c[1]+j,以此类推,第i行j列元素的地址可以表示为c[i]+j。实际上,c[i]可以用*(c+i)来表示,这里的步长为一个一维数组元素的大小,即sizeof(int)*3,所以另一种表示方法为*(c+i)+j。还有一种最简答的,就是&c[i][j]了。

指针数组与数组指针

这两个东西刚开始学的时候很容易混淆,指针数组指的是元素为指针的数组,如char* p[]={"How","Are","You"};这个数组有三个char*的元素,p[0]="How",p[1]="Are",p[2]="You";数组指针指的是指向数组的指针,如int a[10]; int(*p)[10]=&a;

数组作函数参数退化为指针问题

先来看一段程序:

#include <iostream>
using namespace std;
void PrintArraySize(int a[10])
{
	cout << sizeof(a)<<endl;
}
void PrintArraySize(int a[10][10])
{
	cout << sizeof(a) << endl;
}
void main()
{
	int a[10];
	int b[10][10];
	cout << sizeof(a) << endl;
	cout << sizeof(b) << endl;
	PrintArraySize(a);
	PrintArraySize(b);
	system("pause");
}

猜一下这个程序的输出结果是啥?40 400 40 400吗?如果是这样猜的话只猜对了前两个,后两个输出为 4 4,为什么会这样呢?实际上,当数组做函数参数时,会退化为指针。上面的程序中,一维数组会退化为int* p,二维数组会退化为int(*p)[30],如果是指针数组的话,如int *b[10],会退化为int**p,这里的规律,不用说应该也能看出来吧。

牢骚

更新这么短一篇博客,居然花了两个多小时,这才意识到自己的功力还是不够啊,如有错误之处还望指出,感激不尽!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值