1、数组与指针
省流:
- 数组名 =数组首元素的地址,步长为数组内一个元素的类型大小
- &数组名 是整个数组的地址,步长为整个数组所占的字节大小。
- 步长是指 执行 指针+1 之后地址字节的增长量。
- 数组名 =&数组名 。二者值相同,但是含义不同
- 不要单纯的以为二维数组名是个二级指针,它实际上是它内部元素的一个数组指针。
1)一维数组名 是指向该数组首元素地址的指针常量,其值满足 arr = &arr[0],
但是要注意 arr =&arr 也是成立的。
&arr是一个数组指针,它的步长是 数组长度,即 &arr+1 =arr + 数组大小*类型所占字节数。
但是arr和&arr[0]的步长是单个元素 表示的是&arr[0]+1 =arr+1 =&arr[1]。
&arr表示的是整个数组的地址。
2)二维数组名 是一个数组指针,该指针指向二维数组第一行数组的地址,步长增量是整个行。
int main(){
//一维数组
int arr[6] = {0, 1, 2, 4, 5, 6};
int *a_p = arr; //arr是指针,a_p也是指针,可以等价赋值
//这些写法都是合法的 居然还可以 序号在前[数组名]
cout << "指针操作一维数组 " << *(a_p + 1) << *(arr + 2) << a_p[4] << 5[a_p] << endl;
//二维数组
int arr2[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
cout<<"指针操作二维数组"<<*(*(arr2+1)+2)<<endl; //[1][2] ,二位数组数组名是一个数组指针,它指向第一行的首地址。 arr2+1 增量是一行,即此时指针移到第二行首地址
int (*a_p2)[3] =arr2; //定义一个数组指针,步长是3,等同于二维数组的数组名
cout<<" a_p2测试二维数组 "<<a_p2[1][2]<<endl; //输出结果应该是6
}
数组指针:指向数组的指针,格式:
type (*p)[n] = 整个数组的地址
整个数组的地址:
如上面所说,一维数组是的数组地址是: &数组名,而不仅仅是 数组名。
因为数组地址和数组元素首地址的步长是不同的
()与[ ] 优先级相同,根据结合律,就从左向右运算。
()里是*p,先定义了指针,所以p是个指针,然后后面是[ ],才是数组,即数组指针。它指向了含有n个int类型的数组。
普通指针的大小是所在操作系统的字长(32位机 4字节,64位机 8字节)。
指针的步长(增量)是它所指向的数据类型的大小。比如
//指针步长
int a=10;
int *a_ptr =&a;
cout<<a_ptr<<" \t指针加1 "<<a_ptr+1<<endl;
double d=1.01;
double * d_ptr=&d;
cout<<d_ptr<<" \t指针加1 "<<d_ptr+1<<endl;
9c 到a0 差4个基本内存单元,一个内存单元是1B;4B刚好对应一个Int
90~98差8个字节,刚好对应一个double
同理,数组指针的步长是 该数组的长度。定义数组指针的语句:如下
int arr[3]={0,3,6};
//数组指针
int (*ptr_arr)[3]=&arr;
//普通指针
int *ptr_arr =arr;
为了方便理解:(这样写编译器不通过,这里只是为了方便理解)
int[3] (*p) =&arr; //这样是不是好理解了? double *p ; int *p
按照指针增量的知识,推测下面结果:
int arr[3]={0,3,6};
int (*ptr_arr)[3]=&arr;
cout<<ptr_arr<<" \t指针加1 "<<ptr_arr+1<<endl;
输出结果差值正好是12字节
0x81bd7ff62c 指针加1 0x81bd7ff638
对于二维数组:
int arrb[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
int (*ptr_arrb)[3]=arrb;
由于我们已知:数组名 =数组元素的首地址。
二维数组的元素是一维数组,所以二维数组名其实就是 该数组内首个一维数组的数组地址。
因此 上面代码里 定义的数组指针,其实是二维数组内元素的指针,步长是数组的一个行,即长度为3的一个一维数组。
如图:二维数组名实际上指的是首个元素(arr[0][]行的一维数组)的地址,即步长为3的数组指针
提一个问题:如果想定义上面二维数组的 数组指针呢?
答案:
int (*p)[2][3]=&arrb;
cout<<p<< " "<<p+1<<endl;
0xc1fa3ff6e0 0xc1fa3ff6f8
结果刚好差24字节 6个int元素