一、指针和数组
区别:
指针可以申请一块内存当作数组使用 数组直接定义使用
相同点:
1#include<stdio.h>
2int main()
3{
4 int arr[4] = { 0,1,2,3 };
5 int *temp = arr;
6 //arr[1]和*(arr+1)等效
7 printf("arr[1]:%d\n*(temp+1):%d", *(arr + 1),temp[1]);
8 return 0;
9}
不同点:
注意:
在解释指针数组和数组指针之前先来解释下数组的存储结构
1//定义一个二维数组
2int a[3][4] = { { 1,3,5,7 },{9,11,13,15},{17,19,21,23} };
那么它的存储结构如下图:
a[0]是a[ 0 ] [ 0 ]的地址,也是a数组的首地址
同理,a[1]是a[ 1 ] [ 0 ]的地址,a[2]是a[ 2 ] [ 0 ]的地址
指针数组:存放指针的数组 本质是数组,数组元素是指针
1int* arr[3]; //指针数组 10个int*
1#include<stdio.h>
2int main()
3{
4 int arr[3][4] = { { 1,3,5,7 },{9,11,13,15},{17,19,21,23} };
5 int *p[3];
6 for(int i=0;i<3;i++)
7 {
8 p[i] = arr[i]; //指针数组指向二维数组每行的首地址
9 }
10 //输出指针数组指向的数组
11 for (int i = 0; i < 3; i++)
12 {
13 for (int j = 0; j < 4; j++)
14 printf("%d\t", p[i][j]);
15 putchar(10); //换行
16 }
17 return 0;
18}
也称行指针表示方法:int(*p)[n] 数组指针:指向一个整型的一维数组,这个一维数组的长度是n
1#include<stdio.h>
2int main()
3{
4 int arr[3][4] = { { 1,3,5,7 },{ 9,11,13,15 },{ 17,19,21,23 } };
5 int(*p)[4] = arr; //指针数组指向数组arr
6 //打印指针数组指向的值
7 for (int i = 0; i < 3; i++)
8 {
9 for (int j = 0; j < 4; j++)
10 printf("%d\t", *(*(p + i) + j)); //printf("%d\t",p[i][j]);
11 putchar(10);
12 }
13 getchar();
14 return 0;
15}
1在这里我想解释下为什么 *(*(p + i) + j)) 和 p[i][j] 等价;
2指针数组的表示方法:int(*p)[n]
3p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n;
4n也可以说是p的步长,也就是说执行p+1时,p要跨过n个整型数据的长度。
5
6*(p+i) == p[i] == &p[i][0] == arr[i] == &arr[i][0] (==是等价的意思)
7*(*(p + i) + j) == *(p[i] + j) == p[i][j]
8
9在数组的存储结构里就是第i行的第j个元素
指向指针的指针,称为 二级指针
任何数据都有地址,一级指针的值虽然是地址,但是这个地址做为一个数据也需要空间来存放,而二级指针就是就是来存储这个地址的。
1#include<stdio.h>
2int main()
3{
4 int a = 10;
5 int *p = &a;
6 int **pp = &p;
7 printf("&a:%p\np:%p\n*pp:%p\n**pp:%d\n", &a, p, *pp, **pp); //%p打印地址
8 return 0;
9}
打印结果:
1&a:000000B0CB1EF964
2p:000000B0CB1EF964
3*pp:000000B0CB1EF964
4**pp:10
1二级指针的一次解引用 *pp 得到所指向一级指针的地址,也就是p的值
2
3二级指针的两次解引用 **pp 得到所指向一级指针指向的值 也就是a的值
二级指针可以直接访问二维数组吗?答案当然是不行的,那么如何访问二维数组呢?
通过指针数组间接访问数组
1#include<stdio.h>
2int main()
3{
4 int arr[3][4] = { { 1,3,5,7 },{9,11,13,15},{17,19,21,23} };
5 int *p[3];
6 for (int i = 0; i < 3; i++)
7 {
8 p[i] = arr[i]; //指针数组指向二维数组
9 }
10 int **pp = p; //二级指针指向指针p
11 for (int i = 0; i < 3; i++)
12 {
13 for (int j = 0; j < 4; j++)
14 printf("%d\t", pp[i][j]);
15 putchar(10); //换行
16 }
17 return 0;
18}
返回值为指针的函数,本质是一个函数,而该函数的返回值是一个指针
例如 malloc() 函数,或者自定义的函数如:
1int* add(int x,int y);
所谓的指针函数也没什么特别的,和普通函数相比就是指针函数返回一个指针
指向函数的指针
1int (*p)(int x, int y);
1#include<stdio.h>
2int add(int x, int y)
3{
4 return x + y;
5}
6int main()
7{
8 int (*p)(int x, int y); //定义函数指针
9 p = add; //函数指针p指向函数add
10 printf("第一种方法:%d\n第二种方法:%d", (*p)(1, 2), p(2, 3));//函数指针的两种调用方法
11 return 0;
12}
根据传参类型分类
1//函数原型
2void fun(int x);
3//函数调用
4fun(a);
1//函数原型
2void fun(int* p);
3//函数调用
4fun(&a);
一维数组:int arr[3];
1//函数原型
2void fun(int* p);
3void fun(int arr[]); //推荐这种,让人一看就知道你要传的是数组
4//函数调用
5fun(arr);
二维数组:int arr[3] [3];
1//函数原型
2void fun(int(*p)[3]);
3void fun(int[][3]); //行省略,列不能省略
4//函数调用
5fun(arr);
指针数组:int*p[3];
1//函数原型
2void fun(int* p[3]);
3void fun(int** p);
4//函数调用
5fun(p);
函数名:add();
1#include<stdio.h>
2void add()
3{
4 printf("调用add()函数");
5}
6void fun(void(*p)())
7{
8 p(); //通过函数地址调用add函数
9}
10int main()
11{
12 fun(add);//函数地址作为实参
13 return 0;
14}
可以思考下为什么要把一个函数的地址作为参数传递给另一个函数,要知道在C语言中,一个函数内部是可以直接调用其他函数的,既然可以直接调用,为什么还要用这么麻烦的办法去把函数当做参数来传递呢。
上一篇:指针(一)