(十四)C语言之指针

        说到指针,我真的想多说两句闲话。

        指针在我看来,就是一个分水岭,如果你不会指针,你即使再牛B,也厉害不到哪去。反过来,如果你会指针,你即使再菜,你也菜不到哪去。C语言的指针有一种独特的魅力,学会它,那以后学习C语言,使用C语言就会得心应手,我们可以使用指针直接操作最底层的东西,想干嘛就干嘛。但是同时指针也是最难学的,说他难,不是难在使用,是难在灵活使用。

        想必有学过指针的小伙伴都被“段错误”搞过。这种bug是最难找的,大概率事出现在你的逻辑上,这种bug,要改就要改一大片。小伙伴也不要慌张,只要按照语法规则,细心细心再细心,段错误是可以被避免的。

        小伙伴们加油,让我们来学习指针吧~


目录

1、内存的概述

1.1 地址编号

1.2 地址、指针、指针变量的区别

2、指针变量的定义

2.1 定义步骤

2.2 如何建立普通变量和指针变量的关系

2.3 指针变量的初始化

2.4 如何判断变量是什么(怎么读)

3、指针变量的类型

3.1 指针变量的自身类型

3.2 指针变量的指向类型

4、指针变量指向类型的作用

4.1 决定变量取值范围

4.2 决定加减的幅度

 5、& 和 * 的关系

6、万能指针

7、指针操作的注意点(有效防止段错误)

7.1 不能直接操作万能指针,万能指针使用必须强转

7.2 不能对未初始化的指针变量取值

7.3 不要对初始化为NULL的指针变量取值

7.4 操作指针变量时不能越界


1、内存的概述

1.1 地址编号

在32位操作系统中,系统会给每个进程分配一个4G(0x0000 0000 ~ 0xffff ffff)的空间,其中,每一个字节都会分配一个地址编号(占4字节),相当于这个地址编号指向的就是内存空间

在64位操作系统中,地址编号占8字节。

计算机最小分配单位是字节。

计算机最小存储单位是二级制位。

1.2 地址、指针、指针变量的区别

地址:强调的是地址编号

指针:强调的是地址编号的类型,决定了内存访问的深度。

指针变量:本质是个变量,存储的是地址编号。

2、指针变量的定义

2.1 定义步骤

  1. 将*和指针变量名结合
  2. 将上面的整体看成变量名,定义你所需的变量。

例1:定义一个指针变量p,可以保存int data的地址。

int *p;

例2:定义一个指针变量p,可以保存int data[3]的地址。

int (*p)[3];

例3:定义一个指针变量p,可以保存int func(int a,char b)的地址。

//定义函数指针时,需要将形参变量去掉,只保留形参类型
int (*p)(int,char);

2.2 如何建立普通变量和指针变量的关系

//定义普通变量
int data = 10;

//定义指针变量
int *p;

//将p保存data的地址
p = &data;

注意 :定义时 * 代表这个是指针变量。

           使用时 * 代表取内容,*p等价于data

           &是取地址符,&data意思是获取data的地址

指针指向的是变量,指针保存的是变量的地址编号。

2.3 指针变量的初始化

C语言中有一个关键字是 NULL ,他代表什么也不指向,代表空

指针变量初始化可以写成,任何指针变量都可以初始化为NULL

int *p = NULL;

不能对未初始化 或者 初始化为NULL 的指针变量取内容,这样会导致段错误。

注:段错误就触发的情况有许多,最常见的是操作非法内存,读了不能读的,写了不能写的。

2.4 如何判断变量是什么(怎么读)

当遇到一个不认识的变量,不知道怎么读时,不要慌,可以用以下方法。

  1. 根据优先级,分别读出各个部分代表什么,注意不要去掉()
  2. 倒着把各个部分读出来

例:int (*arr[5])(int,int);是什么?

答:第一步:(指针数组)(函数)

       第二部:函数指针数组

       所以int (*arr[5])(int,int);是一个 函数指针数组

解析:本质是个数组,保存的是返回值为int,形参为(int,int)类型的函数指针。

3、指针变量的类型

指针变量的自身类型和指向类型实在定义的时候确立的。

3.1 指针变量的自身类型

指针变量的自身类型,是将变量名去掉,剩下的部分为自身类型

一般用于赋值语句中

例:int *p;          自身类型是   int *

       int **p[3]      自身类型是   int **

       int (*p)(int,char);       自身类型是   int (*)(int,char)

3.2 指针变量的指向类型

指针变量的指向类型,是将变量名和一个*去掉,剩下的部分是指向类型

一般用于决定指针变量的指向深度和单位跨度中

例:int *p;          指向类型是   int 

       int **p[3]      指向类型是   int *

       int (*p)(int,char);       指向类型是   int (int,char)

4、指针变量指向类型的作用

4.1 决定变量取值范围

指向类型决定取值是的范围

注:大端存储和小端存储问题在以后得网络编程中会讲到(这里可以不用关注)。 

4.2 决定加减的幅度

 5、& 和 * 的关系

&为取地址符,与变量结合可以去这个变量的地址

*为取内容,与指针变量结合是取这个指针变量所指向的值。

在定义时*代表指针变量的意思。

可以对指针变量取地址,因为指针变量本质是变量。

int *p;//为一级指针

int **p;//为二级指针

以此类推;

注意:在使用时 * 和 & 可以从右往左相互抵消 。

例:*&*&*p == *p;

       &*&p == &p;

6、万能指针

我们在前面学过一个关键字 void

void是一个空类型,不能使用void定义普通变量,因为无法为变量开辟空间。

void data;//错误,无法为data开辟空间

但是,可以用void定义指针变量,应为不管是什么类型的指针变量,所占用的内存空间都是一样的,32为操作系统为4B,64位操作系统为8B。

void *p;//正确,32位操作系统下指针变量p占4B空间

我们称p为万能指针,可以保存任何类型的一级地址编号。

注意:如果定义了 void *p;

  1. 不能 *p ,即不能对p去内容,应为无法根据屏的指向类型确定取值宽度。
  2. 不能p+1.无法根据p的指向类型确定单位跨度。
  3. 如果想使用p,必须对p进行强转。
  4. 万能指针一般用于函数形参,提高函数通性。

7、指针操作的注意点(有效防止段错误)

7.1 不能直接操作万能指针,万能指针使用必须强转

如果定义了 void *p;

  1. 不能 *p ,即不能对p去内容,应为无法根据屏的指向类型确定取值宽度。
  2. 不能p+1.无法根据p的指向类型确定单位跨度。
  3. 如果想使用p,必须对p进行强转。
  4. 万能指针一般用于函数形参,提高函数通性。

7.2 不能对未初始化的指针变量取值

如果定义了 int*p;

不能*p,应为p未初始化,内容不确定,*p的话就是从一个不确定的地址上取内容,容易出现段错误。

7.3 不要对初始化为NULL的指针变量取值

如果定义了 int *p = NULL;

不能*p,应为p初始化为NULL,*p是从地址编号0的位置取值,一般地址编号0是系统必要的内存结构,不允许用户操作,会出现段错误。

7.4 操作指针变量时不能越界

如果执行了以下语句:int data = 10;

                                    int *p = &data;

                                    p++;

如果此时对p取内容,即*p,就会操作非法内存空间,这就是所谓的指针变量越界,容易出现段错误。

好了,看到这里,指针的基本概念就差不多了,下一章,我们来讲讲指针变量在编写代码的时候具体怎么用。 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值