0
点赞
收藏
分享

微信扫一扫

【C进阶】two -> 指针进阶(二)

萨摩斯加士奇 2022-03-21 阅读 65
c语言

前言


 ⭐往期真集

【C进阶】【C进阶】 one -> 数据的存储
【C进阶】【C进阶】two -> 指针进阶

 

先复习下上节课讲的内容 

目录

⭐前言⭐

※※※大家好!我是同学〖森〗,一名计算机爱好者,今天让我们进入学习模式。若有错误,请多多指教。

 ⭐往期真集⭐

四、数组参数和指针参数

1、一维数组传参

2、二维数组传参

 3、一级指针传参

4、二级指针传参

五、函数指针

六、函数指针数组 

 函数指针数组的应用(计算器)

七、指向函数指针数组的指针

八、回调函数

用回调函数简化计算器代码冗余 

 qsort函数

完整代码 


聪明的你能不能分清楚上面的数组(指针)是那种类型? 


四、数组参数和指针参数

1、一维数组传参

#include<stdio.h>

int mian()
{
    int arr1[10];
    int *arr2[10];
    
    test1(arr1);
    test2(arr2);
    return 0;
}

如以上代码,函数test1的形参该怎么写呢?用来打印一维数组。

提示:函数传参即test1、test2传的是数组首元素的地址。 

void test1(int arr[10])    //1
{}

void test1(int arr[])       //2
{}

void test1(int arr[100])    //3
{}

void test1(int *pa)    //4
{}

举一反三

那么test2的形参的两种表达方式你会了吗? 

void test2 (int *arr2[20])    //1
{}

void test2 (int *(*pb))    //2
{}

 和你想的一样吗?

再多说一句:2的(*pb)表示pb是一个指针。int *表示指针指向的内容是int *型的。 就是二级指针。

现在的你能不能区分数组的地址和数组搜元素的地址的区别呢?

不会的话就看看小主以前的内容复习回顾下吧!3.2、&数组名VS数组名


2、二维数组传参

#include<stdio.h>
int main()
{
    int arr[3][5];
    
    test(arr);
    return 0;
}

如上所示,test函数的形参该怎么写?test函数用来打印一维数组。

void test(int arr1[3][5])    //1
{}

void test(int arr1[][5])    //2
{}

void test(int arr1[3][])    //3
{}

void test(int arr1[][])    //4
{}
void test(int *arr5)    
{}
void test(int* arr6[5])    
{}
void test(int (*arr7)[5])    
{}
void test(int **arr8)   
{}

那如果一个二维数组 int arr[3][5];   实参是arr和&arr有什么区别呢?

#include<stdio.h>
void test1(int(*pa)[5])
{

}

void test2(int(*pb)[3][5])
{

}
int main()
{
	int arr[3][5];
	test1(arr);	//传的是第一行的地址。即行地址。
	test2(&arr);//传的是整个二维数组的地址。即面地址。
	return 0;
}

 3、一级指针传参

#include<stdio.h>
int main()
{

 int arr[10] = {1,2,3,4,5,6,7,8,9};
 int *p = arr;
 int sz = sizeof(arr)/sizeof(arr[0]);

 //一级指针p,传给函数
 print(p, sz);

 return 0;
 }

 print函数怎么写?打印数组。

void print(int *p, int sz) 
{
 int i = 0;
 for(i=0; i<sz; i++)
 {
     printf("%d\n", *(p+i));
 }
}

和你写的代码一样吗?十分简单,小主就不在多唠叨了。


 那我们反过来想的话。如果函数的形参有了,那么都能传什么 呢?

void test1(int *p)
{}
//test1函数能接收什么参数?

你还会想到什么情况呢?


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

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

void test(int **p)
{}

五、函数指针

有多少小伙伴会一头雾水地问道:什么?函数还有指针 

由数组指针我们可以推测出是指向函数的指针

#include <stdio.h>

void test()
{
     printf("你好,中国\n");
}

int main()
{
 printf("%p\n", test);
 printf("%p\n", &test);

 return 0; 

}

输出的结果是

 既然我们知道了函数指针,那么怎么定义函数指针变量呢?

函数指针的使用: 

#include<stdio.h>

int Add(int x, int y)
{
	return x + y;
}

int main()
{
	int m = 0, n = 0;
	int(*p)(int, int) = Add;    //定义并赋值函数指针变量
	printf("请输入两个整数:");
	scanf("%d%d", &m, &n);
	int ret = (*p)(m, n);        //函数指针变量的使用
	printf("%d", ret);
	return 0;
}

 欣赏下列两个代码

//代码1 

( * (void (*) () ) 0)();

//代码2

void (*signal(int, void(*)(int)))(int);

六、函数指针数组 

#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}

int Sub(int x, int y)
{
	return x - y;
}

int Mul(int x, int y)
{
	return x * y;
}

int Div(int x, int y)
{
	return x / y;
}

int main()
{
	int m = 0, n = 0;
	printf("请输入两个整数:");
	scanf("%d%d", &m, &n);
	若用函数指针变量
	//int(*pa)(int, int) = Add;
	//int(*pb)(int, int) = Sub;
	//int(*pc)(int, int) = Mul;
	//int(*pd)(int, int) = Div;

	//那我们用函数指针数组呢?

	int(*p[4])(int, int) = { Add,Sub,Mul,Div };
	for (int i = 0; i < 4; i++)
	{
		int ret = p[i](m, n);    //p[i]相当于是函数名

		printf("%d\n", ret);
	}

	return 0;
}

运行结果

 函数指针数组的应用(计算器)

#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int Sub(int x, int y)
{
	return x - y;
}
int Mul(int x, int y)
{
	return x * y;
}
int Div(int x, int y)
{
	return x / y;
}


void menu()
{
	printf("**************************\n");
	printf("****  1.add   2.sub   ****\n");
	printf("****  3.mul   4.div   ****\n");
	printf("****  0.exit          ****\n");
	printf("**************************\n");
}
int main()
{
	int input = 0;
	int x = 0;
	int y = 0;
	int ret = 0;

	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("请输入2个操作数:>");
			scanf("%d%d", &x, &y);
			ret = Add(x, y);
			printf("ret = %d\n", ret);
			break;
		case 2:
			printf("请输入2个操作数:>");
			scanf("%d%d", &x, &y);
			ret = Sub(x, y);
			printf("ret = %d\n", ret);
			break;
		case 3:
			printf("请输入2个操作数:>");
			scanf("%d%d", &x, &y);
			ret = Mul(x, y);
			printf("ret = %d\n", ret);
			break;
		case 4:
			printf("请输入2个操作数:>");
			scanf("%d%d", &x, &y);
			ret = Div(x, y);
			printf("ret = %d\n", ret);
			break;
		case 0:
			printf("退出计算器\n");
			break;
		default:
			printf("选择错误\n");
			break;
		}
	} while (input);

	return 0;
}

运行结果

int main()
{
	int input = 0;
	int x = 0;
	int y = 0;
	int ret = 0;

	//转移表
	int (*pfArr[])(int, int) = {0, Add, Sub, Mul, Div};

	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		if (input == 0)
		{
			printf("退出计算器\n");
		}
		else if(input >= 1 && input<=4)
		{
			printf("请输入2个操作数:>");
			scanf("%d%d", &x, &y);	
			ret = pfArr[input](x, y);
			printf("ret = %d\n", ret);
		}
		else
		{
			printf("选择错误\n");
		}

	} while (input);

	return 0;
}

 我们可以发现实现相同的功能,用转移表就会简化很多。

就是把用户的选择数字和函数指针数组的下标相结合。


七、指向函数指针数组的指针

怎么定义? 

 

 

 

 

 

 注意:p3的大小也是4/8字节。


八、回调函数

 

如上:print_hehe  就是回调函数。 

用回调函数简化计算器代码冗余 

#include<stdio.h>

int Add(int x, int y)
{
	return x + y;
}

int Sub(int x, int y)
{
	return x - y;
}

int Mul(int x, int y)
{
	return x * y;
}

int Div(int x, int y)
{
	return x / y;
}

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

void calc(int (*pf)(int,int))
{
	int x = 0;
	int y = 0;
	int ret = 0;

	printf("请输入2个操作数:>");
	scanf("%d%d", &x, &y);
	ret = pf(x, y);
	printf("ret = %d\n", ret);
}

int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			calc(Add);
			break;
		case 2:
			calc(Sub);
			break;
		case 3:
			calc(Mul);
			break;
		case 4:
			calc(Div);
			break;
		case 0:
			printf("退出计算器\n");
			break;
		default:
			printf("选择错误\n");
			break;
		}
	} while (input);

	return 0;
}

 qsort函数

qsort函数的应用 

#include<stdio.h>

//要和qsort要求的类型相合 
//int (*compar)(const void*,const void*)
int C_int(const void* e1, const void* e2)	
{
	//void*类型的指针不能解引用,也不能+1;
	if (*(int*)e1 > *(int*)e2)	
		return 1;
	else if (*(int*)e1 < *(int*)e2)
		return -1;
	if (*(int*)e1 == *(int*)e2)
		return 0;

}

void test()
{
	int arr[] = { 5,4,3,2,1, };
	int sz = sizeof(arr) / sizeof(arr[0]);    //求数组元素的多少

	qsort(arr, sz, sizeof(arr[0]), C_int);
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}
int main()
{
	test();
	return 0;
}

运行结果:

 排序结构体

#include<stdio.h>

struct Stu
{
	char name[20];
	int age;
	double score;
};

int cmp_stu_by_name(const void* e1, const void* e2)
{
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}

int cmp_stu_by_age(const void* e1, const void* e2)
{
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}

void test1()
{
	struct Stu arr[3] = { {"zhangsan", 20, 55.5},{"lisi", 30, 88.0},
                          {"wangwu", 10, 90.0} };
	int sz = sizeof(arr) / sizeof(arr[0]);
	//qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
	qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
}

int main()
{
	test1();
	return 0;
}

克隆qsort函数

void Swap(char* p1, char* p2, size_t width)
{
	size_t i = 0;
	for (i = 0; i < width; i++)	//逐个字符地替换
	{
		char tem = *p1;
		*p1 = *p2;
		*p2 = tem;
		p1++;
		p2++;
	}
}

void qsort_1(void* base, size_t num, size_t width, int(*cmp)(const void* e1, const void* e2))
{
	size_t i = 0, j = 0;
	for (i = 0; i < num - 1; i++)	//冒泡排序
	{
		j = 0;
        //升序排列
		for (j = 0; j < num - 1 - i; j++)
		{
			//因为base是void类型指针,要强制类型转换为char型
			if (cmp((char*)base + j * width,
				(char*)base + (j + 1) * width) > 0)	//比较大小
			{
				//交换函数
				Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
			}
		}
	}
}

完整代码 

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

struct Stu
{
	char name[20];
	int age;
	double score;
};

//打印整数数组
void print_arr(int arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}

//打印结构体数组
void Print(struct Stu arr[], int sz)
{
	for (int i = 0; i < sz; i++)
	{
		printf("%s %d %.2lf\n", arr[i].name, arr[i].age, arr[i].score);
	}
}


//qsort函数的比较大小函数,第四个函数参数
int cmp_int(const void* e1, const void* e2)
{
	return (*(int*)e1 - *(int*)e2);
}


//结构体按年龄比较大小
int cmp_stu_by_age(const void* e1, const void* e2)
{
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}

//结构体按姓名比较大小
int cmp_stu_by_name(const void* e1, const void* e2)
{
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}

//数据对调
void Swap(char* p1, char* p2, size_t width)
{
	size_t i = 0;
	for (i = 0; i < width; i++)	//逐个字符地替换
	{
		char tem = *p1;
		*p1 = *p2;
		*p2 = tem;
		p1++;
		p2++;
	}
}

//克隆qsort
void qsort_1(void* base, size_t num, size_t width, int(*cmp)(const void* e1, const void* e2))
{
	size_t i = 0, j = 0;
	for (i = 0; i < num - 1; i++)	//冒泡排序
	{
		j = 0;
		for (j = 0; j < num - 1 - i; j++)
		{
			//因为base是void类型指针,要强制类型转换为char型
			if (cmp((char*)base + j * width,
				(char*)base + (j + 1) * width) > 0)	//比较大小
			{
				//交换函数
				Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
			}
		}
	}
}

//整数排序测试
void test1()
{
	int arr1[] = { 9,8,7,6,5,4,3,2,1,0 };
	int arr2[] = { 9,8,7,6,5,4,3,2,1,0 };
	//排序为升序

	int sz1 = sizeof(arr1) / sizeof(arr1[0]);
	int sz2 = sizeof(arr2) / sizeof(arr2[0]);
	printf("整数排序测试:\n原数组排列顺序:\n");
	print_arr(arr1, sz1);

	printf("qsort函数升序排列\n");
	qsort(arr1, sz1, sizeof(arr1[0]), cmp_int);
	print_arr(arr1, sz1);

	printf("克隆qsort函数升序排列\n");
	qsort_1(arr2, sz2, sizeof(arr2[0]), cmp_int);
	print_arr(arr2, sz2);

	printf("\n");
}

//结构体排序测试
void test2()
{
	struct Stu arr1[3] = { {"zhangsan", 20, 55.5},{"lisi", 30, 88.0},{"wangwu", 10, 90.0} };
	struct Stu arr2[3] = { {"zhangsan", 20, 55.5},{"lisi", 30, 88.0},{"wangwu", 10, 90.0} };

	int sz1 = sizeof(arr1) / sizeof(arr1[0]);
	int sz2 = sizeof(arr2) / sizeof(arr2[0]);

	printf("结构体排序测试:\n原数组排列顺序:\n");
	Print(arr1, sz1);

	printf("\nqsort函数按年龄升序排列\n");
	qsort(arr1, sz1, sizeof(arr1[0]), cmp_stu_by_age);
	Print(arr1, sz1);

	printf("\n克隆qsort函数按年龄升序排列\n");
	qsort_1(arr2, sz2, sizeof(arr1[0]), cmp_stu_by_age);
	Print(arr2, sz2);

	printf("\nqsort函数按名字升序排列\n");
	qsort(arr1, sz1, sizeof(arr1[0]), cmp_stu_by_name);
	Print(arr1, sz1);

	printf("\n克隆qsort函数按名字升序排列\n");
	qsort(arr2, sz2, sizeof(arr2[0]), cmp_stu_by_name);
	Print(arr2, sz2);
}

int main()
{
	test1();
	test2();

	return 0;
}

测试结果

 

举报

相关推荐

0 条评论