字符指针、指针数组、数组指针、二级指针传参、函数指针、函数指针数组、指向函数指针数组的指针、回调函数

字符指针

#include "stdio.h"
int main(){
    char* ptr = "hello bit";
    return 0;
}

这里并不是把"hello bit"整个字符串传给指针ptr,指针ptr只是只想字符串首字母"h"的地址

#include "stdio.h"
int main(){
    char str1[] = "hello";
    char str2[] = "hello";
    char *ptr1 = "hello";
    char *ptr2 = "hello";
    return 0;
}

这里str1和str2都是创建新的数组空间存放字符串"hello",而ptr1和ptr2只是两个指针,其只想一片存放"hello"的地址,ptr1和ptr2相等,而str1和str2不等。且char *ptr="hello"这样ptr表示常量字符串,是不能修改的,可以写成const char *ptr = “hello”

指针数组

指针数组是一个元素为指针的数组

int* arr1[10];

名字arr先与[]结合表示这是一个数组,里面存放int类型的元素。
去除数组名arr,剩下int
[10]就是数组类型

数组指针

int (*p)[10]

因为[]优先级高于*,所以使用(*p)表示p是一个指针;将(*p)去掉后剩余int [10]为p指向的类型,是存放10个元素的数组,每个元素类型为int

  • 数组指针使用场景
#include "stdio.h"
void my_print(int (*ptr)[2], int a, int b){
//    传过来的是一个数组的地址&a,a是存有两个元素的数组的数组名,故用指向数组的指针接收
    for (int i = 0; i < a; ++i) {
        for (int j = 0; j < b; ++j) {
//            printf("%d ",ptr[i][j]);
            printf("%d ",*((*(ptr+i))+j));   //  (ptr+i)得到第i行数组的首地址,*(ptr+i)对数组地址解引用得到数组,相当于得到一维数组数组名,*(ptr+i)其是数组首元素地址
        }
    }
}


int main(){
//    在非siezeof情况下,二维数组数组名arr表示第一行数组的地址,若第一行存放a[10]={0},则arr = &a;
//    因此 *arr得到第一行数组,即*arr相当于第一行数组名a,其存放的与a一样(无sizeof等两种特殊情况),是第一行数组首元素a[0]的地址;
//    *arr 与 arr[0]等价,arr[0] = *(arr+0)
    int arr[3][2] = {{1,2},{3,4},{5,6}};
    my_print(arr,3,2);  //这里不是sizeof情况,arr单独出现,表示的应该是首行数组的地址(一个数组的地址,相当于&a)
    return 0;
}

二级指针传参

#include "stdio.h"
void test(char* *P){  //p是一个指针,其指向一个地址(指针),该指针指向的元素是char

}

int main(){
    char c = 'b';
    char *pc = &c;
    char* *pcc = &pc;
    char* arr[10];
    test(&pc);    //pc是一个指针,其指向char,传地址过去符合
    test(pcc);    //pcc是一个指针,其存放的是一个地址,该地址指向char,因此pcc丢进去就传进去了一个指向char类型元素地址的地址
    test(arr);    //arr是一个数组名,其存放指向第一个元素的地址,第一个元素为char * ;相当于传进去了char * 的地址,用char* *p接受正合适
    return 0;
}

函数指针

int (*p) (int, int) 

(*p)表示指针;(int,int)与(*p)结合表示该指针为函数指针,(int,int)其本身表示指向的函数的两个参数类型;将(*p)和(int int)去掉后剩余的int表示指向函数的返回类型

#include "stdio.h"
void test(){
    printf("hehe\n");
}
int main(){
    printf("%p\n",test);
    printf("%p\n",&test);
    return 0;
}

对于函数名来说,这两种一样,都是函数地址

同样,对于(*p)中的*也只是个摆设,为了容易理解而写而已;完全可以(*p)(a,b) -> p(a,b)

函数指针数组

int (*ptr[10])()
//函数指针数组是数组,所以名称应该与[]先结合

首先ptr与[10]先结合,说明ptr这个名称表示数组,有10个元素;把ptr[10]去掉可知剩余的int (*)()是数组每个元素的类型,其为函数指针类型,可知这是函数指针数组(其他情况一样分析)

指向函数指针数组的指针

一个指针指向一个数组,数组元素都是函数指针

//一个函数指针
void (*ptr)(char *)

//一个指针数组
void (*ptrr[10])(char *)

//*首先与ptrrr结合(*ptrrr)表明ptrrr是个指针;紧接着(*ptrrr)与[10]结合(*ptrrr)[10]表明指针指向数组;将(*ptrrr)[10]这部分去掉,剩余的void (*)(char *)表示数组元素类型为函数指针类型
void (*((*ptrrr)[10]))(char *)

回调函数

回调函数就是一个通过函数指针调用的函数。如果把函数的指针(地址)作为参数传给另一个函数,当这个指针被用来调用其指向函数时,这个被指向的函数叫回调函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值