C语言--指针进阶3

前言

        在上篇我们学习了回调函数的经典案例qsort,今天,我们将尝试模拟实现qsort

1.模拟实现qsort 函数

        qsort是C语言中的一个库函数,它是基于快速排序算法实现的一个排序函数,qsort函数最大的特点就是它可以排任意类型的数据。

使用方法如下:

#include <stdlib.h>
void qsort(void* base, //待排序数组的第一个元素的地址
	       size_t num, //待排序数组的元素个数
	       size_t size,//待排序数组中一个元素的大小
	       int (* cmp)(const void* e1, const void* e2)//函数指针-cmp指向了一个函数,这个函数是用来比较两个元素的
         //e1和e2中存放的是需要比较的两个元素的地址
          );

现在我们将基于冒泡排序算法实现qsort函数 :

代码(升序):

#include<stdio.h>
#include <string.h>
void print_arr(int arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}
int cmp(const void* e1, const void* e2)
{
	return *(int*)e1 - *(int*)e2;
}
void temp(char* a1, char* a2, size_t size)
{
	for (int i = 0; i < size; i++)
	{
		char temp1 = *a1;
		*a1 = *a2;
		*a2 = temp1;
		a1++;
		a2++;
	}
}
void bubble_sort(void* base, size_t num, size_t size,int (*cmp)(const void*e1,const void*e2))
{
	for (int i = 0; i < num - 1; i++)
	{
		for (int j = 0; j < num - 1 - i; j++)
		{
			if (cmp((char*)base +j*size,(char*)base +(j+1)*size)>0)
			{
				temp((char*)base + j * size, (char*)base + (j + 1) * size, size);
			}
		}
	}
}
void test1()
{
	int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz, sizeof(arr[0]),cmp);
	print_arr(arr, sz);
}
int main()
{
	test1();
	test2();
	return 0;

}

 运行结果:

代码解析: 

        可以看到我将base转化成了char*类型,为什么这么做呢?

如果想做到和qsort一样,可以排序任意类型的数据,那就要想办法接收任意类型,那char*类型的指针就再适合不过了,char*每移动一步就跳过一个字节,那么所接收的类型有及字节跳过几字节就行了,列如,int(4字节),那我们就只需要跳过4个字节就好了。

        所以可以写成(char*)base +j*size。

 同样的我们看到temp函数,在实现数组成员的交换时,也是一个一个字节去交换的。

2.sizeof与strlen中与指针相关的问题

这类问题会在面试题中出现,是很重要的类容。做这种题时,要知道两个前提。

关于数组名的理解,数组名是数组首元素的地址,但有两个例外:

        1.sizeof(数组名),这里的数组名表示整个数组,sizeof(数组名)计算的是整个数组的大小,单位是字节。

        2.&数组名,这里的数组名表示整个数组,&数组名取出的是数组的地址。

sizeof示例:

int main()
{
	//一维数组
	int a[] = { 1,2,3,4 };
	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof(a + 0));
	printf("%d\n", sizeof(*a));
	printf("%d\n", sizeof(a + 1));
	printf("%d\n", sizeof(a[1]));
	printf("%d\n", sizeof(&a));
	printf("%d\n", sizeof(*&a));
	printf("%d\n", sizeof(&a + 1));
	printf("%d\n", sizeof(&a[0]));
	printf("%d\n", sizeof(&a[0] + 1));
	
	return 0;
}

解释:

    //一维数组
    int a[] = { 1,2,3,4 };//4个元素,每个元素使int类型(4个字节)

    printf("%d\n", sizeof(a));//16,数组名a单独放在sizeof内部,数组名表示整个数组,计算的是整个数组的大小单位是字节,是16字节
    printf("%d\n", sizeof(a + 0));//a并非单独放在sizeof内部,也没有&,所以数组名a是数组首元素的地址,a+0还是首元素的地址
    //是地址大小就是4/8 Byte

    printf("%d\n", sizeof(*a));//a并非单独放在sizeof内部,也没有&,所以数组名a是数组首元素的地址
    //*a 就是 首元素,大小就是4Byte  //*a == *(a+0) == a[0]

    printf("%d\n", sizeof(a + 1));//a并非单独放在sizeof内部,也没有&,所以数组名a是数组首元素的地址,a+1就是第二个元素的地址
    //a+1 == &a[1]  是第2个元素的地址,是地址就是4/8个字节

    printf("%d\n", sizeof(a[1]));//a[1]就是数组的第二个元素,这里计算的就是第二个元素的大小,单位是字节 - 4

    printf("%d\n", sizeof(&a));//&a - 是取出数组的地址,但是数组的地址也是地址,是地址就是4/8个Byte
    //数组的地址 和 数组首元素的地址 的本质区别是类型的区别,并非大小的区别
    //a  -- int*             int * p = a;
    //&a -- int (*)[4]       int (*p)[4] = &a;
    
    printf("%d\n", sizeof(*&a));//16   对数组指针解引用访问一个数组的大小,单位是字节
    //sizeof(*&a) --- sizeof(a) //16

    printf("%d\n", sizeof(&a + 1));//&a数组的地址,&a+1表示跳过整个数组,但还是地址,是地址就是4/8个字节


    printf("%d\n", sizeof(&a[0]));//&a[0]是首元素的地址, 计算的是地址的大小 4/8 个字节
    printf("%d\n", sizeof(&a[0] + 1));//&a[0]是首元素的地址,&a[0]+1就是第二个元素的地址,大小4/8个字节

strlen示例:

int main()
{
	char arr[] = { 'a','b','c','d','e','f' };
	printf("%d\n", strlen(arr));
	printf("%d\n", strlen(arr + 0));
	printf("%d\n", strlen(*arr));
	printf("%d\n", strlen(arr[1]));
	printf("%d\n", strlen(&arr));
	printf("%d\n", strlen(&arr + 1));
	printf("%d\n", strlen(&arr[0] + 1));
	return 0;
}

解释:

    char arr[] = { 'a','b','c','d','e','f'};//6
    //strlen是找'\0',没找到就出随机值
    printf("%d\n", strlen(arr));//随机值,arr是首元素的地址
    printf("%d\n", strlen(arr + 0));//随机值,arr是首元素的地址, arr+0还是首元素的地址
    printf("%d\n", strlen(*arr));//err,arr是首元素的地址, *arr就是首元素 - 'a' - 97
    //站在strlen的角度,认为传参进去的'a'-97就是地址,97作为地址,直接进行访问,就是非法访问
    printf("%d\n", strlen(arr[1]));//err, 'b' - 98
    printf("%d\n", strlen(&arr));//随机值
    //&arr -- char (*)[6]
    //const char*
    printf("%d\n", strlen(&arr + 1));//随机值
    printf("%d\n", strlen(&arr[0] + 1));//随机值

        

おすすめ

転載: blog.csdn.net/2301_76618602/article/details/132882357