BIT-2-指针的进阶


指针的主题,我们在初级阶段的《指针》章节已经接触过了,我们知道了指针的概念:

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

1.字符指针

在指针的类型中我们知道有一种指针类型为字符指针char*;
一种使用“变量指针”

int main()
{
    char ch = 'w';
    char *pc = &ch;
    *pc = 'w';
    return 0;
}
``
** ”常量指针“**

```c
int main()
{
    const char* pstr = "hello bit.";//这里是把一个字符串放到pstr指针变量里了吗?
    printf("%s\n", pstr);
    return 0;
}

“hello bit”是一个常量,地址在常量区,不在栈区,所以不可以改变,而变量指针是把一个常量赋值到一个变量中,再把变量地址赋给指针变量。
那就有可这样的面试题:

#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;
}

注意:在栈区一定是新占一个空间;所以每个变量地址不同;
str3和str4是常量指针,所以二者存的都是常量区的“hello bit”的地址;

2.指针数组

在《指针》章节我们也学习了指针数组,指针数组是存放指针的数组。
在这里插入图片描述
例题
使用指针数组来模拟二维数组
在这里插入图片描述

3.数组指针

3.1 数组指针的定义

数组指针是指针?还是数组?
答案是:指针。
下面代码哪个是数组指针?

int *p1[10];
int (*p2)[10];
//p1, p2分别是什么?

p1是指针数组,而p2是数组指针;可以发现:数组指针比指针数组多加了一个()。

3.2 &数组名VS数组名

在这里插入图片描述
数组名和&数组名的区别:
指针类型不同:
arr:int *pa 指针变量
&arr:int(*pa)[10] 数组指针;
两者数值相同但是两者加一的数值加的比一样;

3.3 数组指针的使用
3.3.1示例一

在这里插入图片描述

3.3.2示例二,二维数组

在这里插入图片描述

4. 数组参数、指针参数

4.1 一维数组传参

在这里插入图片描述

4.2 二维数组传参

在这里插入图片描述
终结
数组传参都有数组型和指针型。

4.3 一级指针传参

在这里插入图片描述
思考
当一个函数的参数部分为一级指针的时候,函数能接收什么参数?
在这里插入图片描述

4.4 二级指针传参
#include <stdio.h>
void test(int** ptr)
{
 printf("num = %d\n", **ptr); 
}
int main()
{
 int n = 10;
 int*p = &n;
 int **pp = &p;
 test(pp);
 test(&p);
 return 0;
}

思考:
当函数的参数为二级指针的时候,可以接收什么参数?

在这里插入图片描述

5. 函数指针

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

在这里插入图片描述
由此可以看出函数名字是函数的地址;
函数指针如何写
举例:
在这里插入图片描述
**但是使用时函数指针不需要用”*“;
因为:函数本来就用的是地址;

5.1例题
5.1.1
//代码1
(*(void (*)())0)();

在这里插入图片描述

5.1.2
//代码2
void (*signal(int , void(*)(int)))(int);

在这里插入图片描述

6. 函数指针数组

把函数的地址存到一个数组中,那这个数组就叫函数指针数组。

//例子:
int(*pa[10])(int,int)

用途
示例:
计算器
1.使用函数数组的方法:

#include<stdio.h>
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 mune()
{
	printf("************************\n");
	printf("*******1.add,2,sub******\n");
	printf("*******3.mul,4.div******\n");
	printf("*******0.退出***********\n");
}
int main()
{
	int a = 0, b = 0;
	int (*pa[5])(int, int) = { 0,add,sub,mul,div };
	int input;
	int ret = 0;
	do
	{
		mune();
		scanf("%d", &input);
		if (input>=1&&input<=4)
		{
			printf("输入操作数: ");
			scanf("%d %d", &a, &b);
			ret = pa[input](a,b);

		}
		else if(input==0)
		{
			printf("退出");
		}
		else
		{
			printf("输入错误");
		}
		printf("ret=%d\n", ret);

	} while (input);
	return 0;
}

在这里插入图片描述
2.使用分支语句的方法:
在这里插入图片描述

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

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

在这里插入图片描述
加指针就加一个()和
加数组就在名字后加【】
*

8.回调函数

在这里插入图片描述
这里使用上面的代码进行解释;
在这里插入图片描述
使用回调函数的方法;
在这里插入图片描述
介绍qsort函数
该函数是一个排序函数;
根据前面的知识我们知道冒泡法,等排序法;
出现qsport函数的原因:
在这里插入图片描述
对于冒泡法排序的类型是固定的,大大影响了代码的效率;
qsort的定义
在这里插入图片描述
注意:qsort的底层算法是快速算法;
举例
1.整形排序
在这里插入图片描述
对于正常情况下qsort是将排序后是以升序来排列;
如果想要呈现降序:可以把p1p2的位互换;
2.字符型排序
在这里插入图片描述
3.结构体排序

struct Ps
{
	char name[20];
	int age;
};
int  cmp_stu_by_name(const void * p1, const void* p2)
{
	return strcmp(((struct Ps*)p1)->name, ((struct Ps*)p2)->name);
}

void test()
{
	struct Ps arr[] = { {"zhangsan",30},{"lisi",25},{"wangwu",50} };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
    printf("%s %s %s", arr->name, (arr + 1)->name, (arr + 2)->name);
}
int main()
{
	test();

	return 0;
}

在这里插入图片描述

使用冒泡法模拟可以排序任何类型序列的冒泡法;
功能和psort相同;

int cmp(const void* p1, const void* p2)
{
	return *((int*)p1) - *((int*)p2);
}
void Swap(char* buf1, char* buf2, int width)
{
	int i = 0  ;
	for (i = 0; i < width; i++)
	{
		char tmp = *buf1;
		*buf1 = *buf2;
		*buf2 = tmp;
		buf1++;
		buf2++;

	}
}
void buble_sort(void* base, int num, int width, int(*cmp)(const void*p1,const void*p2))//size_t是无符号整形
{
	size_t i = 0;
	for (i = 0; i < num-1; i++)
	{
		int flag = 1;
		size_t j = 0;
		for (j = 0; j < num - 1 - i; j++)
		{
			if (cmp((char*)base+j*width,(char*)base+(j+1)*width)>0)
			{
				flag = 0;
				Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
		   }
			
		}
		if (flag == 1)
		{
			break;
		}
	}
}
void test()
{
	int s[] = { 3,1,2,4,5,6,7,8,9,10 };
	int sz = sizeof(s) / sizeof(s[0]);
	//使用冒泡法模拟一个可以随意选择类型的冒泡法(通用冒泡法);
	buble_sort(s, sz, sizeof(s[0]), cmp);
}






int main()
{
	test();

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值