「1」指针进阶——详解

🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀 

目录

🐰指针的回顾

🐰字符指针

🐰指针数组

🌸模拟二维数组(整形)

🐰数组指针

🌸数组指针和指针数组的区分

🌸&数组名和数组名的区别

🌸数组指针p,*p等价于arr,*p就是数组名

🌸数组指针的使用

🌸数组参数和指针参数

🐰函数指针-指向函数的指针

🌸函数指针数组


🐰指针的回顾

1.指针是内存中一个最小单元的编号,也就是地址

2.平时口语上所说的指针,通常指的是指针变量,是用来存放地址的变量

3.把内存划分为一个个的内存单元,这个内存单元大小是1字节,从概念上讲:编号 == 地址 == 指针

指针变量:

我们可以通过& (取地址操作符) 取出变量的内存起始地址,把地址可以存放到一个变量中,这个变量就是指针变量

4.指针大小(4字节 32位/8字节 64位)

🐰字符指针

#include<stdio.h>
int main()
{
    char ch='w';
    char* pc=&ch;
    const char* p="abcdef";//"abcdef",是把字符串的首地址放到p中
    //"abcdef"是常量字符串,是不可以修改的
    char arr[]="abcdef";
    //"abcdef",这里的arr的值是可以修改的
    char *pa=arr;
    *pa='w';
    printf("%s\n",arr);//修改的结果为wbcdef
    return 0;
}

‼️注:常量字符串在内存中只保存一份!!!

#include<stdio.h>
int main()
{
    char str1[]="abcdef";
    char str2[]="abcdef";

    char* str3="abcdef";//保存的就是常量字符串
    char* str4="abcdef";//保存的就是常量字符串
    if(str1==str2)//数组保存的字符串是变量,所以str1!=str2
    {
        printf("str1==str2\n");
    }
    else
    {
        printf("str1!=str2\n");
    }
    if(str3==str4)//常量字符串在内存中只保留一份,所以str3==str4
    {
        printf("str3==str4\n");
    }
    else
    {
        printf("str3!=str4\n");
    }
    return 0;
}

结果为:
str1!=str2

str3==str4

🐰指针数组

字符数组-存放字符的数组
char arr[10];
整形数组-存放整形的数组
int arr[10];
指针数组-存放的就是指针
char* arr[10];
int* arr[10];
#include<stdio.h>
int main()
{
    char* arr[]={"abc","bcd","edf"};//指针数组,保存了三个字符串的首地址
    for(int i=0;i<3;i++)
    {
        printf("%s\n",arr[i]);
    }
    return 0;
}
结果为:

abc

bcd

edf

🌸模拟二维数组(整形)

#include<stdio.h>
int main()
{
    int arr1[]={1,2,3,4,5};
    int arr2[]={1,2,3,4,5};
    int arr3[]={1,2,3,4,5};
    int arr4[]={1,2,3,4,5};
    int* arr5[]={arr1,arr2,arr3,arr4};
    for(int i=0;i<4;i++)
    {
        for(int j=0;j<5;j++)
        {
            printf("%d",*(arr5[i]+j));
            //printf("%d\n",arr5[i][j]);//结果一样
        }
        printf("\n");
    }
    return 0;
}

结果为:

12345

12345

12345

12345

🐰数组指针

整形指针-指向整形的指针
int a=10;
int* P=&a
字符指针-指向字符的指针
char ch='w';
char* pc=&ch;
数组指针-指向数组的指针
int arr[10];
&arr就是数组的地址
int (*pa)[10]=&arr;
char arr[10];
char(*pc)[10]=&arr
int* arr[5];
int* (*pa)[5]=&arr//这个数组指针指向的是arr这个指针数组

🌸数组指针和指针数组的区分

指针数组->存放指针的数组
数组指针->是一种指向数组的指针-存放的是数组的地址

🌸&数组名和数组名的区别

数组名是数组首元素地址
sizeof(数组名)--这个时候表示的不是首元素的首地址,计算的整个数组的大小
&数组名--这里的数组名表示整个数组,取出的是整个数组的地址,从地址角度看和数组首元素的地址一样,他们的类型不一样
#include<stdio.h>
int main()
{
    int arr[10]={0};
    printf("arr=%p\n",arr);//数组首元素的地址
    printf("arr+1=%p\n",arr+1);//数组第二个元素的地址

    printf("&arr[0]=%p\n",&arr[0]);//数组首元素的地址
    printf("&arr[0]+1=%p\n",&arr[0]+1);//数组第二个元素的地址

    printf("&arr=%p\n",&arr);//整个数组的地址
    printf("&arr+1=%p\n",&arr+1);//数组第最后一个元素的下一个的地址
    int(*p)[10]=&arr;//数组指针保存整个数组的地址
    return 0;
}

结果

r=0x7ffeefbff3c0
arr+1=0x7ffeefbff3c4
&arr[0]=0x7ffeefbff3c0
&arr[0]+1=0x7ffeefbff3c4
&arr=0x7ffeefbff3c0
&arr+1=0x7ffeefbff3e8

🌸数组指针p,*p等价于arr,*p就是数组名

#include<stdio.h>
int main()
{
    int arr[10]={1,2,3,4,5,6,7,8,9,10};
    int (*p)[10]=&arr;
    for(int i=0;i<10;i++)
    {
        printf("%d ",*((*p)+i));//*p等价于arr,*p就是数组名
    }
    return 0;
}
结果为:

1 2 3 4 5 6 7 8 9 10

🌸数组指针的使用

#include<stdio.h>
void print(int (*arr)[5],int r,int c)
{
    for(int i=0;i<r;i++)
        {
            for(int j=0;j<c;j++)
            {
                printf("%d ",*(*(arr+i)+j));//arr+i==&arr[i]
                //printf("%d ",arr[i][j]);
            }
        }
}
int main()
{
    //二维数组的数组名,也表示首元素地址
    //二维数组的首元素是第一行的地址,是一个一维数组的地址
    int arr[3][5]={1,2,3,4,5,6,7,8,9,10};
    print(arr,3,5);
    return 0;
}

结果为:
1 2 3 4 5 6 7 8 9 10 0 0 0 0 0

二维数组arr

int (*p)[10]=&arr;
p等价于arr
arr=&arr[i]
arr[i]=&arr[i][0]
分析代码
int arr[5];
int *parr1[10];//指针数组
int (*parr2)[10];//数组指针
int (*parr3[10])[5];//数组中存放的数组指针

🌸数组参数和指针参数

一维数组传参
一维数组传参,形参可以是数组,可以是指针
二维数组传参
参数可以是指针,可以是数组,如果是指针,传过去的是第一行的地址
函数形参的设计只能省略第一个[]的数字,因为一个二维数组,可以不知道有对少行,但是必须知道一行有多少元素
一级指针传参
当一个函数的参数部分为一级指针的时候,函数能接收什么参数
数组,指针
二级指针传参
当一个函数的参数部分为二级指针的时候,函数能接收什么参数
二级指针变量,一级指针的地址,指针数组

🐰函数指针-指向函数的指针

函数指针存放的是函数的地址,函数也是有地址的
‼️注:函数名和取地址函数名 是一样的
#include<stdio.h>
int Add(int x,int y)
{
    return x+y;
}
//函数是存在地址
int main()
{
    printf("%p\n",&Add);//0x100003f40
    printf("%p\n",Add);//0x100003f40
    int (*pf)(int,int)=Add;//pf就是函数指针

    int ret=(*pf)(3,5);//函数指针的调用
    int rat=pf(3,5);//*pf和pf等价
    //这里的*没有实际的意义,可以不要pf(3,5),可以多加(**pf)(3,5),都不影响结果,*pf)(3,5)是为了方便理解
    printf("%d %d\n",ret,rat);
}

结果为:

0x100003ef0

0x100003ef0

8 8

🌸函数指针数组

数组的每个元素是一个函数指针
这是利用switch()语句制作的两位数计算器
#include<stdio.h>
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 menu(void)
{
    printf("****    两位数的计算器     ****\n");
    printf("****    1.Add   2.Sub   ****\n");
    printf("****    3.Mul   4.Div   ****\n");
    printf("****    0.exit          ****\n");
}
int main()
{

    int input=0;
    do
    {
        menu();
        printf("请选择\n");
        scanf("%d",&input);
        int x=0,y=0,ret=0;
        switch(input)
        {
            case 1:
                printf("请输入两个操作数\n");
                scanf("%d %d",&x,&y);
                ret=Add(x,y);
                printf("%d\n",ret);
                break;
            case 2:
                printf("请输入两个操作数\n");
                scanf("%d %d",&x,&y);
                ret=Sub(x,y);
                printf("%d\n",ret);
                break;
            case 3:
                printf("请输入两个操作数\n");
                scanf("%d %d",&x,&y);
                ret=Mul(x,y);
                printf("%d\n",ret);
                break;
            case 4:
                printf("请输入两个操作数\n");
                scanf("%d %d",&x,&y);
                ret=Div(x,y);
                printf("%d\n",ret);
                break;
            default:
                printf("输入错误\n");
        }
    }while(input);
}

结果为:

****      两位数的计算器     ****

****      1.Add   2.Sub        ****

****      3.Mul   4.Div         ****

****      0.exit                      ****

请选择

1

请输入两个操作数

3 8

11

这种算法,太冗余了,不够简洁
这是利用函数指针数组制作的两位数计算器
#include<stdio.h>
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 menu(void)
{
    printf("****    两位数的计算器     ****\n");
    printf("****    1.Add   2.Sub   ****\n");
    printf("****    3.Mul   4.Div   ****\n");
    printf("****    0.exit          ****\n");
}
int main()
{
    int input=0;
    do
    {
        int x=0,y=0;
        menu();
        printf("请选择\n");
        scanf("%d",&input);
        printf("请输入两个操作数\n");
        scanf("%d %d",&x,&y);
        int (*pf[5])(int,int)={0,Add,Sub,Mul,Div};//这里之所以数组元素给了5个,是为了与菜单对应起来
        if(input<5&&input>=0)
        {
            int ret=(*pf[input])(x,y);
            printf("%d\n",ret);
        }
        else if(input==0)
        {
            printf("计算结束\n");
            break;
        }
        else
        {
            printf("输入错误\n");
        }
    }while(input);
}

结果为:

****      两位数的计算器     ****

****      1.Add   2.Sub        ****

****      3.Mul   4.Div         ****

****      0.exit                      ****

请选择

1

请输入两个操作数

3 8

11

这种算法,很简洁,逻辑更清晰。

🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸      

  • 27
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 21
    评论
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值