指针1(字符数组,指针数组,数组指针,函数指针,函数指针数组,指向函数指针数组的指针)

#define _CRT_SECURE_NO_WARNINGS 
#include<stdio.h>
字符数组
int main()
{
    char arr[]= "abcdef";
    char* p = arr;//指针变量p存的是数组arr的首元素地址
    const char* p1 = "abcdef";//abcdef为常量字符串,不能被修改.p1存的是这个常量字符串的首元素地址
    printf("%s\n", p);//%s——根据指针指向的元素进行打印,找到/0后才停止打印
    printf("%c\n", *p);//*p——p解引用之后找到的是一个字符,需要用%c来接收
    printf("%s\n", p1);
    return 0;
}

判断下列代码输出的结果
int main()
{
    const char arr1[] = "abcdef";
    const char arr2[] = "abcdef";
    const char* p1 = "abcdef";
    const char* p2= "abcdef";
    if (arr1 == arr2)//比较的是两个数组的首元素地址,两个数组储存在不同的内存地址中
        printf("hehe\n");
    else
        printf("haha\n");
    if (p1==p2)//比较的是两个指针所指向的地址,由于内容相同,因此两指针所指向的地址相同。但两个指针变量的地址不相同(注意!)
        printf("hehe\n");
    else
        printf("haha\n");

    return 0;
}

指针数组——用来存放指针的数组
eg:
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 };//parr——用来存储三个数组首元素的地址
    int i = 0;
    for (i = 0; i <= 2; i++)
    {
        int j = 0;
        for (j = 0; j <= 4; j++)
        {
            printf("%d ",*(parr[i] + j));
        }
        printf("\n");
    }
    return 0;
}

数组指针——是指向某一个数组的指针
int main()
{
    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
    int(*p)[10] = &arr;//*p表示p是一个指针,[10]表示p指向的数组有10个元素,int指的是数组的类型
注意:[]的优先级高于*,因此必须加上()来保证p先和*结合
    return 0;
}


int main()
{
    int* arr[5];
    int* (*parr)[5] = &arr;//*parr表示parr是一个指针,int*表示数组的类型,[5]表示的是parr指向数组有5个元素
    return 0;
}

数组指针的一般使用方法eg:
void print(int (*p)[5], int x, int y)//p为一个数组指针
{
    int i = 0;
    for (i = 0; i < x; i++)
    {
        int j = 0;
        for (j = 0; j < y; j++)
        {
            printf("%d ", *((*p + i) + j));//*p——数组的首元素地址,*p+i——跳过i个数组,*p+j——访问一行数组的第j-1个元素的地址
        }
        printf("\n");
    }
}
int main()
{
    int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
    print(arr,3,5);//arr是首元素地址,对于一个二维数组传参,将二维数组看成是一维数组,其中每一行看成这个一维数组的一个元素
    return 0;
}

int main() 
{
    int arr[] = { 0 };
    int(*p)[1] = &arr;//p是数组指针
    int(*(*pa))[1] = &p;//pa是指向数组指针p的指针(类似于二级指针)
    int(*ppa[2])[1] = { p ,NULL };//ppa是一个元素类型为数组指针的数组
    printf("%d\n", (*ppa[0])[0]);//ppa[0]相当于p,*(ppa[0])相当于arr
}

判断下列代码的含义
int main()
{
    int(*parr1)[10];//parr1是一个数组指针,它指向的是一个具有10个整形元素的一个数组
    int(*parr2[10])[5];//parr2是一个数组,里面含有10个元素,每个元素都是一个int*[5]类型的一个指向含有5个整形元素数组的数组指针
    return 0;
}

一维数组传参可以用数组接收,也可以用指针接收,对于一个指针数组传参,可以用一个二级指针接收,或直接用指针数组接收。函数形参的设计可以省略[]里的内容
二维数组传参,需要用一个数组指针接收,或者直接用二维数组接收,函数形参的设计只能省略第一个[]的数字。

一级指针传参和二级指针传参,穿什么样的参数就用什么样的参数接收。例如,传一个一级指针,就用一级指针接收,传一级指针的地址就用二级指针接收等。

函数指针:函数指针是一个用来存放函数地址的指针。是指向函数的指针。类似于数组指针的表达方法
int add(int x, int y)
{
    int z = x + y;
    return z;
}
int main()
{
    int a = 10;
    int b = 20;
    int p = add(a, b);
    printf("%d\n", p);
    printf("%p\n", &add);
    printf("%p\n", add);//&add与add的输出结果相同,都表示函数add的地址
    int(*padd)(int, int) = &add;//padd即为函数指针。(int,int)为指针所指的函数的传参的类型。int(*padd)中int是函数add的返回值类型,*padd表示padd是指针
    int(*Padd)(int, int) = add;//*的优先级低于()
    printf("%p\n", padd);//padd是一个函数指针,即是函数的地址
    printf("%d\n", (*padd)(2, 3));
    printf("%d\n", (**padd)(2, 3));//对于函数有多少个*与函数指针的解引用无关(仅对于函数的特例)
    printf("%d\n", padd(2, 3));//(*padd)与padd的输出结果相同。都表示对指针所指向的函数进行重新传参。
    return 0;
}

阅读两段有趣的代码,并解释其含义
(*(viod(*)())0)();//将整形0强制类型转换成viod(*)()函数指针类型,并调用0地址处的该函数
void(*signal(int, void(*)(int)))(int);
表示函数名为signal的函数,参数类型有两个,第一个为int类型,第二个为函数指针类型,该函数指针指向函数的参数类型为int类型,返回类型为void。signal函数的返回类型
也为一个指向的函数的参数类型为int类型,返回类型为void函数指针类型

对下列代码进行简化
void(*signal(int, void(*)(int)))(int);//void(*)(int)为一个函数指针类型
typedef void(*vdt)(int);//将void(*)(int)重命名为vdt
vdt signal(int, vdt);

函数指针数组——存放函数指针(地址)的数组——int(*p[5])()——p先和[]结合,说明p是数组,数组的内容是int(*)()类型的函数指针。
eg:
int add(int x, int y)
{
    int z = 0;
    z = x + y;
    return z;
}
int sub(int x, int y)
{
    int z = 0;
    z = x - y;
    return z;
}
int mul(int x, int y)
{
    int z = 0;
    z = x * y;
    return z;
}
int div(int x, int y)
{
    int z = 0;
    z = x /y;
    return z;
}
int main()
{
    int x = 0;
    int y = 0;
    scanf("%d%d", &x, &y);
    int i = 0;
    int(*p[4])(int, int) = { add,sub,mul,div };
    for (i = 0; i <= 3; i++)
    {
        printf("%d\n", p[i](x,y));
    }
    
    return 0;
}

函数指针数组的应用:转移表      
eg:(计算器)
1、使用switch case,并引用了回调函数的概念
void menu(void)
{
    printf("**********************************\n");
    printf("**********1.add   2.sub***********\n");
    printf("**********3.mul   4.div***********\n");
    printf("************ 0.exit **************\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;
}
void srfct(int(*p)(int,int))
{
    int x = 0;
    int y = 0;
    printf("请输入两个值:\n");
    scanf("%d%d", &x, &y);
    printf("输出的结果为:%d\n", p(x,y));
}
int main()
{
    int input = 0;
    
    do
    {
        menu();
        printf("请输入:");
        scanf("%d", &input);
        switch (input)
        {
        case 1:
            srfct(add);//srfct函数()里的函数即为回调函数
            break;
        case 2:
            srfct(sub);
            break;
        case 3:
            srfct(mul);
            break;
        case 4:
            srfct(div);
            break;
        case 0:
            printf("退出程序\n");
            break;
        default:
            printf("输入错误\n");
            break;
        }
        
    } while (input);
    return 0;
}
2、使用了函数指针数组的概念
void menu(void)
{
printf("**********************************\n");
printf("**********1.add   2.sub***********\n");
printf("**********3.mul   4.div***********\n");
printf("************ 0.exit **************\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 main()
{
    int input = 0;
    int x = 0;
    int y = 0;
    int(*p[5])(int, int) = { 0, add,sub,mul,div };
    do
    {

        menu();
        printf("请输入:");
        scanf("%d", &input);
        if (input == 0)
            break;
        else if (input > 4)
        {
            printf("输入错误,请重新输入\n");
        }
        else
        {
            
            printf("请输入两个值:\n");
            scanf("%d%d", &x, &y);
            
            printf("输出的结果为:%d\n", p[input](x, y));

        }
    } while (input);
    return 0;
}

指向函数指针数组的指针——(函数指针)数组的指针——这个指针指向的是一个数组,这个数组的元素为指向函数的指针
int add(int x, int y)
{
    return x + y;
}
int main()
{
    int(*p)(int, int) = &add;//p是函数指针
    int(*pa[2])(int, int) = { p };//pa是函数指针数组
    int(*(*ppa)[2])(int, int) = &pa;//ppa是指向函数指针数组pa的指针
    printf("%d\n", (*((*ppa)[0]))(2,3));//结果为对add函数进行赋值(2,3)
    printf("%d\n", (*((ppa)[0]))(2, 3));
    printf("%d\n", p(2,3));
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值