C语言指针详解(有qsort模拟实现)

目录

指针?指针变量?

指针类型

指针类型的意义

野指针

成因

规避

指针与数组

二级指针

字符指针

指针数组?数组指针

函数指针

函数指针数组

指向函数指针数组的指针

回调函数


指针?指针变量?

指针就是地址,是内存中最小单元的编号 一个内存单元就是一个字节

指针变量是变量 用来存放地址的变量(口语可能说指针但自己要分清楚是变量还是地址)

指针大小在32位平台是4字节,在64位平台是8字节(地址线数量不同产生01序列的数量就不同所以造成4或8字节)

指针类型

变量有char,short,int,float,double等等不同类型那么指针有类型嘛?

答案是肯定的 举个例子

可以看到指针确实有类型,不同指针类型是为了存放不同类型变量的地址。

指针类型的意义

1.指针的解引用

指针的类型决定了,对指针解引用能操作几个字节

例:char*指针解引用访问一个字节,int*指针解引用访问四个字节

2.指针+-整数

指针类型决定了指针一步多大(距离)单位字节

野指针

成因

1.指针未初始化

2.指针越界

3.指针指向空间释放

规避

1.指针初始化

2.小心指针越界

3.指针指向空间释放置空

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

5.指针使用前判断是否为NULL

指针与数组

可以看到数组名和数组首元素的地址是相同的

结论:数组名表示首元素的地址(有两个例外)

1.sizeof(数组名)表示整个数组

2.&数组名 表示整个数组的地址

二级指针

 指针变量是变量,是变量就有地址,那么指针变量的地址就可以存放在指针中就产生了二级指针

字符指针

 要注意将字符串放到字符指针中本质是将字符串中首字符地址放到了字符指针中

指针数组?数组指针

我们首先区分二者

指针数组是数组,是存放指针的数组

数组指针是指针,是存放数组的指针

举个例子

int main()
{
	int *p1[10];//指针数组
	int(*pa)[10];//数组指针
	return 0;
}

首先我们要知道*与【】的优先级,【】高于*,所以可以看到int(*pa)[10]中*与pa结合pa是一个指针变量,指向的是一个大小为10个整型的数组所以是数组指针 

函数指针

存放函数地址的指针

 其中pf就是一个函数指针变量

注:函数名==&函数名  数组名!=&数组名

函数指针数组

 存放同类型的函数指针

int(*pfarr[2])(int, int);//函数指针数组

函数指针数组的用途:转移表 

指向函数指针数组的指针

 看起来很绕口怎么解释呢

指向函数指针数组的指针是一个指针

指针指向一个数组,数组元素都是函数指针

int main()
{
	int(*p)(int, int)=test;//函数指针
	int(*p2[3])(int, int);//函数指针数组
	p2[0] = test;
	int(*(*p3)[3])(int, int) = &p2;//函数指针数组指针
	return 0;
}

回调函数

通过函数指针调用函数

把函数的地址作为参数传参给一个函数,函数用函数指针接收来调用函数叫回调函数

 以上是实现qsort库函数的代码,其中就使用到了回调函数可以看一下实现过程

int cmp_int(const void* e1, const void*e2)
{
	return *(int*)e1 - *(int*)e2;
}
void print(int* arr, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}
void swap(char* s1, char* s2,int width)
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char tmp = *s1;
		*s1 = *s2;
		*s2 = tmp;
		*s1++;
		*s2++;
	}
}
bubble_sort(void* base, int sz, int width, int(*cmp)(const void* e1, const void*e2))
{
	int i = 0;
	int j = 0;
	for (i = 0; i < sz - 1; i++)
	{
		for (j = 0; j < sz -i -1; j++)
		{
			if (cmp((char*)base + j * width, (char*)base + (j + 1)*width) > 0)
			{
				swap((char*)base + j * width, (char*)base + (j + 1)*width, width);
			}
		}
	}
}
int main()
{
	int arr[] = { 9,8,7,6,5,4,3,2,1};
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);
	print(arr, sz);
	return 0;
}

排序用到的是冒泡排序,交换时每次交换一个字节数据也可以通过memcpy库函数实现交换一个元素的数据

void bubble_sort(void* base, int sz, int width, int(*cmp)(const void* e1,const void* e2) )
{
	int i = 0;
	int j = 0;
	char* st = (char*)base;
	char tmp[16];
	for (i = 0; i < sz - 1; i++)
	{
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (cmp(st + j * width, st + (j + 1)*width) >0)
			{
				memcpy(tmp, st + j * width,width);
				memcpy(st + j *width, st + (j+1) * width, width);
				memcpy(st + (j + 1)*width, tmp, width);//目标空间,起始空间,宽度
			}
		}
	}
}

 以上是我对于指针的总结主要是概念知识并没给出例题可以关注一下明天更新多道面试题详解!期待你的点赞求求了!!!会不断抽风跟新的哈哈哈哈

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值