高阶指针详解【C语言】

        一、指针的概念:

                        1. 指针就是个变量,用来存放地址,地址唯一标识一块内存空间。
                        2. 指针的大小是固定的4/8个字节(32位平台/64位平台)。
                        3. 指针是有类型,指针的类型决定了指针的+-整数的步长,指针解引用操作

                            的时候的权限。
                        4. 指针的运算。

        二、字符指针:

                1.字符指针的使用

在指针的类型中我们知道有一种指针类型为字符指针 char*
char*的使用一般有两种情况:

存储字符的地址

#include<stdio.h>

int main()
{
	char a = 'c';
	char* pa = &a;
	*pa = 'w';
	return 0;
}

存储字符串的首地址

#include<stdio.h>

int main()
{
	char* pc = "abcdef";
	printf("%s\n",pc);
	return 0;
}

                2.字符指针的存储方式

字符指针存储字符串(如"abcdef")时,不会存储所有字符的地址,只会存储字符串首元素的地址(例如:第二种存储方式,字符指针pc只会存储‘a’的指针)。

                3.存储数组和常量字符串的区别

有这样一个题

#include<stdio.h>

int main()
{
	char str1[] = "hello bit.";
	char str2[] = "hello bit.";
	const char* str3 = "hello bit.";
	const char* str4 = "hello bit.";
	if (str1 == str2)
		printf("str1 and str2 are same\n");
	else
		printf("str1 and str2 are not same\n");
	if (str3 == str4)
		printf("str3 and str4 are same\n");
	else
		printf("str3 and str4 are not same\n");
	return 0;
}

最后输出的结果是

可见字符指针存储数组首元素地址和存储常量字符串首地址是不一样的

分析:字符指针存储数组首元素地址时,由于每个数组都是一块独立的空间,所以数组指针存储的地址必然时不一样的,而常量字符串属于常量,在内存中是固定不变的,所以没有必要创建多份。所以指向同一个常量字符串时,指针都指向同一块空间。

        三、指针数组

指针数组就是存储数组的指针

定义为

#include<stdio.h>

int main()
{
	int a = 10;
	int b = 10;
	int* pa = &a;
	int* pb = &b;
	int* parr[10] = { pa,pb };

	return 0;
}

  数组名为parr, [10]表示这是一个数组,int*表示数组存储的是整形指针,(由于[ ] 的结合行比 * 高,所以[ ] 先与parr结合,确定了这是个数组)

        四、数组指针

 由上面的指针数组我们可以猜出,数组指针表示指向数组的指针

                1.定义形式

#include<stdio.h>

int main()
{
	int arr[10] = { 1,2,3,4,5 };
	int(*pa)[10] = &arr;

	return 0;
}

   p先和*结合,说明p是一个指针变量,然后指着指向的是一个大小为10个整型的数组。所以p是一个指针,指向一个数组,叫数组指针(这里将*与数组名括起来,保证pa先与*结合)

                2.&数组名和数组名的区别

除 sizeof(数组名) 和 &数组名 之外 数组名都是表示数组的首元素的地址

当我们运行这样一段代码时:

#include <stdio.h>
int main()
{
	int arr[10] = { 0 };
	printf("%p\n", arr);
	printf("%p\n", &arr);
	return 0;
}

 输出结果是:

可以看到打印出的地址是一样的

但是当我们给指针增加时

#include <stdio.h>
int main()
{
	int arr[10] = { 0 };
	printf("arr = %p\n", arr);
	printf("&arr= %p\n", &arr);
	printf("arr+1 = %p\n", arr + 1);
	printf("&arr+1= %p\n", &arr + 1);
	return 0;
}

运行结果是

从这次运行结果可以看出,&数组名和数组名在使用时情况是不同的。

                3.数组指针的使用

                

#include <stdio.h>
void print_arr1(int arr[3][5], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			printf("%d ", arr[i][j]);
		}
			printf("\n");
	}
}
void print_arr2(int(*arr)[5], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
}
int main()
{
	int arr[3][5] = { 1,2,3,4,5,6,7,8,9,10 };
	print_arr1(arr, 3, 5);
	//数组名arr,表示首元素的地址
	//但是二维数组的首元素是二维数组的第一行
	//所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址
	//可以数组指针来接收
	print_arr2(arr, 3, 5);
	return 0;
}

二维数组的首地址表示首元素的地址,也就是arr[1]的地址,也可以看成一个一维数组的地址,可以用数组指针接收, 可以解读成*(*(arr+i) +j),其中,arr+i找的是二维数组的第几行,+j找的是第几列的数据。

        五、函数指针

由之前的内容,我们可以推断,函数指针的主语是指针,所以函数指针表示的是指向函数的指针

        我们先看一段代码

#include <stdio.h>
void test()
{
	printf("hehe\n");
}
int main()
{
	printf("%p\n", test);
	printf("%p\n", &test);
	return 0;
}

        这段代码的结果是

 可以看出函数名就是函数的地址

那么我们要怎样存储呢?请看下面的代码。

void test()
{
	printf("hehe\n");
}

//下面pfun1和pfun2哪个有能力存放test函数的地址?
void (*pfun1)();
void* pfun2();

由前面数组指针的规则,我们可以猜测,指针名要先与 * 结合才表明是一个指针,所以pfun1是一个函数指针,有能力存放test函数,而存储的是函数,所以要有( ) 表明指向的是一个函数,函数的返回值是void

        六、函数指针数组

函数指针数组中心语是数组,是存放函数指针的数组

我们已经学习了指针数组

int* arr[10];
//数组的每个元素是int*

函数指针的数组该如何定义呢?下面哪一个是正确的定义

int (*parr1[10])();
int* parr2[10]();
int (*)() parr3[10];

答案是parr1

我们定义函数指针是

 要用一个数组来存储它,就是要pfun1先与 [ ] 先结合,来保证是一个数组

   

        七、回调函数

概念:回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。(即:函数不是直接调用,而是通过另一个函数使用函数指针来调用

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值