本章重点内容:
- 字符指针
- 指针数组
- 数组指针
- 数组传参和指针传参
- 函数指针
- 函数指针数组
- 指向函数指针数组的指针
- 回调函数
- 指针和数组面试题的解析
⚡指针数组
字符数组:存放字符的数组,char arr1[10];
整型数组:存放整形的数组,int arr2[10];
指针数组:存放指针的数组。
- 字符指针数组:存放字符指针的数组,char* arr3[10];
- 整形指针数组:存放整形指针的数组,int* arr4[10];
字符指针数组的使用,代码示例如下:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
char* arr[] = { "abcdef","higklmn","opqrst" };
int i = 0;
for (i = 0; i < 3; i++)
{
printf("%s\n", arr[i]);
}
return 0;
}
运行结果如下:
整形指针数组的使用,代码示例如下:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 6,7,8,9,10 };
int arr3[] = { 11,12,13,14,15 };
int* arr[] = { arr1,arr2,arr3 };
//arr是一个存放整形指针的数组
int i = 0;
for (i = 0; i < 3; i++)
{
int j = 0;
for (j = 0; j < 5; j++)
{
printf("%2d ", *(arr[i] + j));
//printf("%d ", *(arr[i] + j))也可写为printf("%d ", arr[i][j]);
}
printf("\n");
}
return 0;
}
运行结果如下:
⚡数组指针
数组指针的定义:
整形指针:指向整形的指针,int a = 10 ;int* pa = &a;
字符指针:指向字符的指针,char ch = 'w';char* pc =&ch;
数组指针:指向数组的指针。
- 字符数组指针:指向字符数组的指针,char arr[10];char (*pc)[10] = &arr;
- 整形数组指针:指向整形数组的指针,int arr[10];int (*pa)[10] = &arr;
代码示例如下:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
//指针数组:本质是数组,是一种存放指针的数组。
//数组指针:本质是指针,是一种指向数组的指针,存放的是数组的地址
int main()
{
//指针数组
char* arr[5];
//数组指针
int arr[5] = { 0 };
int(*p)[5] = &arr;
return 0;
}
&数组名VS数组名:
我们大家在学习C语言的过程中经常将 arr 和 &arr 傻傻分不太清楚,我们知道arr是数组名,数组名表示数组首元素的地址。那&arr数组名到底是啥,下面通过一段代码来揭开大家多年的疑问:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
//数组名绝大部分情况下是首元素的地址
//但是有两个例外:
// 1.sizeof(数组名):sizeof内部单独放一个数组名的时候,数组名表示的是整个数组,计算得到的是数组的总大小
// 2.&数组名:这里的数组名表示整个数组,取出的是整个数组的地址,从地址值的角度来讲和数组首元素的地址是一样的,但是意义不一样
int main()
{
int arr[10] = { 0 };
printf("%d\n", sizeof(arr));
printf("arr = %p\n", arr);
printf("&arr= %p\n", arr + 1);
printf("arr+1 = %p\n", &arr[0]);
printf("&arr+1= %p\n", &arr[0] + 1);
printf("arr+1 = %p\n", &arr);
printf("&arr+1= %p\n", &arr + 1);
return 0;
}
代码分析:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int arr[10] = { 0 };
printf("%d\n", sizeof(arr));
printf("arr = %p\n", arr);//arr表示首元素的地址,类型是 int* 类型
printf("arr+1 = %p\n", arr + 1);//+1就跳过4个字节
printf("&arr[0] = %p\n", &arr[0]);//&arr[0]表示首元素的地址,类型是 int* 类型
printf("&arr[0]+1= %p\n", &arr[0] + 1);//+1就跳过4个字节
printf("&arr = %p\n", &arr);//&arr表示一个数组的地址,将其存放到数组指针中去:int (*p)[10] = &arr;
printf("&arr+1= %p\n", &arr + 1);//类型 int (*)[10],所以+1跳过去的就是指向的整个数组的大小
return 0;
}
代码运行结果如下:
简单总结一下:其实&arr和arr,虽然值是一样的,但是意义应该不一样的。实际上 &arr 表示的是数组的地址,而不是数组首元素的地址。(细细体会一下)代码中 &arr 的类型是 int(*)[10] ,是一种数组指针类型数组的地址+1,跳过整个数组的大小,所以 &arr+1 相对于 &arr 的差值是40。
数组指针的使用:
访问数组中的元素,不但可以使用下标来进行访问,而且还可以使用指针来进行访问,代码示例如下:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
//使用下标进行访问
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
//使用指针来访问
int* p = arr;
for (i = 0; i < sz; i++)
{
printf("%d ", *(p + i));
}
//使用数组指针来访问,可以用,但是不推荐,有些复杂
int (*p)[10] = &arr;
for (i = 0; i < sz; i++)
{
printf("%d ", *((*p) + i));
}
return 0;
}
我们知道一维数组传参是,形参既可以写成数组也可以写成指针,代码示例如下:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
//一维数组传参,参数是数组
void print(int arr[10], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
//一维数组传参,参数是指针
void print(int arr[10], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", *(arr + i));//也可以写成 printf("%d ", arr[i]);
}
printf("\n");
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
print(arr, sz);
return 0;
}
通过一维数组的传参,而且有了数组指针的学习,二维数组除了将形参写为数组形式,其实也可以写为指针形式,代码示例如下:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
//二维数组传参,形参可写为二维数组
void print(int arr[3][5], int r, int c)
{
int i = 0;
for (i = 0; i < r; i++)
{
int j = 0;
for (j = 0; j < c; j++)
{
printf("%2d ", arr[i][j]);
}
printf("\n");
}
}
//二维数组传参,形参可写为数组指针
void print(int(*arr)[5], int r, int c)
{
int i = 0;
for (i = 0; i < r; i++)
{
int j = 0;
for (j = 0; j < c; j++)
{
printf("%2d ",*(*(arr+i)+j)); //*(arr+i)==arr[i]==&arr[i][j]
//也可写为arr[i][j]
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { 1,2,3,4,5, 6,7,8,9,10, 11,12,13,14,15 };
//数组名arr,表示首元素的地址
//但是二维数组的首元素是二维数组的第一行
//所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址
print(arr, 3, 5);
return 0;
}
代码运行结果如下:
感谢大家能够看完这篇博客,创作时长,小伙伴们觉得我的博客对你有帮助,不妨留下你的点赞的收藏,关注我,带你了解不一样的C语言。