猿创征文|指针(C语言)

共分为以下八点

1.字符指针

2. 指针数组

3. 数组指针

4. 数组传参和指针传参

5. 函数指针

6. 函数指针数组

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

8. 回调函数

字符指针

int main()
{
    char ch = 'w';
    char* pc = &ch;//pc中存放着‘w’的地址
    *pc = 'w';
    char* p = "abcdef";//常量字符串是不允许修改的
    //只是把这个字符串中a的地址放到了p当中
    const char* p = "abcdef";//可以改为这样写
    return 0;
}
int main()
{
    char str1[] = "hello bit.";
    char str2[] = "hello bit.";//str1和str2分别存放着hello bit的首地址,地址是不同的
    const char* str3 = "hello bit.";
    const char* str4 = "hello bit.";//str3和str4都是不可修改的所以只需要存一份就可以了
    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;
}

输出结果:
在这里插入图片描述

指针数组

int* arr1[10]; //整形指针的数组
char *arr2[4]; //一级字符指针的数组
char **arr3[5];//二级字符指针的数组
int main()
{
	int arr1[5] = {1,2,3,4,5};
	int arr2[5] = {3,4,5,6,7};
	int arr3[5] = {6,7,8,9,0};
	int* arr[3] = {arr1,arr2,arr3};//用来存放指针的数组
	int i = 0;
	int j = 0;
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 5; j++)
		{
			printf("%d",arr[i][j]);
		}
		printf("\n");
	}
}

数组指针

数组指针是指针,指向数组的指针
int main()
{
	int arr[10] = { 1,2,3,4,5 };
	int (*p)[10] = &arr;//取出来的数组地址存放在p当中;
	//int(*)[10]为数组指针类型;
}

区分arr和&arr

int main()
{
	int arr[10] = {0};
	printf("%p\n",arr);
	printf("%p\n",&arr[0]);
	printf("%p\n",&arr);
}

输出结果:
在这里插入图片描述

int main()
{
	int arr[10] = {0};
	printf("%p\n",arr);
	printf("%p\n", arr+1);

	printf("%p\n",&arr[0]);
	printf("%p\n", &arr[0]+1);

	printf("%p\n",&arr);
	printf("%p\n", &arr+1);
}

输出结果:
猿创征文|指针(C语言)_第1张图片
俩个特殊:&arr和sizeof(arr)代表的是整个数组的地址

void print(int(*p)[5], int a, int b)
{
	int i = 0;
	for (i = 0; i < a; i++)
	{
		int j = 0;
		for (j = 0; j < b; j++)
		{
			printf("%d",*(*(p+i)+j));
		}
		printf("\n");
	}
}
int main()
{
	int arr[3][5] = { {1,2,3,4,5},{3,4,5,6,7},{6,7,8,9,0} };
	print(arr,3,5);
}

数组传参和指针传参

一维数组传参

#include
void test1(int arr[])//ture形参是数组
{}
void test1(int arr[10])//ture形参是数组
{}
void test1(int* arr)//ture形参是指针
{}
void test2(int* p[10])//ture形参是数组
{}
void test2(int** p)//ture形参是指针
{}
int main()
{
	int arr[10] = {0};
	int* p[10] = {0};
	test1(arr);
	test2(p);
	return 0;
}

二维数组传参

void test(int arr[3][5])//ture形参是数组
{}
void test(int arr[][])//err
{}
void test(int arr[][5])//ture形参是数组
{}
void test(int* arr[5])//err
{}
void test(int(*arr)[5])//ture形参是指针
{}
void test(int** arr)//err
{}
int main()
{
	int arr[3][5] = {0};
	test(arr);
	return 0;
}

一级指针传参

#include 
void print(int* p, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d\n", *(p + i));
	}
}
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;
}

思考:当一个函数的参数部分为一级指针的时候,函数能接收什么参数?

void test(int *arr)
{}
//三种情况:
int arr=0;
test(&arr);

int *p=&arr;
test(p);

int arr[3];
test(arr);

二级指针传参

#include 
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** arr)
{}
int main()
{
//三种情况:
	int* p[10];
	test(p);
	
	int** p = 0;
	test(p);
	
	int* p = 0;
	test(&p);
}

函数指针

数组与函数取地址

void Add(int a, int b)
{
}
int main()
{
	int arr[10] = {0};
	printf("%p\n", &arr);
	printf("%p\n",Add);
	printf("%p\n",&Add);
	return 0;
}

在数组当中&arr和arr之间是有区别的&arr是代表整个数组的地址而arr代表的是首元素地址,函数Add和&Add是一样的,都是函数的地址,没有区别。

int Add(int a, int b)
{
	return a + b;
}
int main()
{
	int (*p)(int a, int b) = &Add;//&可要可不要
	int sum = (*p)(3,5);//*可要可不要
	printf("%d",sum);
	return 0;
}

来分析两个有趣的代码

(*(void (*)())0)()//把0直接强转换为void (*)()类型的函数指针,然后去调用0地址处的函数
void(*signal(int,void (*)()))(int);
//上述代码是一次函数声明
//声明的函数叫:signal
//signal函数的第一个参数是int类型的
//signal函数的第二个参数是一个函数指针类型,该函数指针指向的参数是int返回类型是void
//signal函数的返回类型也是一个函数指针类型,该函数指针类型指向函数的参数是int,返回类型是void
//用简洁的的方式typedef
#typedef void(*pf_t)(int)
void(*signal(int,void (*)(int)))(int);
pf_t signal(int,pf_t)//代替后

函数指针数组

函数指针数组的作用就是用来存储多个函数指针用的

实现计算器
不用函数指针数组的做法

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("*********************************\n");
	printf("******* 1.add    2.sub     ******\n");
	printf("******* 3.mul    4.div     ******\n");
	printf("******* 0.exit             ******\n");
	printf("*********************************\n");
}
int main()
{
	int input = 0;
	menu();
	int a = 0;
	int b = 0;
	int ret = 0;
	do
	{
		printf("请选择》");
		scanf_s("%d", &input);
		switch (input)
		{
		case 1:
			printf("请输入两个数》");
			scanf_s("%d %d", &a, &b);
			ret = add(a, b);
			printf("%d\n", ret);
			break;
		case 2:
			printf("请输入两个数》");
			scanf_s("%d %d", &a, &b);
			ret = sub(a, b);
			printf("%d\n", ret);
			break;
		case 3:
			printf("请输入两个数》");
			scanf_s("%d %d", &a, &b);
			ret = mul(a, b);
			printf("%d\n", ret);
			break;
		case 4:
			printf("请输入两个数》");
			scanf_s("%d %d", &a, &b);
			ret=div(a, b);
			printf("%d\n",ret);
			break;
		case 0:
			printf("退出计算器\n");
			break;
		default:
			printf("选择错误\n");
		}
	} while (input);
}

使用函数指针数组的做法

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("*********************************\n");
	printf("******* 1.add    2.sub     ******\n");
	printf("******* 3.mul    4.div     ******\n");
	printf("******* 0.exit             ******\n");
	printf("*********************************\n");
}
int main()
{
	int input = 0;
	menu();
	int a = 0;
	int b = 0;
	int ret = 0;
	int (*pf_t[5])(int a, int b) = {0,add,sub,mul,div};
	do
	{
		printf("请选择》");
		scanf_s("%d", &input);
		if (input == 0)
		{
			printf("退出计算器");
			break;
		}
		if (input>=1&&input<=4)
		{
			printf("请输入两个数》");
			scanf_s("%d %d", &a, &b);
			ret = pf_t[input](a, b);
			printf("%d\n", ret);
		}
		else
		{
			printf("输入错误,请重新输入》\n");
		}
	} while (input);
}

指向函数指针数组的指针

int (*ptr[10])(int,int);//函数指针数组
int (*(*ph)[10])(int,int)=&ptr;//指向函数指针数组的指针

回调函数

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

实现计算器与上面的代码进行比较

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("*********************************\n");
	printf("******* 1.add    2.sub     ******\n");
	printf("******* 3.mul    4.div     ******\n");
	printf("******* 0.exit             ******\n");
	printf("*********************************\n");
}

void cals(int (*p)(int,int))
{
	int a = 0;
	int b = 0;
	int ret = 0;
	printf("请输入两个数》");
	scanf_s("%d %d", &a, &b);
	ret = p(a, b);
	printf("%d\n", ret);
}
int main()
{
	int input = 0;
	menu();
	do
	{
		printf("请选择》");
		scanf_s("%d", &input);
		switch (input)
		{
		case 1:
			cals(add);//这里使用了回调函数
			break;
		case 2:
			cals(sub);
			break;
		case 3:
			cals(mul);
			break;
		case 4:
			cals(div);
			break;
		case 0:
			printf("退出计算器\n");
			break;
		default:
			printf("选择错误\n");
		}
	} while (input);
}

qsort

qsort函数可以排列任意类型的数据
调用qsort函数形参

void qsort (void* base,//待排序数据起始位置的地址
              size_t num,//待排序数据个数
              size_t size,//待排序数据元素的大小(单位是字节)
            int (*comp)(const void*,const void*)//比较2个元素大小的函数指针
            );

先来了解一下void类型

int a=10;
void *p=&a;//void*是非常地宽容的,可以接受任意类型的地址
*p=20;//err是不能直接修改的
*(int*)p=20//ture
p++//err

测试qsort

#include
#include
int cmp_int(const void* e1, const void* e2)
{
	return (*(int*)e1 - *(int*)e2);//升序
	//降序为(*(int*)e2 - *(int*)e1);
}
void print(int arr[])
{
	int a = 10;
	for (int i = 0; i < a; i++)
	{
		printf("%d ",arr[i]);
	}
}
int main()
{
	int arr[10] = {2,3,1,4,5,7,6,8,0,9};
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_int);
	print(arr);
}

对结构体进行排序

#include
#include
#include
struct stu {
	char name[10];
	int age;
};
int cmp_stu_name(const void* e1, const void* e2)//对姓名排序,根据首字母的前后
{
	return strcmp(((struct stu*)e1)->name ,((struct stu*)e2)->name);
}
//int cmp_stu_age(const void* e1, const void* e2)//对年龄排序
//{
//	  return ((struct stu*)e1)->age-((struct stu*)e2)->age;
//}

void print(struct stu* s)
{
	for (int i = 0; i < 3; i++)
	{
		printf("%s\n", s[i].name);
	}
}
int main()
{
	struct stu s[] = { {"zhangsan",10},{"lisi",36},{"wangwu",24}};
	int sz = sizeof(s) / sizeof(s[0]);
	qsort(s, sz, sizeof(s[0]), cmp_stu_name);
	print(s);
}

输出结果
请添加图片描述

用冒泡排序的方法模拟实现qsort

排序结构体

#include
#include
#include
struct stu {
	char name[10];
	int age;
};
int cmp_stu_name(const void* e1, const void* e2)
{
	return strcmp(((struct stu*)e1)->name ,((struct stu*)e2)->name);
}

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 bubble_sort(void* base, int sz, int width, int (*cmp)(const void* e1, const void* e2))
{
	int i = 0;
	//趟数
	for (i = 0; i < sz - 1; i++)
	{
		//一趟冒泡排序的过程
		int j = 0;
		for (j = 0; j < sz - 1 - i; 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()
{
	struct stu s[] = { {"zhangsan",10},{"lisi",36},{"wangwu",24} };
	int sz = sizeof(s) / sizeof(s[0]);
	bubble_sort(s, sz, sizeof(s[0]), cmp_stu_name);
	print(s);
}

排序整数

int cmp_int(const void* e1, const void* e2)
{
	return (*(int*)e1 - *(int*)e2);//升序
}
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 bubble_sort(void* base, int sz, int width, int (*cmp)(const void* e1, const void* e2))
{
	int i = 0;
	//趟数
	for (i = 0; i < sz - 1; i++)
	{
		//一趟冒泡排序的过程
		int j = 0;
		for (j = 0; j < sz - 1 - i; 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[10] = {2,3,1,4,5,7,6,8,0,9};
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_qsort(arr, sz, sizeof(arr[0]), cmp_int);
	print(arr);
}

qsort函数使用快速排序实现的,而bubble_sort是通过冒泡排序实现的

最后:文章有什么不对的地方或者有什么更好的写法欢迎大家在评论区指出来。

你可能感兴趣的:(c语言,数据结构,算法)