[朝花夕拾C语言]:排序函数qsort详细讲解

目录

前言

一、整型的冒泡(bubble)排序

二、排序函数qsort的快捷使用

2.1函数qosrt的整型冒泡排序运用

2.2函数qosrt的浮点型冒泡排序运用

2.3函数qosrt的结构体(数字类型对比)冒泡排序运用

2.3函数qosrt的结构体(字符串类型对比)冒泡排序运用

三、sizeof()和strlen()的异同点

3.1 一维数组 和 字符数组 下的区别

3.2 字符串下的区别

3.3一维指针下的区别

总结


前言

提示:这里可以添加本文要记录的大概内容:

这篇文章是在学习完指针的进阶后,想对最近这一个星期的知识点做一个归纳与整理吧! 最近越发发现,好多知识还是要常进行相应的运用,实践出真知,代码不能只看视频课,还是要好好的理解与感悟,跟考研一样:千万不能有看完了==我就会了! 总感觉自己还有好多的知识都没有学,慢慢加油吧!

前面絮叨了好多,也是最近的一些感悟吧!这篇文章主要介绍

1.整型冒泡排序;

2.qsort函数对于排序捷运用,其中通过建立结构体指针,对相同的项进行比较;

3.对sizeof()和stelrn()的基本概念和基本运用的分析。


提示:以下是本篇文章正文内容,下面案例可供参考

一、整型的冒泡(bubble)排序

对于冒泡排序(bubble)这是一个比较经典的问题,我们首先来看其相应的代码片段:

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

void bubble_sort(int arr[], int sz)//需要两个函数形参进行接收
{
	int i = 0;
	for (i = 0; i < sz - 1; i++) //对要进行的数字进行相应的趟数排序
	{
		//一趟冒泡排序
		int j = 0;
         // j<=sz-1-i 第一次走完一遍后,再进行后面的比较和交换 
		for (j = 0; j < sz - 1 - i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int tmp = arr[j];
				arr[j] = arr[j + 1];//利用临时变量tmp,对两个数据进行交换
				arr[j + 1] = tmp;
			}
		}
	}
}

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

	int i = 0;

	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);

	}
	return 0;
}

通过上面的分析,我们可以很清楚的看到,利用bubble函数对数组里面的数据可以进行排序,但是,在没有进行指针的学习时,我们可能浅尝则止就差不多了,现在摆在我们面前的问题是:如果不是整型的变量,我们还可以进行排序嘛?

二、排序函数qsort的快捷使用

通过对上面问题的分析,我们必须要思考:有没有这种函数,改变类型后,但是仍然可以排序呢?

这时候:qsort就挺身而出了!

qsort可以进行以下的四个方面的排序:

1.整型的冒泡排序;

2.浮点数的排序

3.将结构体的元素利用年龄的大小进行排序

4..将结构体里面的字符串按照“a-z”的顺序排序

先来看一看qsort里面的基本参数:

qsort(arr, sz, sizeof(arr[0]), cmp_int);

这里面主要是有四个参数:1.待排序数组的首元素地址 2.待排序数组的个数 3.待排序数组的元素大小 4.要实现函数的函数指针(函数指针)

2.1函数qosrt的整型冒泡排序运用

首先,我们要分析需要的参数

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

int cmp_int(const void* e1, const void* e2)
{
	//比较两个整型元素的大小
	return (*(int*)e1 - *(int*)e2);//如果第一个的值比第二个小
}								  //则返回的是值为:-1


void test()
{
	int arr[10] = {9,8,7,6,5,4,3,2,1,0};
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_int);//所需要的四个参数分别进行对应!
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}

int main()
{


    return 0;
}

运行后,结果是:0 1 2 3 4 5 6 7 8 9 很显然,运行结果符合我们预期的想法。

2.2函数qosrt的浮点型冒泡排序运用

上面的整型我们介绍完了,下面说下浮点型的排序和运用:

#include <stdio.h>
#include <string.h>
int  cmp_float(const void* e1, const void* e2)
{
	//比较两个浮点型型元素的大小
	return  *(float*)e1 - *(float*)e2;//如果第一个的值比第二个小
}								      //则返回的是值为:-1

void test2()
{
	float f[] = { 9.0,8.0,7.0,6.0,5.0 };
	int sz = sizeof(f) / sizeof(f[0]);
	qsort(f, sz, sizeof(f[0]), cmp_float);//依然是四个参数
	int j = 0;
	for (j = 0; j < sz; j++)
	{
		printf("%f ", f[j]);
	}

}
int main()
{
	test2();//调用test2()函数
	return 0;
}

浮点数的排序结果是:

5.000000 6.000000 7.000000 8.000000 9.000000 和整型的运行结果一致!

return  *(float*)e1 - *(float*)e2;//如果第一个的值比第二个小 ,则返回的是值为:-1

                                                //如果第一个的值比第二个大 ,则返回的是值为:1

2.3函数qosrt的结构体(数字类型对比)冒泡排序运用

和上面的整型和浮点型的类型不同,结构体的比较,我们要找到相对应的类型进行比较,在此案例中,主要是利用年龄进行比较排序:

首先:要定义结构体:定义为 1.名字 2.年龄

struct stu//结构体的定义啊!
{
	char name[20];
	int age;

};

然后下面放一下代码为:
 

//用年龄进行比较
int cmp_stu_by_age(const void* e1, const void* e2)
{
	return ((struct stu*)e1)->age - ((struct stu*)e2)->age;

}

void test3()
{
	struct stu s[3] = { {"zs",20},{"ls",10},{"ww",15} };
	int sz = sizeof(s) / sizeof(s[0]);
	qsort(s,sz,sizeof(s[0]),cmp_stu_by_age);

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

在内存里面对其进行监视后,最终的结果是:

ls 10

ww 15

zs 20


2.3函数qosrt的结构体(字符串类型对比)冒泡排序运用

对原来的结构体里面的名字进行排序:主要是对“a-z”的字母按照顺序进行排序:

int cmp_stu_by_name(const void* e1, const void* e2)
{
	return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name);
		//名字的首字母进行比较
}
void test4()
{
	struct stu s[3] = { {"zs",20},{"ls",10},{"ww",15} };
	int sz = sizeof(s) / sizeof(s[0]);

	qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);

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

在内存里面对其进行监视后,最终的结果是:

ls 10

zs 20

ww 15

其实我们还可以用bubble对上述的字符进行排序,这路不再过多说明。

三、sizeof()和strlen()的异同点

区别:

1.sizeof()是一个单目运算符,而strlen()是一个库函数

2.sizeof()求的是数据类型所占的内存空间的大小,而strlen()求的是字符串的长度

3.strlen是求字符串的长度 要找到 \0 才能停止,找不到 \0 则会产生随机值!

3.1 一维数组 和 字符数组 下的区别

int main()
{
	//一维数组
	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));
	//sizeof(数组名)-计算的是数组的总大小 单位是字节 16
	printf("%d\n", sizeof(a + 0));
	// 4或8  表示的是首元素的值 a+0也是首元素的地址
	printf("%d\n", sizeof(*a));
	// 4 表示的是首元素 所以也是 4
	printf("%d\n", sizeof(a + 1));
	// 4 表示的是第二个元素的大小啊! 大小为4 
	printf("%d\n", sizeof(a[1]));
	//  4 仍然表示的是第二个元素的大小啊 !
	printf("%d\n", sizeof(&a));
	//4 虽然取出的是整个数组的地址 但是也是地址啊  所以是4
	printf("%d\n", sizeof(*&a));
	// 16  数组的地址进行相应的解引用 所以是 16 先取地址 然后数组的地址再解引用
	printf("%d\n", sizeof(&a + 1));
	// 4 仍然是一个地址哎! &a 是数组的地址  (&a+1)跳过整个地址 所以是4个字节 所以也是4 
	printf("%d\n", sizeof(&a[0]));
	// 4或者8 第一个元素的地址 看平台进行相应的决定
	printf("%d\n", sizeof(&a[0] + 1));
	// 4或者8  第二个元素的地址 


	//字符数组
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", sizeof(arr));
	//大小是 6
	printf("%d\n", sizeof(arr + 0));
	//地址是 4或者8 arr表示的是首元素的地址 (arr+0)表示的也是地址
	printf("%d\n", sizeof(*arr));
	//1  arr也是首元素的地址  *arr则表示首元素
	printf("%d\n", sizeof(arr[1]));
	// 1  第二个字符啊!
	printf("%d\n", sizeof(&arr));
	//4 &arr 虽然取出的是整个数组的地址 但是也是地址啊  所以是4
	printf("%d\n", sizeof(&arr + 1));
	//4  &arr+1 取地址进行加1 是跳过整个数组后的地址 所以还是4或者8
 	printf("%d\n", sizeof(&arr[0] + 1));
	// 4  取出第二个元素的地址 还是4


	//strlen是求字符串的长度 要找到 \0 才能停止

	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", strlen(arr));
	//随机值  是随机数   找不到 \0 的位置在哪里啊!!!
	printf("%d\n", strlen(arr + 0));
	//随机值 仍然是随机值 和上面一样啊! 
	printf("%d\n", strlen(*arr));
	// 报错 内存开始报错啊!这里本来需要的是首元素的地址啊! 'a'-97 非法访问啊!
	printf("%d\n", strlen(arr[1]));
	//报错 相当于 第二个元素 将‘b’-98传过去了! 所以仍然会报错!!!
	printf("%d\n", strlen(&arr));
	//随机值  从刚开始数 但是找不到 \0 在哪里啊!
	printf("%d\n", strlen(&arr+1));
	//随机值  从开始数+1  但是找不到 \0 在哪里啊!和上面的相差了一个 随机值-6!
	//和上面的两种情况是一样的!
	printf("%d\n", strlen(&arr[0]+1));
	//仍然是随机值  从 b 开始进行开始向后数 随机值-1

	return 0; 
}

3.2 字符串下的区别

int main()
{
	//字符串下的区别
	char arr[] = "abcdef";

	printf("%d\n", strlen(arr));
	//6 arr是从首元素的地址开始 一直向后取到\0 为止
	printf("%d\n", strlen(arr + 0));
	//6 和上面一样从a 开始进行取值啊!!
	//printf("%d\n", strlen(*arr));
	err *arr--a--97 是非法访问啊!
	//printf("%d\n", strlen(arr[1]));
	//err *arr--b--98 还是非法访问啊!!!!
	printf("%d\n", strlen(&arr));
	//6  &arr 取地址啊 数组的地址-数组指针 char(*p)[7]=&arr;
	printf("%d\n", strlen(&arr + 1));
	//随机 直接全部调完了!	 随机值啊 !!
	printf("%d\n", strlen(&arr[0] + 1));
	//5 从b的地址开始向后取到"\0" b c d e f 一共是5个字符!		



	printf("%d\n", sizeof(arr));
	//7 计算数组的大小 单位值字节 7*1=7 
	printf("%d\n", sizeof(arr + 0));
	// 4  还是首元素的大小
	printf("%d\n", sizeof(*arr)); 
	// 1  *arr是首元素 sizeof(*arr)计算首元素的大小
	printf("%d\n", sizeof(arr[1]));
	// 1 arr[1]是第二个元素的大小 sizeof(arr[1])是第二个元素
	printf("%d\n", sizeof(&arr));
	// 4或者8 算的是地址的大小  数组的地址也是地址
	printf("%d\n", sizeof(&arr + 1));
	//4 或者是 8  还是地址 &arr+1 是跳过整个数组后的地址 
	printf("%d\n", sizeof(&arr[0] + 1));
	//4 &arr[0]+1 第二个元素的地址 也就是相当于b的地址啊!
	return 0;
}

3.3一维指针下的区别

int main()
{
	//一维指针啊! 
	char* p = "abcdef";//p里面存的是a的地址

	printf("%d\n", strlen(p));
	//6 首先将a的地址传过去啊 a b c d e f 共计是6个
	printf("%d\n", strlen(p + 1));
	//5 从b的地址开始向后数啊
	printf("%d\n", strlen(*p));
	//error  *p--a--97
	printf("%d\n", strlen(p[0]));
	//error 和上面一样啊
	printf("%d\n", strlen(&p));
	//随机值啊!!
	printf("%d\n", strlen(&p + 1));
	//随机值啊!
	printf("%d\n", strlen(&p[0] + 1));
	//5 从b开始向后开始数啊!!!!


	//把常量字符串的a的地址放到p里面去了
	/*char* p = "abcdef";*///p 是一个指针只有4个字节的空间 
					   //根本放不下 后面的6个
	printf("%d\n", sizeof(p));
	//4  指针变量 计算指针变量p的大小 就是问地址的大小啊!
	printf("%d\n", sizeof(p + 1));
	//4  指针变量  原来是a的地址  p+1是字符b的地址  地址的大小是4或者8的大小
	printf("%d\n", sizeof(*p));
	//1 解引用 就是字符串的第一个字符啊!就是字符a
	printf("%d\n", sizeof(p[0]));
	//1	int arr[10]  arr[0]== *(arr+0)  p[0]== *(p+0)=='a';
	printf("%d\n", sizeof(&p));
	//4 取地址
	printf("%d\n", sizeof(&p + 1));
	//4 把原来的取地址+1  还是地址啊 最后还是地址啊!
	printf("%d\n", sizeof(&p[0] + 1));
	 //这是b的地址啊 地址啊 !!

	return 0;
}

3.4 二维数组下的区别

int main()
{
    //二维数组
	int a[3][4] = { 0 };//三行四列的元素全部是0

	printf("%d\n", sizeof(a));
	//48  12*4=48
	printf("%d\n", sizeof(a[0][0]));
	//4  第一个元素啊 是4 
	printf("%d\n", sizeof(a[0]));
	//16 4*4=16 将三行的元素当成a[0] a[1] a[2] 
	// a[0]相当于一维数组的数组名 计算第一行的大小
	printf("%d\n", sizeof(a[0] + 1));
	//尤其注意啊!!!!!
	// a[0]是第一行的数组名 数组名此时是
	//4 相当于计算第一行第2个元素的地址  
	printf("%d\n", sizeof(*(a[0] + 1)));
	//4  是第一行第二个元素 所以是4啊!
	printf("%d\n", sizeof(a + 1));
	//4  a是二维数组的数组名 没有sizeof(数组名) 也没有&(数组名)所以a是首元素的地址 
	//而二维数组看成一维数组时,则二维数组的首元素是其第一行 a是第一行(首元素)的地址
	//a+1 就是第二行的地址
	printf("%d\n", sizeof(*(a + 1)));
	//16 对第二行的数组进行相应的解引用 所以为4*4=16
	//计算第二行的大小啊!
	printf("%d\n", sizeof(&a[0] + 1));
	//4  应该是第二行的地址啊 
	//   取第一行的地址后 然后+1 就能得到第二行啊!
	printf("%d\n", sizeof(*(&a[0] + 1)));
	//16  解引用第二行的元素是4*4=16
	printf("%d\n", sizeof(*a));
	//16  a是首元素的地址--也是第一行的地址(把二维数组当成一维数组进行使用)  
	// 所以*a就是第一行的地址啊!
	//sizeof(*a)是第一行的元素啊!!!
	printf("%d\n", sizeof(a[3]));
	//16   相当于是第四行

	return 0;

}


总结

上述写了最近这一周的学习的知识点,学然后知其不足也!通过对:冒泡排序、qsort不同类型的运行和区别、对sizeof()和strlen()在不同类型下的打印值进行表述,加深理解!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值