指针进阶

头文件

#include<stdio.h
#include<stdlib.h
#include<string.h

字符指针

int main()
{
    //字符指针
    char arr1[]="abcdef";
    char arr2[]="abcdef";
    char* p1="abcdef";
    char* p2="abcdef";
    if (arr1==arr2)
    {
        printf("hehe\n");
    }
    else
    {
        printf("haha\n");
    }
    if (p1==p2)
    {
        printf("hehe\n");
    }
    else
    {
        printf("haha\n");
    }
    printf("arr1:%p\n",arr1);
    printf("arr2:%p\n",arr2);
    printf("p1:%p\n",p1);
    printf("p2:%p\n",p2);
    return 0;
}

指针数组

int main()
{
    int arr1[]={1,2,3,4,5};
    int arr2[]={2,3,4,5,6};
    int arr3[]={3,4,5,6,7};

    int* parr[]={arr1,arr2,arr3};//指针数组-数组-存放指针的数组
    int i = 0;
    for (i=0;i<3;i++)
    {
        int j=0;
        for (j=0;j<5;j++)
        {
            printf("%d ",*(parr[i]+j));
        }
        printf("\n");
    }
    return 0;
}

数组指针

int main()
{
    int arr[5]={1,2,3,4,5};
    int (*p)[5]=&arr;//数组指针-指针-数组的地址要存起来

    return 0;
}

int main()
{
    char* arr[5];
    char* (*p)[5]=&arr;
    return 0;
}

int main()
{
    int arr[10]={1,2,3,4,5,6,7,8,9,10};
    int *p=arr;//arr[i]==*(arr+i)==*(p+i)==p[i]
    int i=0;
    for(i=0;i<10;i++)
    {
        printf("%d ",*(p+i));
    }

    // int (*p)[10]=&arr;
    // int i=0;
    // for(i=0;i<10;i++)
    // {
    //     printf("%d ",(*p)[i]);
    // }

    // for(i=0;i<10;i++)
    // {
    //     printf("%d ",*(*p+i));//*p==arr
    // }
    return 0;
}

数组参数,指针参数

//参数是数组的形式
void print1(int arr[3][5],int x,int y)
{
    int i=0;
    int j=0;
    for (i=0;i<x;i++)
    {
        for (j=0;j<y;j++)
        {
            printf("%d ",arr[i][j]);
        }
        printf("\n");
    }
}

//参数是指针的形式
void print2(int(*p)[5],int x,int y)
{
    int i=0;
    for(i=0;i<x;i++)
    {
        int j=0;
        for(j=0;j<y;j++)
        {
            //printf("%d ",p[i][j]);
            //printf("%d ",*(p[i]+j));
            printf("%d ",*(*(p+i)+j));
            //printf("%d ",(*(p+i))[j]);
        }
        printf("\n");
    }
}

二维数组传参

int main()
{
    int arr[3][5]={{1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7}};
    print1(arr,3,5);//arr-数组名-数组名就是首元素地址
    print2(arr,3,5);//
    return 0;
}

void test(int arr[3][5])
{}
void test1(int arr[][5])//可以省略行
{}
// void test2(int arr[3][])//err 不可以省略列
// {}
// void test3(int *arr)//err
// {}
// void test4(int **arr)//err
// {}
void test5(int (*arr)[5])
{}
int main()
{
    int arr[3][5]={0};

    // test(arr);//二维数组传参
    // test1(arr);
    // test2(arr);
    // test3(arr);
    // test4(arr);
    test5(arr);
    return 0;
}

void test1(int** p)
{}

int main()
{
    int *ptr;
    test1(&ptr);
    int **pp=&ptr;
    test1(pp);
    int* arr[10];
    test1(arr);
    return 0;
}

函数指针

//数组指针——是指向数组的指针
//函数指针——是指向函数的指针——存放函数地址的指针

int Add(int x,int y)
{
    int z=0;
    z=x+y;
    return z;
}

int main()
{
    int a=10;
    int b=20;
    // int arr[10]={0};
    // int (*p)[10]=&arr;
    //printf("%d\n",Add(a,b));

    //&arr;
    //arr;  

    //&函数名 和 函数名 都是函数的地址
    /*
    printf("%p\n",&Add);
    printf("%p\n",Add);
    */
    int (*pa)(int,int) = Add;
    printf("%d\n",(*pa)(2,3));
    return 0;
}

void Print(char* str)
{
    printf("%s\n",str);
}

int main()
{
    void (*p)(char*) = Print;
    (*p)("hello bite");

    return 0;
}

// 代码一
// (*(void(*)())0)();
// void(*)()-函数指针类型
// 把0强制类型转换成void(*)()函数指针类型-0就是一个函数地址
// 调用0地址处的该函数

// 代码二
// void (*singal(int ,void(*)(int)))(int);
// signal是一个函数声明
// signal第一个参数整形,第二个参数是函数指针类型,该函数指针指向的函数的参数是int,返回类型是void
// signal函数返回类型-函数指针-void(*   singal(int,void(*)(int)) )(int)
// 简化
// typedef void(*pfun_t)(int);
// pfun_t signal(int,pfun_t);

// typedef unsigned int unit;

int Add(int x,int y)
{
    int z=0;
    z=x+y;
    return z;
}

int main()
{
    int a=10;
    int b=20;

    int (*pa)(int,int) = Add;
    printf("%d\n",pa(2,3));
    printf("%d\n",Add(2,3));
    printf("%d\n",(*pa)(2,3));//*是摆设

    // printf("%d\n",(**pa)(2,3));
    // printf("%d\n",(***pa)(2,3));没必要
    return 0;
}

函数指针数组

int Add(int x,int y)
{
    return x+y;
}
int Sub(int x,int y)
{
    return x-y;
}
int Mul(int x,int y)
{
    return x*y;
}
int Div(int x,int y)
{
    return x/y;
}

int main()
{
    //指针数组
    int* arr[5];
    //需要一个数组可以存放四个函数的地址 - 函数指针的数组
    //int (*pa)(int,int) = Add;//Sub/Mul/Div
    int (*parr[4])(int,int) = {Add,Sub,Mul,Div};//函数指针的数组
    int i = 0;
    for (i=0;i<4;i++)
    {
        printf("%d\n",parr[i](2,3));
    }

    return 0;
}

函数指针数组的用途:转移表

void menu()
{
    printf("*****************\n");
    printf("** 1.add  2.sub**\n");
    printf("** 3.mul  4.div**\n");
    printf("** 5.Xor  0.exit**\n");
    printf("*****************\n");
}

int Add(int x,int y)
{
    return x+y;
}
int Sub(int x,int y)
{
    return x-y;
}
int Mul(int x,int y)
{
    return x*y;
}
int Div(int x,int y)
{
    return x/y;
}
int Xor(int x,int y)
{
    return x^y;
}

int main()
{
    int input = 0;
    int x = 0;
    int y = 0;
    //转移表
    int (*pfArr[])(int,int)={0,Add,Sub,Mul,Div,Xor};
    do
    {
        menu();
        printf("请选择:");
        scanf("%d",&input);
        if(input = 1 && input <=5)
        {
            printf("请输入两个操作数:");
            scanf("%d%d",&x,&y);
            int ret = pfArr[input](x,y);
            printf("%d\n",ret);
        }
        else if(input == 0)
        {
            printf("退出\n");
        }
        else
        {
            printf("选择错误\n");
        }
    }while(input);
    return 0;
}

回调函数

void Calc(int (*pf)(int,int))
{
    int x = 0;
    int y = 0;
    printf("请输入两个操作数:");
    scanf("%d%d",&x,&y);
    printf("%d\n",pf(x,y));
}

int main()
{
    int input = 0;

    do
    {
        menu();
        printf("请选择:");
        scanf("%d",&input);

        switch (input)
        {
            case 1:
                Calc(Add);
                break;
            case 2:
                Calc(Sub);
                break;
            case 3:
                Calc(Mul);
                break;
            case 4:
                Calc(Div);
                break;
            case 0:
                printf("退出\n");
                break;
            default:
                printf("选择错误\n");
                break;
        }

    }while(input);
    return 0;
}



//回调函数2
void print(char* str)
{
    printf("hehe:%s",str);
}

void test( void(*p)(char*) )
{
    printf("test\n");
    p("bit");
}
int main()
{
    test(print);

    return 0;
}

指向函数指针数组的指针

int Add(int x,int y)
{
    return x+y;
}

int main()
{
    int arr[10]={0};
    int (*p)[10]=&arr;//取出数组的地址
    int (*pfArr[4])(int,int);//pfArr是一个数组-函数指针数组
    //ppfArr是一个指向[函数指针数组]的指针 
    int (*(*ppfArr)[4])(int,int) = &pfArr;
    //
    //ppfArr是一个数组指针,指针指向的数组有四个元素
    //指向的数组的每个元素的类型是一个函数指针int(*)(int,int)
    //
    return 0;
}

冒泡排序

void bubble_sort(int arr[],int sz) //整形的冒泡排序
{
    int i = 0;
    for (i=0;i<sz-1;i++)
    {
        int j=0;
        for (j=0;j<sz-1-i;j++)
        {
            if (arr[j]arr[j+1])
            {
                int tmp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = tmp;
            }
        }
    }
}

// void qsort(void *base, size_t nmemb, size_t size,
//            int (*compar)(const void *a, const void *b));
//base:指向待排序数组的第一个元素的指针。
//nmemb:数组中元素的数量。sz
//size:每个元素的大小(以字节为单位)。width
//compar:用于比较两个元素的函数指针,比较两个元素的所用函数的地址-这个函数使用者自己实现函数指针的两个参数是:带比较的两个元素的地址。

int cmp_int(const void* a,const void* b)
{
    //比较两个整形值
    return (*(int*)a - *(int*)b);;
}

void test1()
{
    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]);
    }
}

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

void test2()
{
    float f[]={9.0,8.0,7.0,6.0,5.0,4.0,3.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]);
    }
}

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

int cmp_stu_by_age(const void* a,const void* b)
{
    return ((struct Stu*)a)-age - ((struct Stu*)b)-age;
}

int cmp_stu_by_name(const void* a,const void* b)
{
    //比较字符串用strcmp
    return strcmp(((struct Stu*)a)-name,((struct Stu*)b)-name);
}

void test3()
{
    struct Stu s[3]={{"zhangsan",20},{"lisi",30},{"wangwu",10}};
    int sz = sizeof(s) / sizeof(s[0]);
    //qsort(s,sz,sizeof(s[0]),cmp_stu_by_age);
    qsort(s,sz,sizeof(s[0]),cmp_stu_by_name);
    int k = 0;
    for (k=0;k<sz;k++)
    {
        printf("%d " ,s[k].age);
        //printf("%s " ,s[k].name);
    }
}

// 实现bubble_sort函数的程序员,他是否知道未来排序的数据类型-不知道
// 那程序员也不知道,带比较的两个元素的类型

void Swap(char* buf1,char* buf2,int width)
{
    int i = 0;
    for(i=0;i<width;i++)
    {
        char tmp = *buf1;
        *buf1 = *buf2;
        *buf2 = tmp;
        buf1++;
        buf2++;
    }
}

void bubble_sort(void* base,int sz,int width,int(*cmp)(void*a,void*b))
{
    int i = 0;
    //趟数
    for (i=0;i<sz-1;i++)
    {
        //每一趟比较的对数
        int j = 0;
        for(j=0;j<sz-1-i;j++)
        {
            //两个元素比较
            if(cmp((char*)base+j*width,(char*)base+(j+1)*width)0)
            {
                //交换
                Swap((char*)base+j*width,(char*)base+(j+1)*width,width);
            }
        }
    }
}

void test4()
{
    int arr[10]={9,8,7,6,5,4,3,2,1,0};
    int sz = sizeof(arr) / sizeof(arr[0]);
    //使用bubble_sort的程序员一定知道自己排序的是什么数据、
    //就应该知道如何比较待排序数组中的元素
    bubble_sort(arr,sz,sizeof(arr[0]),cmp_int);
    int i = 0;
    for (i=0;i<sz;i++)
    {
        printf("%d ",arr[i]);
    }
}

void test5()
{
    struct Stu s[3]={{"zhangsan",20},{"lisi",30},{"wangwu",10}};
    int sz = sizeof(s) / sizeof(s[0]);
    bubble_sort(s,sz,sizeof(s[0]),cmp_stu_by_age);
    int k = 0;
    for (k=0;k<sz;k++)
    {
        printf("%d " ,s[k].age);
        //printf("%s " ,s[k].name);
    }
}

int main()
{
    //test1();
    //test2();
    //test3();
    //test4();
    test5();
    return 0;
}

例题

```c
int main()
{
//数组名是首元素的地址
//1.sizeof(数组名) - 数组名表示首元素地址
//2.&数组名 - 数组名表示整个数组
//一维数组
int a[] = {1,2,3,4};//44=16
printf(“%d\n”,sizeof(a));//16-sizeof(数组名)-计算的是数组总大小-单位是字节
printf(“%d\n”,sizeof(a+0));//数组名这里表示首元素地址,a+0还是首元素地址,地址大小就是4/8个字节
printf(“%d\n”,sizeof(
a));//4-数字名表示首元素地址,a就是首元素,sizeof(a)就是4
printf(“%d\n”,sizeof(a+1));//a+1第二个元素地址,地址大小为4/8
printf(“%d\n”,sizeof(a[1]));//4-第二个元素的大小
printf(“%d\n”,sizeof(&a));//&a取出的是数组的地址,数组的地址也是地址,地址大小为4/8
printf(“%d\n”,sizeof(*&a));//16 - &a是取数组的地址,数组的地址解引用访问的数组,sizeof计算的就是数组的大小单位是字节
printf(“%d\n”,sizeof(&a+1));//&a是数组的地址,&a+1虽然地址跳过整个数组,但还是地址,所以是4/8
printf(“%d\n”,sizeof(&a[0]));//&a[0]是第一个元素的地址
printf(“%d\n”,sizeof(&a[0]+1));//&a[0]+1是第二个元素的地址

//字符数组
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n",sizeof(arr));//sizeof计算的是数组大小,6*1=6字节
printf("%d\n",sizeof(arr+0));//arr是首元素的地址,arr+0还是首元素的地址 地址的大小4/8
printf("%d\n",sizeof(*arr));//1  arr是首元素地址 *arr就是首元素 首元素是字符大小是一个字节
printf("%d\n",sizeof(arr[1]));//1
printf("%d\n",sizeof(&arr));//&arr 虽然是数组的地址,但还是地址,地址大小4/8
printf("%d\n",sizeof(&arr+1));//&arr+1 是跳过整个数组的地址,地址大小4/8
printf("%d\n",sizeof(&arr[0]+1));//第二个元素的地址,地址大小4/8

printf("%d\n",strlen(arr));//随机值1
printf("%d\n",strlen(arr+0));//随机值1
// printf("%d\n",strlen(*arr));//err
// printf("%d\n",strlen(arr[1]));//err
// printf("%d\n",strlen(&arr));//随机值1
// printf("%d\n",strlen(&arr+1));//随机值2 -6
// printf("%d\n",strlen(&arr[0]+1));//随机值3 -1

return 0;

}