深入理解指针

文章来自公众号 : 技术乱舞

原文链接 : https://mp.weixin.qq.com/s/ASJQIK-GXdEqFqEWJeR4ng

深入理解C指针

目录

深入理解C指针

指针概念

指针变量

指针变量的声明

指针变量的使用

指针变量初始化

指针运算

指针与数组

二级指针

*运算符和++运算符的结合

数组名作为指针

二维数组与指针

指针与函数

函数参数为指针

函数返回值为指针

函数指针

指针与结构体

小结

欢迎关注 #公众号:技术乱舞 一起交流


我记不清第十一条戒律是“你应该计算”还是“你不应该计算”了

作为C语言中最重要的角色,可以说没有了指针C语言就没了灵魂,那么就来深入理解一下指针,分别从概念上,与数组的关系,函数指针几方面来理解指针到底是什么。

指针概念

如果你真正明白了指针到底是什么,那么你也肯定懂得计算机内存是如何存储的,大多数计算机把内存分割为字节,一般32位的机器int性32比特,4字节,一字节有8比特数据。

 

上图中就是一个字节8比特的数据,为了区分内存中的每个字节,那么我们就给字节排号,每个字节都有自己专属的字节号,这个字节号就是地址,也就是通过这个地址,我们可以找到这个字节。举个简单的例子就是,作为一名学生,在学校看来,所有学生都一样,为了区分每一个学生,我们都给他排号,每个人都拥有一个学号,通过学号就可以找到这个学生,内存中也是这样。

图片

由此,指针其实指向的就是这块内存中的某个字节的地址,一般来说int型变量有四字节,看如下代码

int tmp = 10;
int  *p = &tmp;

上面两行代码,定义一个int型变量,那么这个p指针指向了这个tmp变量的首地址,就如上图一样。

指针变量

指针变量的声明

指针变量的声明与普通的变量一样,只不过在前面多了一个号,但是也要注意,声明的指针变量是p,q,n,而不是 * p, q,* n。其实一个指针p实际代表另外一个变量的地址,如果前面加上* 变成 * p,那么这就表示这个指针指向地址的变量值了。对于初学者来说,可以把指针理解成普通的变量,只不过这个变量的值是地址的值。

int *p;
double *q;
char *n;

指针变量的使用

使用指针,就不得不提取地址符&,与* 号相反,如果一个变量加上&号,就代表了这是取这个变量的地址值。下面是官方解释。

  • 取地址运算符&:单目运算符&是用来取操作对象的地址

  • 指针运算符*(间接寻址符):与&为逆运算,作用是通过操作对象的地址,获取存储的内容

int *p;
int  a = 10;
p = &a;
printf("%d\n",a);
printf("%d\n",*p);

指针变量初始化

对于指针变量的初始化来说,上文已经多次对指针变量初始化了,一定要注意,声明指针变量如果不指向任何地址,那么一定要让它等于NULL或者为0!

int *p = NULL;

同时一定要注意不要试图使用未初始化的指针变量!

int *p;
printf("%d",*p);

或者有如下操作:

int *p;
*p = 1;

如果把上面的指针直接赋值为1,那么有可能直接导致崩溃,毕竟不知道这个指针上面的地址到底在哪。

指针运算

首先如果一个指针指向了某个其他类型的变量那么 * p 就代表了那个变量的值

(*p)++;
int m = *p - *q ;

类似如上所说,那么还可以比较地址大小,其实就是指针变量中存储的地址大小。

m = p -q;//p 和 q 是指针变量

m代表了两个地址的差值

指针与数组

 首先来看一个例子

int A[10],*p;
p = &A[0];

图片

可以看出此时指针p指向了数组A的第一个数据,也可以这样

p = &A[3];

这样是指向了数组的第四个数据。

图片

还可以进行如下操作:

q = p + 3;

 

二级指针

int **p;

关于二级指针,大可不比害怕,都是纸老虎。说的简单点,现在这个p指针变量是二级指针,那么* p就是这个指针变量指向地址的那个值,但是呢,这个值还是地址值,那么这还不是我们需要的,需要通过这个地址,找到真正的值,那就是 * (* p) ,也就是 ** p ,画图来说明:

图片

*运算符和++运算符的结合

这两个运算符会经常放在一起被用到,如果这篇文章能认真看到这,我想下面的表格,大家也一定能看明白

表达式含义
*p++或者 *(p++)指针指向的那个值之后,自增指针p
(*p)++指针p指向的值自增
*++p或者 *(++p)指针p自增后,指向的那个值
++*p或者 ++( * p)指针p指向的值自增

数组名作为指针

这种情况还是比较常见的,例子如下:

int a[10];
*a = 9;  // a[0] = 9
*(a+1)=8; // a[1] = 8

二维数组与指针

这应该算是指针的天花板之一了,这个明白了,指针真的明白了

    int a[2][2]={{1,2},{3,4}},*p,*q[2];
    p = &a;
    *q = &a[0];
    printf("%d\n",*p);
    printf("%d\n",**q);
//此时 *p = **q = a[0][0]

指针p与上文谈到的指针并无二致,对于q来说是一个指针变量类型的数组,q取的是二维数组第一个数组的首地址,那么* q就是第一个数组中的第一个值。

指针与函数

函数参数为指针

这里举一个最简单的例子

int max(int *a , int *b){
   return  *a   > *b ?  *a : *b;
}
void main(void){
      int b = 3,c = 2;
      int a = max(&b,&c);
      printf("%d",a);
}

这是最常见的,这么用最大的好处就是运行速度更快,减少内存。

函数返回值为指针

int* max(int *a , int *b){
    return  *a   > *b ?  a : b;
}
void main(void){
      int b = 3,c = 2;
      int* a = max(&b,&c);
      printf("%d",*a);
}

这里的程序与上一个几乎没有差异,可以自行体会其中的含义。

函数指针

先来一个例子,还是与之前的类似

int* (*p)(int*,int*);//函数指针
int* max(int *a , int *b){
    return  *a   > *b ?  a : b;
}
int main(int argc,char* argv[]){
    int b = 3,c = 2;
    p = &max;
    int* a = (*p)(&b,&c);
    printf("%d",*a);
    return 0;
}

函数指针对于初学者来说确实难懂,看过很多C语言的书,大多数只是说明了指针的基本含义,这里就相当于把函数看成一个变量,或者说,有一个指针指向的是一个函数,我可以用这个指针代表这个函数。

指针与结构体

关于指针与结构体的知识,在前几期栈和链表的文章中,就是指针与结构体的结合。

typedef struct Node{
    int elements;
    struct Node *next;
}T_Node,*P_Node;

typedef struct Stack{
    int size;
    P_Node list_head;
}T_Stack,*P_Stack;

//初始化栈
P_Stack Create_Stack(void)
{
    P_Stack stack = NULL;
    stack = malloc(sizeof(T_Stack));
    stack->list_head = malloc(sizeof(T_Node));
    stack->list_head->next = NULL;
    stack->size = 0;
    return stack;
}

注意到malloc函数了吗,与分配内存有关的几乎与指针有关,上文定义的P_Node,P_Stack这两个都是结构体指针,作为一个合格的c程序员,这点应该不难理解。

小结

本文详细介绍了指针到底是什么,指针与函数与结构体稍微涉及到,如果是一个c语言初学者,那么就把最基本的指针知识好好理解,熟能生巧,笔者在初学指针的时候,直接被整糊涂了,实践多了,指针到底是怎么工作的也就慢慢理解了。

  

看到上面的图了吗,推荐一本,入门C语言书籍《C语言程序设计现代方法》,这也是我学习C语言的启蒙思想书,年初重新又看了一遍,这本书也一直带在身边,如果网上的知识鱼龙混杂,那么看书是比网络还快的捷径,如果网上推荐谭浩强的书,大可不必,那本书几年前读过,中国人写的书相对来说比较难懂。好了,今天的分享就到这儿了,下期见!

欢迎关注 #公众号:技术乱舞 一起交流

灵魂碰撞

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

艾恩凝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值