学习不是闭门造车之—–四处留情指针篇

        各位老板、打工人们,下午好。我是“大怨种”,21届毕业生。工作了一年,放弃了稳定还不累的电气设计工作,选择转行,想进入软件行业,本打算自学编程语言的基础–C语言。奈何大学时C语言课程没有好好听讲,外加工作一年没碰相关知识,C语言早都忘得一干二净。就从网上找了教程自学习,后来发现自学,学是能学懂,但是只是些浅浅的皮毛。就打算报个班学习一下,偶然机会知道了华清远见这个教学机构,就抱着试一试的态度去参加了培训。现在上课已经有快一个月了,感觉还不赖,老师的水准特别高,讲课通俗易懂。

        以后的3个多月,我会写一些我自己的C语言、C++还有其他课程的知识点总结,也可能会写一些电气设计行业的一些心得和潜规则,希望对迷茫的”电气人“毕业生们提供一点小小的帮助。

        言归正转,这篇帖子我想总结一下指针、数组指针、指针数组、二级指针、指针函数、函数指针。

一、  首先是指针的祖宗——-一级指针;

        1、指针的定义(自己总结的,非官方解释):存放地址的变量叫指针。通俗点讲,这个变量是放其他变量或者内存空间的地址的。

        2、 指针有两大关注点,指针的类型,指针的指向类型。例如定义一个指针变量p存整形变量a的地址:int a; int * p=&a; 指针p的类型是int*,指向的类型是int

        3、通过指针变量p去访问指向的变量a:用*p,现在这个*p==a; 改变*p和a之间的谁,另一个也跟着改。

        4、上面说的第三点主要应用在函数的传参作用。一个函数要改变a的值,不能直接改a的值,要通过a的地址去改变。

        5、指针和数组: 先定义一个数组int a[5],数组的名字就是该数组的首地址。我的理解是数组的名字a是一个指针变量(当然a不是),这个指针变量存的是int [5]这个一维的无名的数组首地址。那么 int* p=a;————>相当于两个指针变量之间的赋值,地址的复制,传递。

        6、指针、数组与加1: int a[5] ;   int* p=a ;那么p+1—–>可以理解为p原来指向数组的首地址,它加1个,记住不是地址字节加一,是变量加一,相当于地址字节加4(int是4个字节)。那么自然原来p指向a[0],变成了p+1指向a[1],但实际p还是指向a[0]

        7、指针int a[4], int* p=a; p++ —————>代表的是p=p+1;指针变量加一之后,赋值给本身,p的指向变了,变成指向a[1];      a++——–>报错,语法错误。   

        8、指针与数组的重要连等式:   int a[10]={0}; int* p= &a;i是变量,用i代表数组10个元素脚标 

                表示地址         a+i==p+i==&a[i]==&p[i]            表示元素a[i]==p[i]==*(p+i)==*(a+i)

        9、*p++ 和 *++p的区别:  首先要清楚*  和++  都是运算符,和数学里面一样,计算是由优先级的,*和++ 优先级为同级别2,但是它们遵循从左往右计算。所以都是先看p++或者++p ,之后再考虑取值运算*的结果。

二、  数组指针之————-指针的小弟,数学是不会骗人的

        数组指针都叫指针了,那么本质上是指针,所以要关注他的指针类型和指向类型。

        先定义一个数组指针,有个直观的感受:  int (*p)[5]———->这是一个指向一维数组的指针变量p。     

        开始解释: ()、[]、*这三个是运算符,遵循数学规律,优先级问题。()、[]为一级,*为二级。一级别的运算符和二级的不一样,同级别按照从左往右的顺序依次计算。(*p)—>代表这是个指针。int [5]———->代表这是个元素类型为int,元素个数为5的无名一维数组。所以指针变量p的类型为int(*)[5], 指向类型为int [5]。指向了一个一维数组。

        那么学习这个有啥用?  —————为了在函数运行中进行二维数组的传参。下面简单的说下二维数组的理解。

        <——————————-讲个简单的应用——————–>

        二维数组传参到函数,传的还是数组的首地址,它可以是二维数组的名,也可以是a[0]。

#include<stdio.h>
void my_hS(int(*p)[4],int n)
{    
    int i,j;
    for(i=0;i<n;i++)
    {
        for(j=0;j<4;j++)
        {
            printf(“%d”,p[i][j]);
        }
        printf(“\n”);
    }
}
int main(int argc, const char *argv[])
{
    int b[3][4]={ {1,1,1,1},{2,2,2,2},{3,3,3,3}};
    my_hS(b,3);
    return 0;
}

支线任务一:二维数组的解释之———–我的爸爸是一维数组

        二维数组可以看成是一维数组组建构成的,例如:二维数组的a[3][4],第二个脚标代表列数(人为的把它当成矩阵看,其实不是矩阵),上面的二维数组a,它是由一维数组a[3]构成。现在这个a[3]不是元素了,是名字。

三 、指针数组之————–我和指针不是一家的,他是指针,我是数组,他姓指,我姓数

        指针数组,本质上是数组,定义一个数组,里面存的是指针。

        定义个数组,举个例子:int *p[3],   老规矩,数学是不会骗人的,[]优先级一级,*优先级二级。p和[3]是一家的,是个数组,元素个数是三。int*是一家的表示数组里面存的是指针。

        讲完了。。。。下面举个小栗子浅浅的体会下:

 ———————————–>举个例子<———————————-

#include<stdio.h>

int main(int argc, const char *argv[])
{
    char a[]=”hello”;
    char b[]=”hi”;
    char c[]=”bye”;
    char* p[3]={a,b,c};  //存了三个地址,也可以说存了三个指针变量
    int i;
    for(i=0;i<3;i++)
    {
        puts(p[i]);
    }
    return 0;
}

 四、二级指针之———————俄罗斯指针套娃

        讲个故事,从前有个n级指针它是个俄罗斯套娃,里面套了个n-1级指针,n-1级指针套了个n-2级指针……..2级指针套了个1级指针,1级指针套了个猴子(其他变量、函数等等的地址)。

        首先我们要明确,指针无论是几级的里面存的东西都是个地址。

        举个例子:int a=10; int* p= &a;  int** s =&p;    —–>首先p这个一级指针存的是变量a的地址。指针变量p也是变量啊,它也有它自己的地址,那就是&p  ,二级指针就是存一级指针的地址的。特别说明,改变*p的值就相当于改变a的值,改变*s就相当于改掉一级指针p的指向。

        几个重要等式:**s==*p==a ==10———–里面是值  *s=p=&a    指向a的地址

                                s=&p   s指向p的地址

        ——————————->举个小小的例子<———————————–

        

#include<stdio.h>
#include<stdlib.h>
void my_dongT(int **s)
{
    *s=malloc(4*sizeof(int));
    if(*s==NULL)
    {
        printf(“申请空间失败\n”);
    }

}


int main(int argc, const char *argv[])
{
    int i;
    int *p;            //现在我要改变p的指向
    my_dongT(&p);
    for(i=0;i<4;i++)
    {
        p[i]=i;
    }
    for(i=0;i<4;i++)
    {
        printf(“%d\n”,p[i]);
    }

free(p);
    return 0;
}

五、函数指针———之我姓指,不姓函,并且数学不是骗人的

        函数指针,本质是个指针,要研究它的指针类型和指针指向类型。

        定义个函数指针,举个例子:int (*p)(int int ),这个指针名叫p,指向的类型是int (int int)返回值类型是int,两个参数为int的函数。这个指针存的是一个函数的地址,函数的名字就是该函数的首地址。

  —————–>举个例子加法<—————–      

#include<stdio.h>


int my_jia(int a,int b)
{
    return a+b;
}


int main(int argc, const char *argv[])
{
    int (*p)(int, int)=my_jia;
    printf(“%d\n”,(*p)(3,5));        //*p代表,顺着p里面存的地址把函数my_jia调用出来。

//   上一句也可以写成printf(“%d\n”,p(3,5));        //这直接把p和my_jia等价了.
    return 0;
}

ps:重要说明:int my_jia(int a,int b)           int (*p)(int, int)=my_jia;          —–>相当于p=my_jia;

        my_jia是函数的首地址吧,p也是,所有p和my_jia都指向这个函数,所以可以直接用

        调用时候可以写      (*p)(3,5)=========p(3,5)

六、指针函数———-之我是函数,不是指针

        指针函数,本质上是个函数,他的返回值类型是指针:

        定义个指针函数,举个例子: int* num(int a,int b),这个函数的意思是参数类型为2个int型,返回值类型是个int*,是个地址。那么主函数或者其他函数接受其返回值的变量肯定是个指针!!

——————————>举个例子查找字符串中字符是否存在,存在返回其地址,打印<————-

#include<stdio.h>

char* is_within(char* s,char ch)
{
    int i=0;
    while(s[i]!=’\0′)
    {
        if(s[i]==ch)
            return &s[i];
        i++;
    }
    return NULL;
}

int main(int argc, const char *argv[])
{
    char a[100]=”hello”;
    char* p=is_within(a,’l’);
    if(p==NULL)
    {
        printf(“没有找到\n”);
    }
    else
    {
        printf(“找到了\n”);
    }
    return 0;
}

 

        以上的内容,纯属自己的理解,如果和官方解释有冲突的,请以官方为主,其中有不妥的或者错误的地方,请评论区狠狠的喷我,给我指出来,让我长长记性。

        最后祝大家早日成神。

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
xiaoxingxing的头像xiaoxingxing管理团队
上一篇 2023年12月21日
下一篇 2023年12月21日

相关推荐