指针的概念:
1. 指针就是个变量,用来存放地址,地址唯一标识一块内存空间。
2. 指针的大小是固定的4/8个字节(32位平台/64位平台)。
3. 指针是有类型的,指针的类型决定了指针的加减整数的步长,指针的类型也决定了指针解引用操作的时候,访问的权限。
数组的概念:
1.数组是一组相同类型元素的集合。
1.字符指针
在指针的类型中我们知道有一种指针类型为字符指针 char*。
![](https://img-blog.csdnimg.cn/0b88f16f799e427181e49c052e6545b7.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbGlua2FuZzAwNw==,size_10,color_FFFFFF,t_70,g_se,x_16)
1.把字符‘w’赋值给字符变量ch,对ch进行取地址并赋值给指针 pc,指针 pc 是字符指针,再对pc进行解引用,然后把字符‘a’赋值给它,最后用printf( )函数进行打印。
![](https://img-blog.csdnimg.cn/f8e9d9e0cf014405837e72b4d9e26c4c.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbGlua2FuZzAwNw==,size_18,color_FFFFFF,t_70,g_se,x_16)
1.把arr数组中第1个元素的地址放在 p2 里。
2.把字符串"abcdef"的第1个字符的地址放在 p 里,内存中 a 的地址为:0x000A7BD0。
![](https://img-blog.csdnimg.cn/ea17f66e499e4d50a3a362c339719f6f.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbGlua2FuZzAwNw==,size_13,color_FFFFFF,t_70,g_se,x_16)
1.无论是 const char* p1 = "abcdef" 还是 char const * p1 = "abcdef",在这两种情况下被const修饰,就意味着,指针 p1 所指向的内容不能修改,否则就会报错。
![](https://img-blog.csdnimg.cn/9f452134810c472fa8f84f4a2417a188.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbGlua2FuZzAwNw==,size_14,color_FFFFFF,t_70,g_se,x_16)
1.内存中有块空间放着 a b c d e f \0 ,假设字符串中第1个字符的地址,即 a 的地址是0x0012ff40,那么 p1 就等于 0x0012ff40,p2 就等于 0x0012ff40,所以 if 语句中p1 == p2的条件成立,故打印 p1 == p2。
2.内存为arr1开辟一块空间,放着 a b c d e f \0,然后从 arr1 的起始地址开始,分别放着 a b c d e f \0,内存再为arr2开辟另一块空间,放着 a b c d e f \0,然后从 arr2 的起始地址开始,分别放着 a b c d e f \0。arr1 和 arr2 在内存中开辟的空间不一样,起始地址是不会相同的,所以if 语句中p1 == p2的条件不成立,故打印 arr1 != arr2。
2.指针数组
指针数组,是数组,是一个存放指针的数组。
![](https://img-blog.csdnimg.cn/4fbf3e4e753b485198be428a8af5dd3b.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbGlua2FuZzAwNw==,size_16,color_FFFFFF,t_70,g_se,x_16)
1.整型数组 arr[10] 存放10个int 类型的变量。
2.字符数组 arr2[5]存放5个char 类型的变量。
3.指针数组 arr1[10]存放10个 int* 类型的变量,arr2[10]存放10个 int** 类型的变量,arr3[4]存放4个char* 类型的变量,arr4[5]存放5个 char** 类型的变量。
![](https://img-blog.csdnimg.cn/ab155c81e7814bd5877e83ccc8797e00.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbGlua2FuZzAwNw==,size_20,color_FFFFFF,t_70,g_se,x_16)
1.首先 arr[3]是个指针数组,存放p1、p2、p3这三个指针, 这三个指针分别指向a、b、c三个整型变量,在for循环中,用printf( )函数分别打印三个变量的数值和地址。
![](https://img-blog.csdnimg.cn/4cf99e260f6f4e0d803f51a6dc9cdfda.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbGlua2FuZzAwNw==,size_19,color_FFFFFF,t_70,g_se,x_16)
1.首先 parr[3]是个指针数组,存放arr1、arr2、arr3这三个指针, 这三个指针分别指向arr1、arr2、arr3三个整型数组(),在for循环中,用printf( )函数分别打印三个整型数组的数值。
2.在 parr[3] 这个指针数组中,存放着 arr1 这个指针,虽然 arr1 这个指针是该数组的首元素的地址,不是整个数组的地址。这个点在下面会进行强调并运用,这里先进行提示。
3.这类似于二维数组,将 printf("%d ", *(parr[ i ] + j)) 改成 printf("%d ", parr[ i ][ j ]),打印结果保持不变。
3.数组指针
数组指针的定义:
数组指针,是指针,指向数组的指针。
![](https://img-blog.csdnimg.cn/59162d51e246467f9cdc52a439570173.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbGlua2FuZzAwNw==,size_9,color_FFFFFF,t_70,g_se,x_16)
1.整形指针: int* p,是能够指向整型数据的指针。
2.字符指针: char* pc,是能够指向字符数据的指针。
3.同理,那数组指针应该是:能够指向数组数据的指针。
![](https://img-blog.csdnimg.cn/17f5b6eee64f4d42a44da9b15e7d9c24.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbGlua2FuZzAwNw==,size_8,color_FFFFFF,t_70,g_se,x_16)
在 int* p1[ 10 ] 和 int(*p2)[ 10 ] 中,p1 和 p2 分别是什么?
解释如下:
1. 在 int* p1[10] 中, [ ] 的优先级高于 * , p1 先和 [10] 结合,所以 p1 是数组!数组 p1[10] 中存放10个 int* 类型的指针变量。
2.在 int(*p2)[10] 中,( )的优先级高于 [ ], p2 在 ( ) 里先和 * 结合 ,所以 p2 是指针!指向一个大小为10的整型数组,故叫数组指针。
3.在 int(*p2)[10] 中,p2 这个指针不是数组的首元素的地址,而是整个数组的地址。这个点在下面会进行强调并运用,这里先进行提示。
数组名该怎么理解呢?
通常情况下,我们说的数组名都是数组首元素的地址。
但是有2个例外:
1. sizeof(数组名),这里的数组名表示整个数组,sizeof(数组名)计算的是整个数组的大小。
2. &数组名,这里的数组名表示整个数组,&数组名,取出的是整个数组的地址。
解释如下:
![](https://img-blog.csdnimg.cn/21f3f641124b453b808ee9a6cfe2a417.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbGlua2FuZzAwNw==,size_15,color_FFFFFF,t_70,g_se,x_16)
1.表面上,数组名和&数组名打印的地址是一样的。实际上,数组名 表示的是数组首元素的地址,而 &数组名 表示的是整个数组的地址,不是数组首元素的地址。
2.数组 arr[5] 有5个元素,每个元素占4个字节,那么数组 arr[5] 共占 20 个字节,arr表示数组首元素的地址,arr+1 地址跳过4个字节,即一个整型变量的大小,&arr表示整个数组的地址,&arr+1 地址跳过20个字节,即整个数组的大小。
3.补充:%p - 打印地址,打印的地址以十六进制方式显示。
4.所以可以写成这样: int(*p2)[5] = &arr ,p2 这个指针存放的是整个数组的地址,并指向一个大小为5的整型数组,故叫数组指针。
数组指针该如何使用?
写一个函数,打印arr数组的内容,代码如下:
![](https://img-blog.csdnimg.cn/5692ce7049ef45f58e59471d061b2cb1.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbGlua2FuZzAwNw==,size_19,color_FFFFFF,t_70,g_se,x_16)
1.在主函数中创建 arr[10] 的数组,并进行赋值,sz为arr数组的元素个数,对 print1( )、print2( )、print3( ) 这三个函数进行传参,然后这三个函数分别对 arr 数组进行打印。
2.在 print1(arr, sz) 的传参过程中,arr:把数组首元素的地址传过去,sz:把数组的元素个数传过去。在 void print1(int arr[], int sz) 的参数接收的过程中,可以用数组进行接收,把形参写成数组的形式。进入print1()函数,在for循环中,用printf()函数对数组分别进行打印。补充如下:
在 void print1(int arr[], int sz) 中,对 int arr[]进行解释:传参时 arr 把 arr 数组的首元素传过去,首先,用数组接收,写成 arr[],其次,这个数组接收的元素的类型是 int 类型,写成 int arr[],最后,int arr[] 这个数组就成为了接收 arr 的形参。
3.在 print2( arr, sz) 的传参过程中,arr:把数组首元素的地址传过去,sz:把数组的元素个数传过去。在void print2 (int* arr , int sz) 的参数接收的过程中,可以用整型指针进行接收,把形参写成指针的形式。进入print2()函数 ,在for循环中,用 printf( ) 函数对解引用的指针分别进行打印。补充如下:
在 void print2(int* arr, int sz) 中,对 int* arr 进行解释:传参时 arr 把 arr 数组的首元素传过去,首先,用指针接收,写成 * arr ,其次,这个指针接收的元素的类型是 int 类型,写成 int* arr,最后,int * arr 这个指针就成为了接收 arr 的形参。
4.在 print3(&arr, sz) 的传参过程中, &arr:把整个数组的地址传过去,sz:把数组的元素个数传过去。在void print3(int(*p)[10], int sz) 的参数接收的过程中,可以用数组指针进行接收,把形参写成数组指针的形式。补充如下:
在void print3(int(*p)[10], int sz) 中,对 int(*p)[10] 进行解释:传参时 &arr 把 arr 数组的10个元素传过去,首先,用指针接收,写成(*p) ,其次,这个指针接收10个元素,写成(*p)[10],接着,所接收的每个元素是int 类型,写成 int(*p)[10],最后,int(*p)[10] 这个数组指针就成为了接收 &arr 的形参。
![](https://img-blog.csdnimg.cn/36bbc0fc958a47a3bdcda0c66bcef755.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAbGlua2FuZzAwNw==,size_9,color_FFFFFF,t_70,g_se,x_16)
请问 arr 、parr1、parr2、parr3 分别是什么?
1. arr 是一个数组,数组有5个元素 ,每个元素是int类型,所以 arr 是整型数组。
2. parr1 是一个数组,数组有10个元素,每个元素的类型是int*,所以 parr1 是指针数组。
3. parr2 是一个指向数组的指针,指向的数组有10个元素,每个元素的类型是int,所以 parr2 是数组指针。
4. parr3 是一个数组,数组有10个元素,每个元素的类型是:int( * )[5] ,所以 parr3 是存放数组指针的数组。