“第二十七天” qsort函数,字符串函数

        qsort函数

可以排序任意类型的数据

这里的返回值是 e1-e2 ,在比较函数内部是先把无类型指针,转化成其原本的类型之后才操作的。

这里的返回值 e2-e1

结构数据排序

模拟qsort函数的实现,很不熟练,可以消化的点还是蛮多的,一个一个字节交换的那个循环再写一个函数好一点,还有用 flag 来判断原序列是否有序这个点感觉也很不错

#include <stdio.h>
//数据交换
void swap(char*buf1,char*buf2,int width) 
{
	int i = 0;
	char k = 0;
	for (i = 0;i < width; i++)
	{
		k = *buf1;
		*buf1 = *buf2;
		*buf2 = k;
		buf1++;
		buf2++;
	}
}
//模拟qsort函数的功能
void bubble_qsort(void* base,int sz,int width,int (*cmp)(const void* e1, const void* e2) )//注意最后函数指针变量cmp的位置
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		int j = 0;
		int flag= 1;//假设本来就是有序
		for (j = 0; j < sz - i - 1; j++)//这里要-1,不然会栈溢出,老是忘
		{
			if ( (*cmp) ( (char*)base+j*width, (char*)base+(j+1)*width )>0  )
//j*width是为了找到对应的地址,因为这里是不知道指针所指对象的类型的,但可以通过width跳过一个元素的字节,从而找到下一次元素的首地址
			{
			
				//int n = 0;
				//for (n = 0; n < width; n++)//这个循环也是因为不知道指向类型,所以就直接一个字节一个字节的进行交换了
				//{
				//	char k = *((char*)base + j * width + n);
				//	*((char*)base + j * width + n) = *((char*)base + (j + 1) * width + n);
				//	*((char*)base + (j + 1) * width+n) = k;
				//}
				flag = 0;//进入if语句了,表示顺序错误
			 }
		}
		if (flag)//如果第一次大循环就没有进入if语言,表示假设成立,数据有序,之后不再运行,break直接跳出循环
			break;
	}
}
//结构体
struct stu
{
	char name[20];
	int  age;
};
//比较函数
int cmp_stu_by_name(const void* e1, const void* e2)
{
	return  ((struct stu*)e1)->age - ((struct stu*)e2)->age;
}

int main()
{
	struct stu s[3] = { {"zhang",10},{"li",11},{"gao",12} };
	int sz = sizeof(s) / sizeof(s[0]);
	bubble_qsort(s,sz,sizeof(s[0]), cmp_stu_by_name);//头文件  stdlib.h 
	int i = 0;
	for(i=0;i<3;i++)
	{
		printf("%-7s %d\n", &s[i].name, s[i].age);
	}
	return 0;
}

        字符串函数

1、strlen          

sieze_t strlen (const char* str);

        字符串以 ' \0 ' 作为结束标志,strlen函数返回的是在字符串中 ‘ \0 ’ 前面出现的字符个数(不包括空白符)。

        参数指向的字符串必须要以 ' \0 ' 结束。

        注意strlen函数的返回值为size_t,是无符号整型.

模拟实现:

//1、计数器方法
int my_strlen1(char* arr)
{
	int count = 0;
	while (*arr != '\0')
	{
		count++;
        arr++;
	}
	return count;
}
//2、指针-指针
int my_strlen2(char* arr)
{
	char* beg = arr;
	while (*arr != '\0')
	{
		arr++;
	}
	return arr - beg;
}
//3、递归的方式
int my_strlen3(char* arr)
{
	if (*arr != '\0')
		return 1 + my_strlen3(arr+1);
	else
		return 0;
}
int main()
{
	char arr[] = "abcdef";
	int ret = my_strlen1(arr);
	printf("%d\n", ret);
	ret = my_strlen2(arr);
	printf("%d\n", ret);
	ret = my_strlen3(arr);
	printf("%d\n", ret);
	return 0;
}

2、strcmp     

char* strcpy (char* destination,const char* source);

        strcpy函数是有返回值的,返回的是目标的首地址

        再次提醒,字符串是有值的,值是首字符的地址,下面这个也间接说明的了,strcpy会拷贝空白符。

        源字符串必须以 ' \0 ' 结束;

        会将源字符串中的 ' \0 ' 拷贝到目标空间;

        目标空间必须足够大,以确保能存放源字符串;这里实际上也会运行,但会报错,应该是栈溢出。

        目标空间必须可变;

 这个就是属于目标空间不可变的情况,p指向的是常量a的地址,而常量是没有办法修改的。

模拟实现strcpy

#include <assert.h>
//普通版
char* my_strcpy1(char* dest,const char* src)//因为源字符串不需要改变,所以可以用 const 修饰一下,防止意外情况
{
	char* ret = dest;//保留首地址,用以返回
	while (*src != '\0')
	{
		*dest = *src;
		dest++;
		src++;
	}
	*dest = *src;//这里是赋值 '\0' ;
	return ret;
}
//高级版
char* my_strcpy2(char* dest, const char* src)
{
	assert(dest && src);//防止空指针
	char* ret = dest;
	while (*dest++=*src++)//这里的判断条件是被赋值后的*dest,之所以可以作为判断条件是因为 \0 也要赋值,赋值之后*dest的值就变成 0 ,然后退出循环
	{
		;
	}
	return ret;
}
int main()
{
	char arr[20] = { 0 };
	my_strcpy1(arr, "abcdef");
	printf("%s\n", arr);
	my_strcpy2(arr, "abcdefgh");
	printf("%s\n", arr);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值