c语言指针进阶2--回调函数

回调函数qsort模拟实现

这里不使用快排, 使用冒泡排序模拟实现qsort

冒泡排序排序数组使其升序

void bubble_sort(int* arr, int sz){
    for (int i=0; i<sz-1; i++) {
        for (int j=0; j<sz-1-i; j++) {
            if(arr[j]>arr[j+1]){
                int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = arr[j];
            }
        }
    }
}

中间交换的功能封装在函数swap中

void swap(int* a, int* b){
    int temp = *a;
    *a = *b;
    *b = temp;
}

void bubble_sort(int* arr, int sz){
    for (int i=0; i<sz-1; i++) {
        for (int j=0; j<sz-1-i; j++) {
            if(arr[j]>arr[j+1]){
                swap(&arr[j], &arr[j+1]);
            }
        }
    }
}

模拟定义qsort

首先是参数, 

​
void bubble_sort(void* base, size_t num, size_t size, int sz){

​

还需要compare函数

​
void bubble_sort(void* base, size_t num, size_t size, int (*compare)(const void*, const void*))

​

最后一个参数*compare为函数指针,指向compare函数, 函数类型为int  (const void*, const void*)

比较函数

 if(arr[j]>arr[j+1]){

将这一段替换为compare

因为compare函数参数为const void* ,为指针类型,存储的地址,那么,将原来起始位置的地址跳跃到size处的地址,将里面的值取出来, 因为char*的指针每次跳一个字节,char*指针类型本来位置的base加上j个size, 也就是j*size, ,跳这么多的地址,将其中的值取出来比较

代码如下

 if(compare((char*)base+j*size, (char*)base+(j+1)*zise))

那么同理, swap交换函数也应该是参数为char*垃圾桶指针(在if中的compare函数参数也转换为了char*), 里面的交换中间类型为char*, 有多少字节交换多少次(char*每次跳一个字节), 那么交换size次

void swap(char* a, char* b, size_t size){
    for (int i=0; i<size; i++) {
        char temp = *a;
        *a = *b;
        *b = temp;
        a++;
        b++;
    }
}

自定义的比较函数


int compare_arr(const void* a, const void* b){
    return *(int*)a - *(int*)b;
}

为什么有两个指针呢,因为参数传的是指针,就是地址,强转为(int*)类型的指针后, 再试用*解引用

if(compare((char*)base+j*size, (char*)base+(j+1)*size)){
                swap((char*)base+j*size, (char*)base+(j+1)*size, size);
            }

且qsort中的compare函数

返回值<0, 那么让p1在p2前面,此处我们是使用前者的值减去后者的值p1-p2<0, 那么p1<p2

因此想实现升序, 当返回值大于0时才执行交换函数就能模拟此处的功能了

if(compare((char*)base+j*size, (char*)base+(j+1)*size)>0){
                swap((char*)base+j*size, (char*)base+(j+1)*size, size);
            }

swap传参

使用模拟实现的qsort函数实现结构体排序

最终代码


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

struct Stu {
    char name[20];
    int age;
};

void swap(char* a, char* b, size_t size){
    for (int i=0; i<size; i++) {
        char temp = *a;
        *a = *b;
        *b = temp;
        a++;
        b++;
    }
}

int compare_arr(const void* a, const void* b){
    return *(int*)a - *(int*)b;
}

int compare_by_name(const void* a, const void* b){
    return strcmp(((struct Stu*)a)->name, ((struct Stu*)b)->name);
}
int compare_by_age(const void* a, const void* b){
    return ((struct Stu*)a)->age - ((struct Stu*)b)->age;
}

void bubble_sort(void* base, size_t num, size_t size, int (*compare)(const void*, const void*)){
    for (int i=0; i<num-1; i++) {
        for (int j=0; j<num-1-i; j++) {
            if(compare((char*)base+j*size, (char*)base+(j+1)*size)>0){
                swap((char*)base+j*size, (char*)base+(j+1)*size, size);
            }
        }
    }
}

void print(int* arr, int sz){
    for (int i=0; i<sz; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

void print_stu(struct Stu* p, int sz){
    for (int i=0; i<sz; i++) {
        printf("%s %d\n", p[i].name, p[i].age);
    }
    printf("\n");
}

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

void test2(void){
    struct Stu arr[] = {{"lihua", 20}, {"ahua", 39}, {"bhua", 30}};
    int sz = sizeof(arr)/sizeof(arr[0]);
    print_stu(arr, sz);
//    bubble_sort(arr, sz, sizeof(arr[0]), compare_by_name);
    bubble_sort(arr, sz, sizeof(arr[0]), compare_by_age);
    print_stu(arr, sz);
}

int main(int argc, const char * argv[]) {
//    test1();
    test2();
    return 0;
}

指针和数组笔试题解析

一维数组

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));
  1. sizeof(a)

    //4*4 = 16 数组名单独放在sizeof内部, 数组名表示整个数组 计算的是整个数组的大小, 单位是字节

  2. sizeof(a+0)

    // 4/8 数组名并非单独放在sizeof内部 没有& 所以数组名表示首元素地址, 那么a+0仍然是首元素地址,是地址大小就是4/8字节(32位是4,64位是8)

  3. sizeof(*a)

    // 4BYTE a并非单独放进sizeof, 也没有&,所以数组名是数组首元素的地址, 解引用后是数组首元素,即*a == *(a+0) == a[0] ,因此是一个int字节大小, 为4字节

  4. sizeof(a+1)

    //4/8 a并非单独放在sizeof内部,也没有&, 所以数组名是数组首元素的地址, 是地址就是4/8Byte, 这里a+1指向a[1], 即*(a+1) == a[1]

  5. sizeof(a[1])

    // a[1]就是数组的第二个元素,是int类型,4字节

  6. sizeof(&a)

    // &数组名表示整个数组地址, 是地址就是4/8字节

  7. sizeof(*&a)

    // &数组名表示取出的是数组的地址, 解引用表示整个数组的大小,也就是等价于sizeof(a),相当于单独放在sizeof中,即为16

  8. sizeof(&a+1)

    // 取地址数组名,表示取出整个数组的地址,+1以后就是指向数组最后一个元素后面的一个地址,仍然是地址4/8Byte

  9. sizeof(&a[0])

    // 取地址a[0], 把数组首元素的地址取出来, 是地址,就是4/8Byte

  10. sizeof(&a[0]+1)

    //取地址数组首元素,往后+1一位,也就是找到了a[1]的地址,地址是4/8Byte

字符数组

sizeof字符数组

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

    // 数组名arr单独放在sizeof内部, 计算的是整个数组的大小, 单位是字节, 6*1 = 6

  2. sizeof(arr+0)

    // 数组名不是单独放在arr中, 表示首元素地址,加0表示首元素地址, 相当于&a[0] ,也就是地址,地址就是4/8Byte

  3. sizeof(*arr)

    // 解引用数组名, 数组名表示首元素地址,解引用是arr[0]的值,sizeof(char类型)就是1Byte

  4. sizeof(arr[1])

    // sizeof一个数组元素,一个char类型大小,1Byte

  5. sizeof(&arr)

    // 数组名加上取地址, 表示取出整个数组的地址,是地址就是4/8By瑞特

  6. sizeof(&arr+1)

    //&数组名往后+1, 也就是在'\0'地址后面一个,但是终究是地址, 地址就是4/8字节

  7. sizeof(&arr[0]+1)

    // 对数组首元素取出地址,往后+1,移动char*个单位, 指向arr[1], 是arr[1]的地址,但是仍然是地址,就是4/8Byte

strlen字符数组

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));
  1. strlen(arr)

    //strlen求字符串长度, 就是统计'\0'之前的字符数, 但是arr数组没有结束字符, arr单独放在strlen中, 表示首元素的地址, 没有结束字符就是>=6的随机值

  2. strlen(arr+0)

    // 随机值, arr+0, arr是首元素的地址, arr+0是首元素的地址, arr+0还是首元素的地址

  3. strlen(*arr)

    // err 对于strlen函数 它的定义是 size_t strlen(const char* a) 参数是指针, 传值是指针,这段直接解引用操作, 传参是字符a, - 97, 97作为地址,直接进行访问,就是非法访问

  4. strlen(arr[1])

    // 同理 传参b字符,- 98, 非法访问

  5. strlen(&arr)

    // 取出整个数组的地址, 类型是strlen (*)[6],类型不同于const char*,会报警告⚠️, 但是仍然能正常执行,因为这个数组地址其实也是从第一个数组元素地址开始的 是随机值

  6. strlen(&arr+1)

    取地址往后数,也就是数组最后一个元素后面的地址,也是随机值

  7. strlen(&arr[0]+1)

    取出首元素的地址, 往后一位,也是随机值,比前前面也就是5的随机值少1

数组--字符串类型

char arr[] = "abcdef";
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));
char arr[] = "abcdef";

// a b c d e f \0

//0 1 2 3 4 5 6 

  1. sizeof(arr)

    //arr表示整个数组 就是7个元素(包括\0)

  2. sizeof(arr+0)

    //不是单独的arr 表示首元素地址往后一位,就是地址4/8Byte

  3. sizeof(*arr)

    //arr解引用,表示取出首元素使用, 就是arr[0] 即char类型的大小,为1Byte\

  4. sizeof(arr[1])

    //类似于3

  5. sizeof(&arr)

    //取出数组的地址,只要是地址就是4/8Byte

  6. sizeof(&arr+1)

    // 取出首元素的地址后移一位, 仍然是地址

  7. sizeof(&arr[0]+1)

    // 取出首地址元素后移一位, 也是地址

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值