【C语言】指针由浅入深全方位详解

指针定义

1. 指针是内存中一个最小单元的编号,也就是地址。

2. 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量。

3. 我们可以通过 &(取地址操作符) 取出变量的内存起始地址,把地址可以存放到一个变量中,这个变量就是指针变量。

4. 指针的大小在32位平台是4个字节,在64位平台是8个字节

int a = 100;
int * pa = &a; 
//*表示pa是指针变量。
//int表示 1.pa指向的类型是int 2.pa解引用的时候访问的对象大小是sizeof(int)。

 

指针类型

1. 指针类型可以决定指针解引用的时候访问多少个字节(指针的权限)

int* 的指针解引用访问4个字节。

char* 的指针解引用访问1个字节

2. 指针类型决定指针加1减1操作时的步长

整型指针+1跳过4个字节,字符指针+1跳过1个字节


 

野指针

1. 概念

野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)。

2. 野指针成因

//1.指针未初始化
int *p;//局部变量指针未初始化,默认为随机值
*p = 20;

//2.指针越界访问
 int arr[10] = {0};
 int *p = arr;
 int i = 0;
 for(i=0; i<=11; i++)
 {
     //当指针指向的范围超出数组arr的范围时,p就是野指针
     *(p++) = i;
 }

//3.指针指向的空间释放

3. 如何规避野指针? 

1.明确知道指针应该初始化为谁的地址就直接初始化,不知道的就初始化为NULL。

2.小心指针越界。

3.指针指向的空间释放后,及时置NULL。

4.避免返回局部变量的地址。

5.指针使用前检查有效性。


指针运算 

1. 指针加减整数

int arr[10] = {0};
int* p = &arr[0];
for(int i=0; i<sizeof(arr)/sizeof(arr[0]); i++)
{
    *p = i;
    p = p + 1; //指针加1,加一个sizeof(int)
}

p = arr;
for(int i=0; i<sizeof(arr)/sizeof(arr[0]); i++) { printf("&d ", *(p+i)); }

//*(p+i) == arr[i]
//*(arr+i) == arr[i] == *(i+arr) == i[arr]

2. 指针减指针 

int arr[10] = {0};
printf("%d\n", &arr[9] - &arr[0]); //等于9
//指针减指针的绝对值是指针和指针之间的元素个数
//指针和指针相减的前提是两个指针指向了同一块空间

3. 指针的关系运算 

1.地址是有大小的,指针的关系运算就是比较指针的大小

2.标准规定:允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。


函数指针数组

1. 类比

int* arr[5] //整型指针数组

char* arr[5] //字符指针数组

函数指针数组:数组的每个元素都是函数指针类型

2. 用函数指针实现计算器 

int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int mul(int a, int b) { return a * b; }
int div(int a, int b) { return a / b; }

void menu() { printf("0.exit, 1.add, 2.sub, 3.mul, 4.div\n"); }

int main()
{
	int (*pf_arr[])(int, int) = { NULL, add, sub, mul, div }; //函数指针数组,转移表
	int input, a, b;
	int sz = sizeof pf_arr / sizeof pf_arr[0];
	while (1)
	{
		menu();
		scanf("%d", &input);
		if (input == 0) break;
		else if (input > 0 && input <= sz)
		{
			scanf("%d %d", &a, &b);
			printf("%d\n", pf_arr[input](a, b));
		}
		else printf("input err\n");
	}

	return 0;
}

3. 指向函数指针数组的指针

指向函数指针数组的指针是一个指针,这个指针指向一个数组,这个数组的元素都是函数指针。 如何定义?

int (*pf)(int, int); //函数指针
int (*pf_arr[4])(int, int); //函数指针数组
int (*(*p_pf_arr)[4])(int, int) = &pf_arr; //函数指针数组的地址
//p_pf_arr就是指向函数指针数组的指针

回调函数

1. 什么是回调函数

回调函数就是一个通过函数指针调用的函数。

如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。

回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

2. 利用回调函数实现计算器 

int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int mul(int a, int b) { return a * b; }
int div(int a, int b) { return a / b; }

void menu() { printf("0.exit, 1.add, 2.sub, 3.mul, 4.div\n"); }

int Cal(int (*pf)(int, int))
{
	int a, b;
	scanf("%d %d", &a, &b);
	printf("%d\n", pf(a, b));
}

int main()
{
	int input = 1;
	while (input)
	{
		menu();
		scanf("%d", &input);
		switch (input)
		{
		case 0:
			break;
		case 1:
			Cal(add);
			break;
		case 2:
			Cal(sub);
			break;
		case 3:
			Cal(mul);
			break;
		case 4:
			Cal(div);
			break;
		}
	}

	return 0;
}

3. qsort函数

qsort函数特点:

1. 采用快速排序的方法

2. 适合任意类型数据的排序

.

qsort函数参数

void qsort(void* base, //指向需要排序的数组第一个元素

                 size_t num, //排序个数

                 size_t size, //一个元素的大小

                 int (*cmp)(const void*, const void*) //函数指针类型,指向的函数能比较base中元素

                );

.

qsort使用

//void*的指针可以接收任意类型的地址
//但是不能直接解引用和指针运算
//需要强制转换成对应类型
int cmp_int(const void* v1, const void* v2) { return *(int*)v1 - *(int*)v2; }

int main()
{
	int arr[] = { 2, 8, 9, 6, 4, 5, 1 };
	int sz = sizeof arr / sizeof arr[0];
	qsort(arr, sz, sizeof arr[0], cmp_int);

	return 0;
}

4. 利用冒泡排序的思想模拟实现qsort函数

冒泡排序:两两相邻的元素比较,不满足条件就交换

	//冒泡排序
int main()
{
	int arr[] = { 2, 8, 9, 6, 4, 5, 1 };
	int sz = sizeof arr / sizeof arr[0];
	int tmp;
	//需要比较sz-1趟
	for (int i = 0; i < sz - 1; i++)
	{
		//每一趟完成后少一个数 
		for (int j = 0; j<sz-1-i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}

	return 0;
}

模拟实现

问题1:第一个参数如何接收不同类型。

解决1:void*的指针解决并给出个数和每个的大小

问题2:不同类型元素比较方式可能不同

解决2:将两个元素的比较方法作为函数参数传递

问题3:不同的数据类型进行交换时不一样

解决3:利用char*一次只交换一个字节,循环目标字节大小次即可

//比较
int cmp_int(const void* v1, const void* v2) { return *(int*)v1 - *(int*)v2; }
//交换
void swap(char* p1, char* p2, int sz)
{
	char tmp;
	for (int i = 0; i < sz; i++)
	{
		tmp = *p1;
		*p1 = *p2;
		*p2 = tmp;
		p1++;
		p2++;
	}
}
//排序
void bubble_sort(void* base, int num, int sz, int (*cmp)(const void*, const void*))
{
	//冒泡思想
	for (int i = 0; i < num - 1; i++)
	{
		for (int j = 0; j < num - 1 - i; j++)
		{
			//不同类型比较方式不一样所以不能写死
			if (cmp((char*)base + j * sz, (char*)base + (j + 1) * sz) > 0)
			{
				//不同类型交换方式不一样所以不能写死
				swap((char*)base + j * sz, (char*)base + (j + 1) * sz, sz);
			}
		}
	}
}

int main()
{
	int arr[] = { 2, 8, 9, 6, 4, 5, 1 };
	int num = sizeof arr / sizeof arr[0];
	bubble_sort(arr, num, sizeof arr[0], cmp_int);

	return 0;
}

  • 14
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济体公布的最新数据,印度尼西亚2023年国内生产总值(GDP)增长5.05%;越南2023年经济增长5.05%;马来西亚2023年经济增速为3.7%;泰国2023年经济增长1.9%;新加坡2023年经济增长1.1%;柬埔寨2023年经济增速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总体GDP经济规模、贸易总额与国外直接投资均为最大,因此有着举足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元增长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济体受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步增长态势和强韧性的潜能。 本调研报告旨在深度挖掘东南亚市场的增长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整体市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导体产业链(半导体设备及零部件、半导体材料、集成电路、制造、封测、分立器件、传感器、光电器件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变器、电站终端)、新能源汽车产业链(动力电池及材料、电驱电控、汽车半导体/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元器件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机器人、激光、工控、无人机)、食品药品、医疗器械、农业等。邮箱:market@qyresearch.com

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值