C语言指针进阶视频笔记②

这篇博客详细介绍了C语言中数组和指针作为参数传递的各种形式,包括一维数组、二维数组、一级指针和二级指针。同时,解释了回调函数的概念,并通过示例展示了如何使用函数指针调用函数。此外,还讨论了`qsort`函数的工作原理,并给出了不同类型的数组(整型、浮点型和结构体)的快速排序示例。最后,基于`qsort`的原理,实现了自定义的`my_qsort`函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.一维数组传参

 void test1(int arr[])
 {}
 void test1(int arr[10])
 {}
 void test1(int*arr)
 {}
 void test2(int*arr[])
 {}
 void test2(int **arr)
 {}
int main()
{
  int arr1[10]={0};
  int*arr2[10]={0};
  test1(arr1);
  test2(arr2);
  return 0;
}
 

①int arr[]/int arr[10]:可以直接使用相同类型的数组直接接收,可以定义接收的数组大小或不定义

②int*arr:因为传的实参是数组首元素的地址,所以形参可以用指针接收

③int*arr[]:因为test2传的实参是指针数组,所以形参用相同类型的int*arr[]接收

④int**arr:因为test2传的实参是指针数组的首元素地址(指针的地址),所以可以用二级指针int**接收

2.二维数组传参

 void test(int arr[][5])//行可以省略,但是列不能省略
 void test(int(*arr)[5])//arr可以理解为存放每一行的首元素地址,[5]则是有多少列

 3.一级指针传参
 传一级指针则用一级指针接收则可
 
 4.二级指针传参
 传二级指针则用二级指针接收则可

5.回调函数!!

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

 void Cala(int(*p)(int,int))//用*p接收Add函数的地址,所以函数Cala是回调函数
                            //Cala通过函数指针接收Add的地址,调用Add函数
 {}
int main()
{ Cala(Add);//将Add函数地址传过去
    return 0;
}

补充: void*类型的指针可以接收任意类型的地址
            不能进行解引用操作
            不能进行加减整数的操作 

例:qsort函数:quick sort快速排序

格式:

void qsort(void*base,//数组起始元素地址
            size_t nitems,//数组元素个数
            size_t size,//数组每个元素的大小
            int(*compar)(const void*e1,const void*e2))

对比每个元素的大小的函数
 如果compar返回值小于0( < 0),那么p1所指向元素会被排在p2所指向元素的前面
如果compar返回值等于0( = 0),那么p1所指向元素与p2所指向元素的顺序不确定
如果compar返回值大于0(> 0),那么p1所指向元素会被排在p2所指向元素的后面

运用:int类型的数组进行快速排序

#include<stdio.h>
#include<stdlib.h>
int compar(const void* e1, const void* e2)
{
	//不能对e1 e2直接进行解引用,要强制类型转换为传参的数组的类型的指针后再进行解引用
	return (*(int*)e1 - *(int*)e2);
}
int main()
{
    int arr[]={5,2,6,7,3,1,9};
    int sz=sizeof(arr)/sizeof(arr[0]);
    qsort(arr,sz,sizeof(arr[0]),compar);//该compar函数要自己定义,返回类型必须是int类型
    for(int i=0;i<sz;i++)
    {
        printf("%d",arr[i]);
    }
    return 0;
}

浮点类型数组的快速排序

#include<stdio.h>
#include<stdlib.h>
int compar(const void* e1, const void* e2)
{
	//如果直接用return *(float*)e1-*(floar*)e2;的话,返回类型是float类型,而函数类型是int,会报 
                                                                               //错
	//解决 1.将返回类型转换为int:    return (int)(*(float*)e1-*(floar*)e2)
	//2.
	if ((*(float*)e1 - *(float*)e2) == 0)
		return 0;
	if ((*(float*)e1 - *(float*)e2) > 0)
		return 1;
	if ((*(float*)e1 - *(float*)e2) < 0)
		return -1;
}
int main()
{
	float f[] = { 4.00,3.00,2.00,6.00,5.00,8.00 };
	int sz = sizeof(f) / sizeof(f[0]);
	qsort(f, sz, sizeof(f[0]), compar);
	for (int i = 0; i < sz; i++)
	{
		printf("%f ", f[i]);
	}
	return 0;
}

结构体类型的快速排序

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
struct Stu
{
	int age;
	char name[20];
};
int int_compar_name(const void* e1, const void* e2)
{
	//比较名字就是比较字符串
	//字符串比较不能直接用><=符号来比较,应该用strcmp函数
	//int strcmp(const char *str1, const char *str2)  引头文件<string.h>
	//返回值
	/*该函数返回值如下:

		如果返回值小于 0,则表示 str1 小于 str2。
		如果返回值大于 0,则表示 str1 大于 str2。
		如果返回值等于 0,则表示 str1 等于 str2。*/
	return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
int int_compar_age(const void* e1, const void* e2)//排序年龄
{
	return *(int*)e1 - *(int*)e2;
}
int main()
{
	
	static Stu s[3] = { {12,"holle"},{11,"bit"},{15,"world"} };
	int sz = sizeof(s) / sizeof(s[0]);
	qsort(s, sz, sizeof(s[0]), int_compar_age);
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", s[i].age);
	}
    printf("\n");
	qsort(s, sz, sizeof(s[0]), int_compar_name);
    for (int i = 0; i < sz; i++)
	{
		printf("%d ", s[i].name);
	}
	return 0;
}

对于qsort函数的实现原理进行分解,实现my_qsort函数

//my_qsort函数的实现
#include<stdio.h>
int comper(void* e1, void* e2)
{
	return *(int*)e1 - *(int*)e2;
}
void Sap(char* e1, char* e2, int width)//传width的目的是给定交换上界,因为类型是char*,
                                  //交换时是一个字节一个字节的交换,所以要给定宽度防止交换越界
{
	for (int i = 0; i < width; i++)
	{
		char a = *e1;
		*e1 = *e2;
		*e2 = a;
		e1++;
		e2++;
	}
}

void my_qsort(void* base, int sz, int widh, int(*comper)(void* e1, void* e2))
//编辑该函数的程序员并不知道调用该函数的人传的是什么类型的参数,所以用void
{
	//冒泡排序原理
	for (int i = 0; i < sz - 1; i++)
	{
		for (int j = 0; j < sz - 1 - i; j++)
		{
			//对比大小
			if (comper((char*)base+widh*j,(char*)base+widh*(j+1))>0)
                                         //传过来的为首元素的地址,
                                         //为void*类型,要强制类型转换
				                       //但如果强制类型转换为int*类型,
                                       //如果传结构体时加整数时跳跃的字节不清楚,
                                       //不能精准的找到下一个元素进行比较
				                       //所以用char*类型进行强制类型转换,
                                       //加整数时跳的就是该整数的字节
				                      //加上宽度时就能准确的找到下一个元素的地址,
                                       //宽度增大就能继续找到下下个元素的地址了

			{
				//交换
				Sap((char*)base + widh * j, (char*)base + widh * (j + 1),widh);
			}
		}
	}
}
int main()
{
	int arr[] = { 9,5,6,2,4,6,3,8,1 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	my_qsort(arr, sz, sizeof(arr[0]),comper );
	for (int j = 0; j < sz; j++)
	{
		printf("%d ", arr[j]);
	}
	return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值