比特指针进阶

本文介绍了回调函数的概念,以qsort函数为例展示了如何对整形、字符串及结构体数据进行排序。同时,通过示例解释了指针与数组的关系,以及如何使用指针实现冒泡排序。此外,文中还探讨了sizeof运算符在不同情况下的行为,以及在处理字符串和二维数组时的注意事项。
摘要由CSDN通过智能技术生成

回调函数

通过函数指针调用的函数。把函数指针作为参数传递给另一个函数,这个指针被用来调用其指向函数。

qsort函数

快速排序

  • 整形数据

  • 字符串数据

  • 结构体数据

void qsort(void* base,size_t num,size_t size,int (*compar)(const void*,const void*) )

base

pointer to the first object of the array to be sorted,converted to a void*. //待排序数据中第一个对象的地址

num

待排序数据元素个数

size

排序数据中每个元素大小,单位是字节

compar

排序方法函数,比较待排序数据中2个元素的函数,返回+,交换,返回0或-,不换
//使用qsort函数排序结构体数据
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
struct stu { char *name;int age;}s[3]={ {"zhangsan",30},{"lisi,34},{"wangwu",20} };
int sort_age(const void* e1,const void* e2)
{
    return ((struct stu *)e1)->age-(*(struct stu *)e2)->age;
}
int sort_name(const void* e1,const void* e2)
{
    return strcmp(((struct stu*)e1->name,((struct stu*)e2)->name);
}
int main()
{
    int sz = sizeof(s) / sizeof(s[0]);
    //按照年龄来排序
    qsort(s,sz,sizeof(s[0]),sort_age);
    //按照名字来排序
    qsort(s,sz,sizeof(s[0]),sort_name);
 
}

排序前

按年龄排序后

按名字排序后

模仿qsort实现冒泡排序的通用算法

void swap (char *buf1,char*buf2,int width)
{
    char tmp;
    int i;
    for(i=0;i<width;i++)
    {
        tmp=*buf1;
        *buf1=*buf2;
        *buf2=tmp;
        buf1++;
        buf2++;
    }
}
void bubble(void* base,int sum,int width,int(*cmp)(const void *e1,const void *e2))
{
    int i,j;
    for(i=0;i<sum-1;i++)
    {
        for(j=i+1;j<sum;j++)
            {
                if(cmp((char*)base+i*width,(char*)base+j*width)>0)
                swap((char*)base+i*width,(char*)base+j*width,width);
            }
    }
}

指针与数组笔试题解

sizeof(数组名)表示数组大小,&数组名表示整个数组的地址,其他情况数组名表示首元素地址

1.

#include<stdio.h>
int main()
{
    int a[]={1,2,3,4};
    printf("%d\n",sizeof(a));//16,sizeof(数组名)表示计算整个数组的大小
    printf("%d\n",sizeof(a+0));//4或8,第一个元素的地址大小单独的数组名表示首元素地址,int*p=a
    printf("%d\n",sizeof(*a));//4,第一个元素的大小
    printf("%d\n",sizeof(a+1));//4或8,第二个元素的地址大小
    printf("%d\n",sizeof(a[1]);//4,第二个元素的大小

    printf("%d\n",sizeof(&a));//4或8,计算一个地址的大小
    printf("%d\n",sizeof(*&a));//16,int(*p)[4]=&a,&a是数组指针,解引用后是数组
    printf("%d\n",sizeof(&a+1));//4或8,&a+1跳过了一个数组的大小,是数组后面空间的地址
    printf("%d\n",sizeof(&a[0]));//4或8
    printf("%d\n",sizeof(&a[0]+1));//4或8
    return 0;
}

2.

#include<stdio.h>
int main()
{
    //字符数组
    char arr[]={'a','b','c','d','e','f'};

    printf("%d\n",sizeof(arr));//6
    printf("%d\n",sizeof(arr+0));//4或8
    printf("%d\n",sizeof(*arr));//1
    printf("%d\n",sizeof(arr[1]));//1
    printf("%d\n",sizeof(&arr));//4或8
    printf("%d\n",sizeof(&arr+1));//4或8
    printf("%d\n",sizeof(&arr[0]+1));//4或8
    
    return 0;
}

3.

#include<stdio.h>
int main()
{
    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));    //error
    printf("%d\n", strlen(arr[1]));    //error
    printf("%d\n", strlen(&arr));    //随机值
    printf("%d\n", strlen(&arr + 1));    //随机值-6
    printf("%d\n", strlen(&arr[0] + 1));    //随机值-1

    return 0;
}

4.

#include<stdio.h>
int main()
{
    char arr[] = "abcdef";
 
    printf("%d\n", strlen(arr));    //6
    printf("%d\n", strlen(arr + 0));    //6
    printf("%d\n", strlen(*arr));    //error
    printf("%d\n", strlen(arr[1]));    //error
    printf("%d\n", strlen(&arr));    //6
    printf("%d\n", strlen(&arr + 1));    //随机值
    printf("%d\n", strlen(&arr[0] + 1));    //5
 
    return 0;
}

5.

int main()
{
    char arr[] = "abcdef";
 
    printf("%d\n", sizeof(arr));    //7
    printf("%d\n", sizeof(arr+0));    //4或8
    printf("%d\n", sizeof(*arr));    //1👻
    printf("%d\n", sizeof(arr[1]));    //1
    printf("%d\n", sizeof(&arr));    //4或8
    printf("%d\n", sizeof(&arr+1));    //4或8
    printf("%d\n", sizeof(&arr[0]+1));    //4或8
 
    return 0;
}

6.

int main()
{
    char* p = "abcdef";
 
    printf("%d\n", sizeof(p));    //4或8
    printf("%d\n", sizeof(p + 1));    //4或8
    printf("%d\n", sizeof(*p));    //1
    printf("%d\n", sizeof(p[0]));    //1
    printf("%d\n", sizeof(&p));    //4或8
    printf("%d\n", sizeof(&p + 1));    //4或8
    printf("%d\n", sizeof(&p[0] + 1));    //4或8
 
    return 0;
}

7.

int main()
{
    char *p = "abcdef";
 
    printf("%d\n", strlen(p));    //6👻
    printf("%d\n", strlen(p+1));    //5👻
    printf("%d\n", strlen(*p));    //error
    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👻
 
    return 0;
}

8.

int main()
{
    int a[3][4] = {0}; // 二维数组
 
    printf("%d\n",sizeof(a));    //48
    printf("%d\n",sizeof(a[0][0]));    //4
    printf("%d\n",sizeof(a[0]));    //👻16,此时a[0]可以理解为第一行的数组名
    printf("%d\n",sizeof(a[0]+1));    //👻4或8,此时a[0]作为数组名并没有放在sizeof内部,也没有取地址&,所以a[0]就是第一行第一个元素的地址,a[0]+1是第一行第二个元素的地址
    printf("%d\n",sizeof(*(a[0]+1)));    //👻4,*(a[0]+1)是第二个元素
    printf("%d\n",sizeof(a+1));    //4或8👻此时a表示二维数组首元素的地址,即代表第一行的地址,a+1代表第二行的地址
    printf("%d\n",sizeof(*(a+1)));    //👻16,*(a+1)表示第二行
    printf("%d\n",sizeof(&a[0]+1));    //4或8,a[0]是第一行的数组名,&a[0]+1是第二行的地址
    printf("%d\n",sizeof(*(&a[0]+1)));    //👻16,*(&a[0]+1)是第二行
    printf("%d\n",sizeof(*a));    //👻16,*a代表第一行
    printf("%d\n",sizeof(a[3]));    //👻16,类型属性,sizeof通过类型计算大小
 
    return 0;
}

表达式的属性

e.g. 3+5

  1. 值属性 - 8

  1. 类型属性 - int

#include<stdio.h>
 int main()
{
    short s=5;
    int a=4;
    printf("%d\n",sizeof(s=a+6));    //2,s=a+6没有运算,换成s++也不会运算
    printf("%d\n",s);    //5
}

指针笔试题

1.

//这里告知结构体的大小是20个字节
struct Test
{
    int Num;
    char *pcName;
    short sDate;
    char cha[2];
    short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
{
     printf("%p\n", p + 0x1);    //0x100014
     printf("%p\n", (unsigned long)p + 0x1);    //👻0x100001
     printf("%p\n", (unsigned int*)p + 0x1);    //👻0x100004


     return 0;
}

2.

int main()
{
    int a[4] = { 1, 2, 3, 4 };
    int *ptr1 = (int *)(&a + 1);
    int *ptr2 = (int *)((int)a + 1);
    printf( "%x,%x", ptr1[-1], *ptr2);    //4,👻2000000,小端存储0x02 00 00 00低位放在低地址
    return 0;
}

3.指针与指针相减得到之间的元素个数

int main()
{
    int a[5][5];
    int(*p)[4];
    p = a;
    printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
    //FFFFFFFC,-4👻%p打印时内存里的补码被认为是地址,地址无正负之分,补码直接被解析为原码,按十六进制打印
    return 0;
}

4.

int main()
{
    int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    int *ptr1 = (int *)(&aa + 1);
    int *ptr2 = (int *)(*(aa + 1));
    printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));
    //👻10,5。aa+1相当于aa[1],*(aa+1)相当于aa[1][1],ptr2赋值处的(int*)可免去
    return 0;
}

5.

#include <stdio.h>
int main()
{
 char *a[] = {"work","at","alibaba"};
 char**pa = a;
 pa++;    //指向a[1],即指向at的首元素地址
 printf("%s\n", *pa);    //✨✨at,从*pa给的地址处开始打印字符串,**pa等于a,不能打印出at
 return 0;
}

6.👍👍✨

int main()
{
 char *c[] = {"ENTER","NEW","POINT","FIRST"};
 char**cp[] = {c+3,c+2,c+1,c};
 char***cpp = cp;
 printf("%s\n", **++cpp);    //ENTER
 printf("%s\n", *--*++cpp+3);    //ER
 printf("%s\n", *cpp[-2]+3);    //cpp[-2]相当于*(cpp-2)。**(cpp-2)+3输出ST
 printf("%s\n", cpp[-1][-1]+1);    //cpp[-1][-1]+1相当于*(*(cpp-1)-1)+1,输出EW
 return 0;
}

详细解答http://t.csdn.cn/SZHhW

7.

#include <stdio.h>
int main()
{
    int a[3][2] = { (0, 1), (2, 3), (4, 5) };    //👻逗号表达式,等价于int a[3][2]={1,3,5}
    int *p;
    p = a[0];
    printf( "%d", p[0]);    //1
 return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值