数组
- 数组的元素在内存中连续存储
- 各数组元素具有同一类型(大小相等)
- 数组名代表数组的首地址(第一个元素的地址)
数组与地址
- 地址做加法与整数做加法是有区别的,地址做加法时,是以地址的类型大小为单位进行相加的。
- 以int arr[5]为例,arr 代表了int 类型元素的地址,由于int 类型占用4 个字节,那么,arr 加1,实际上是数值增加的是4,这样,就可以通过*(arr + 1)的方式访问第二个数组元素了。
指针
- 与定义整型变量一样,p 本身也存储在程序的栈空间上,在32 位操作系统下,所有指针都占用4 个字节大小。
- 指针是一种结合数据类型,它希望存储的是它所结合的数据类型的地址,即使你存入别的任何数据,也会被当作该类型的地址对待。
数组与指针的关系
数组就是数组,指针就是指针,它们之间没有任何关系。
- 指针变量在32 位系统下,永远占4 字节,其值为某一个内存的地址,指向一块存储区域。
- 数组代表的是一片连续的存储单元。
关于数组名
名称 | 含义 |
---|---|
&a[0] | 取数组第一个元素的地址 |
a | 数组名,只在sizeof(a)和&a 时代表整个数组,其他情况下和&a[0]等价,表示数组第一个元素的地址 |
&a | 表示整个数组的首地址 |
a + 1 | a 在此处表示数组第一个元素的地址,该地址值加上sizeof(int),表示数组下一个元素的地址 |
&a + 1 | &a 表示整个数组的首地址,该地址值加上sizeof(a)的值,得到下一个数组的首地址,显示,该地址相对当前数组已经是越界。 |
注:a 表示数组第一个元素的地址,&a 表示整个数组的首地址,虽然它们的值一样,都是数组的首地址,但是含义完全不一样。举个例子,浙江省的省政府在杭州,杭州市的市政府也在杭州,两个政府都在杭州,但其代表的意义完全不同。
指针数组
- 指针数组本质还是数组,只不过它存储的成员是指针。
int *p[3] = {&a, &b, &c};
p[0][0] -> a
*(*(p + 0)) -> a
野指针问题
指针未指向某一合法地址时,严禁使用*运算符对该地址进行读写:
int *p; //未初始化,存储的地址可能是任意值
*p = 100; //访问的有可能是任意的地址
这种错误称为访问野指针(悬垂指针suspended pointer)。为了防止以该方式访问导致不可预知的错误,通常在定义指针的时候,要将指针赋值为NULL,指向系统的0 地址处,如下:int *p = NULL;
。
指针的运算
当p1、p2 指向同一个类型的地址时,两个指针可以进行运算,运算的规则如下:
- 指针加(p1 + a):地址偏移量为a*sizeof(指针类型)
- 指针减(p1 – a):地址偏移量为-a*sizeof(指针类型)
- 指针相加(p2 + p1):无意义
- 指针相减(p2 – p1):两个指针之间相差的元素个数
- 指针比较(p2 > p1):比较指针的数值大小