首页 > 其他分享 >指针进阶(C语言)

指针进阶(C语言)

时间:2023-08-04 12:12:59浏览次数:37  
标签:arr 进阶 int void C语言 数组 printf sizeof 指针

指针进阶

头文件

#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;
}

例题

int main()
{
    //数组名是首元素的地址
    //1.sizeof(数组名) - 数组名表示首元素地址
    //2.&数组名 - 数组名表示整个数组
    //一维数组
    int a[] = {1,2,3,4};//4*4=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;
}

标签:arr,进阶,int,void,C语言,数组,printf,sizeof,指针
From: https://www.cnblogs.com/bumper/p/17605540.html

相关文章

  • Qt 在线程中invokeMethod采用QueuedConnection模式,调用带指针参数槽,实际不会调用
    widgetObject有操函数Test:voidTest(int*v);在线程中调用Test,会被忽略,实际不会调用。QMetaObject::invokeMethod(widgetObject,"Test",Qt::QueuedConnection,Q_ARG(int*,&v));下面是网上找的理由: 在同一个线程中当信号和槽都在同一个线程中时,值传递参数和引用传递参数有......
  • 代码随想录算法训练营第九天| 复习字符串和双指针法(看卡哥文章复习)
     KMP算法就是在一个字符串中寻找另一个子串,避免了“跳回下一个字符再重新匹配”,实现了在一次字符串的遍历过程中就可以匹配出子串。28. 实现 strStr()  (本题可以跳过)     卡哥建议:因为KMP算法很难,大家别奢求 一次就把kmp全理解了,大家刚学KMP一定会有各种各样的......
  • C语言实现简易版扫雷
     扫雷作为一款内置于windowsXP系统的游戏,相信大多数人都有游玩过。接下来我将带着各位用C语言来实现这个游戏。首先,我们来了解扫雷游戏的规则,将这些规则逐步用函数来实现,再经过逻辑的调整即可得到所需的代码。可以试着先自己玩一把再继续看本文章。扫雷游戏网页版-Minesweeper......
  • C语言
    C语言基础语法1.程序语言的基本构成要素:自然语言程序设计语言字数字,字母,运算符,分隔符词/词组关键字,标识符,常量句子/段落语句篇章程序1.关键字:也称保留字(ReservedWord),是C语言预先定义的、具有特殊意义的单词2.标识符:是大小写字母,数字和下划......
  • C语言 | extern关键字
    extern是C语言中的关键字,它会声明一个全局变量或者函数,表明变量或者函数是定义在其他其他文件中的。​ 定义:表示创建变量或分配存储单元。​ 声明:说明变量的性质,但并不分配存储单元。externinti; //只是声明,但没有分配内存空间给变量iinti; //是定义,给变量i分配了4......
  • 我的第九次C语言练习
    今天终于学完了弟三章,实际上昨天没剩下多少了,今天主要是在写练习。//intmain(void)//{// inta;// unsignedintb;// a=12;// b='\012';// printf("a=%d,b=%u",a,b);// return0;//}首先试了下unsignedint和正常int的不同,因为书上在打印\012时答案上只显示了unsig......
  • 数组双指针技巧汇总 [labuladong-刷题打卡 day2]
    https://labuladong.github.io/algo/challenge/ji-chu-tiao-zhan/day02/快慢指针26.删除有序数组中的重复项两个指针分别维护符合条件数组和待删除数组,当快指针移动时将符合条件元素插入已完成数组后即可。通过这两天对双指针的练习,可以发现很多双指针算法其实也是一种迭代算......
  • C语言关键字extern。
    extern:声明变量是在其他文件正声明(也可以看做是引用变量):extern用在变量或函数的声明前,用来说明“此变量/函数是在别处定义的,要在此处引用”。//文件1代码#include<stdio.h>externvoidlbw();//声明外部lbw()intmain(){ lbw();}//文件2代码#include<stdio.h>voidlbw......
  • C语言嵌入式面试
    指针1.数组指针与指针数组,函数指针与指针函数区别?答:函数指针指向函数的指针变量,即本质是一个变量。指针函数是指返回值是指针的函数,即本质是一个函数。数组指针是指向数组首元素的地址的指针,其本质为指针。(这个指针存放的是数组首地址的地址,相当于2级指针,这个指针不可移动)指......
  • C语言嵌入式开发
    第一类问题:专业考察题在下面问题中,我附上自己的理解,可能不全面,用到的话再自行补充一些。问题1:问你写在简历上的项目经历,一般问的很细很细,在此基础上考察你项目里用到的技术知识。问题2:IIC协议(1)I2C使用两条线在主控制器和从机之间进行数据通信。一条是SCL(串行时钟线),另外一条......