指针——上篇

一.什么是指针

理解指针就要从机器级开始了解.

我们知道在机器中,数据内存中是以一个个字节进行存储的,比如我要创建一个int类型的a变量,并赋值10,那么进行的操作就是申请4个字节的空间,然后在相应的空间将10用二进制表示为补码存进空间里面.

如下图所示:

 那么我们会发现每一个字节都有一个对应的地址,这个地址就被称为指针.

 程序中的变量可能占一个字节或多个字节内存,但我们只把第一个字节的地址作为该变量的地址.

类似于酒店中住着一个个旅客(一个个不同类型的数据),而他们所占房间的门牌号就是一个个地址.

用来存放地址的变量,我们称为指针变量.(存放在指针变量里面的数据都会被默认为地址)

在用指针变量p存储变量i的地址时,我们会说p指向i.换句话说,指针实际上就是地址,而指针变量负责存储地址(指针).

补充:

在大多数情况下,指针和地址是完全相同的

二.指针变量的大小

于是有人会思考,为什么一个字节对应一个地址,不是一个比特位对应一个地址,或者两个字节对应一个地址呢?
 
回答这样的问题,其实自己想想也就清楚,数据是按字节来进行存储的,假如一个比特位一个地址,那地址的数量将会非常庞大,应用起来也不方便,其它想法也是类似,总而言之,我们发现,一个字节对应一个地址,效率是最高的.
那对于32位的机器,假设有 32 根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电平(低电压)就是(1或者 0
那对于32位机器
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001
...
111111111 111111111 111111111 111111111
总共就有2^32个地址
每个地址标识一个字节,那我们就可以给 2^32Byte == 2^32/1024KB ==
2^32/1024/1024MB==2^32/1024/1024/1024GB == 4GB 4G 的空间进行编址
那到这里我们就可以知道:
32 位的机器上,地址是 32 0 或者 1 组成二进制序列,那地址就得用 4 个字节的空间来存储,所以
一个指针变量的大小就应该是 4 个字节
类似可以得到在64位的机器上,一个指针变量的大小就为8个字节
补充:
可能有些人对于为什么一个字节对应一个地址还是有些疑惑
实际上,在一些计算机上,它们确实采用的是字,而不是字节对应一个地址的方式.

假设一个字,占36个比特位,一个字对应一个地址,对于整数来说,一般4个字节,也就是32位就可以表示,现在有36位,因此现在地址(指针)确实就是指向一个整型.

但是我们知道一个字符,只需要一个字节,8位就可以表示,那一个字中,其实可以表示多个字符,现在问题便出来了,我们这个地址(指针),指向的是哪个字符呢?

而在这种情况下,指针并不和地址相同,而是表示偏移量,CPU需要把它和存储在专用寄存器中的段值结合起来.

三.取地址运算符和间接寻址操作符

为了使用指针,C语言开发了两种运算符

第一种是取地址运算符&,顾名思义,&i表示取出变量i的地址

第二种是间接寻址操作符*,假设我们将变量i的地址存到变量p中,通过*p,我们便可以找到i,类似于,知道房间门牌号,便可以相应访问对应房间号的数据.

四.指针变量的声明

指针变量的申明和普通变量声明类似,不过要在前面加上一颗*

值得注意的是,C语言要求指针只能指向一种特定类型(引用类型)的对象

比如:

double *p = NULL;  //指向double类型的指针

int *p1 = NULL;       //指向int类型的指针

float *p2 = NULL; //指向float类型的指针

p指向double类型数据后,就不可能指向int类型,并且也不可能指向多个数据,存储的只是一种引用对象的地址.当然引用对象没有限制,甚至可以指向指针,数组,结构体等等都是可以的.

PS:

指针的类型,决定了指针移动步长和解引用时访问的空间.

如图所示,pc,pi指向的都是n的地址,但是pc+-步长与pi+-步长所移动,得到的地址时不一样的,pc为char*类型,移动的仅仅为1字节,而pi类型为int *,移动的则为4个字节. 

 *pc访问的只是一个字节的内容,因此*pc = 0,仅仅将低位的44改成了00.

*pi为int*类型,解引用访问的便为4个字节的空间因此全部都会赋值为0.

五.指针赋值

1.指针初始化

结合上述两个操作符,我们就可以对指针变量p赋值,变量a的地址便可以存进p中.

*p就可以访问a的空间,因此,a的值我们可以发现,原来是11,后面又被重新改回10l了.

PS:C语言是允许具有相同类型的指针进行赋值的.

比如

 

看上面的程序,p,q都是指针,p存储变量i的地址后,可以赋值给q,此时q同样指向变量i.

这里也可以看出,C语言中任意数量的指针可以指向同一个变量. 

而*q=*p,则是把p指向的变量i的值赋给q指向的变量j,需要注意,两个式子是不同的

2.野指针

野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

野指针出现的情况一般有三种

(1)  指针未初始化
Lg1.
#include <stdio.h>
int main()
{
    int *p;//局部变量指针未初始化,默认为随机值
   *p = 20;
   return 0;
}

假如指针未进行初始化,则p指向随机的地址,如果改变的内存单元属于操作系统,那么很可能会导致系统的崩溃.造成的后果是无法想象的!!!

Lg2.

int* p = &i, i;

这段代码同样也是犯了这个错误,i变量还没有创立,p指针无法指向i,根本就没有初始化,则编译器必然会报错.

Lg3.

出了函数外部,局部变量i就会自动销毁,此时假如用一个指针变量p,接受&i,也是毫无意义的. 

(2)  指针越界访问
#include <stdio.h>
int main()
{
    int arr[10] = {0};
    int *p = arr;
    int i = 0;
    for(i=0; i<=11; i++)
   {
        //当指针指向的范围超出数组arr的范围时,p就是野指针
        *(p++) = i;
   }
    return 0; }
(3) 指针指向的空间释放
malloc动态申请一块空间后,有可能申请失败,此时返回一个空指针,但如果对该空指针进行赋值解引用等操作,一定会引发报错.

3.如何规避野指针

1. 指针初始化
2. 小心指针越界
3. 指针指向空间释放,及时置 NULL
4. 避免返回局部变量的地址
5. 指针使用之前检查有效性
#include <stdio.h>
int main()
{
    int *p = NULL;//指针及时初始化,无地址可赋值为NULL先
    //....
    int a = 10;
    p = &a;
    if(p != NULL)//指针使用前,判断是否位NULL
   {
        *p = 20;
   }
    return 0; 
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
指针是C编程语言中非常重要的概念之一,对于初学者来说可能会感到害怕和困惑。但只要理解了指针的原理和用法,就会发现它其实并不可怕。 首先,指针是一个存储变量地址的变量,它可以指向任何数据类的变量,包括整、浮点、字符等等。我们可以通过指针访问变量的值,也可以通过指针修改变量的值,这是指针的一大优势。 其次,理解指针的应用场景能够帮助我们更好地使用它。比如,当我们需要在函数之间传递大量的数据时,通过传递指针可以提高程序的执行效率。另外,在动态内存分配和释放中,指针也是一个必不可少的工具。 理解指针的用法也是很重要的。首先,我们需要理解指针的声明和初始化。指针的声明使用“类 * 变量名”的语法,例如 int *ptr; 表示声明了一个指向变量的指针指针的初始化可以通过给指针赋值一个变量的地址或者通过取地址符&获取变量的地址。 然后,我们需要了解指针的运算。指针可以进行四种基本的运算:取地址运算符&,取值运算符*,指针加法和指针减法。取地址运算符&用于获取变量的地址,取值运算符*用于获取指针指向的变量的值。指针加法和指针减法用于指针地址的增加和减少,不同数据类指针相加或相减会有不同的结果。 最后,我们需要注意指针的安全性。在使用指针的过程中,需要特别小心避免空指针、野指针等问题的出现,因为这些问题容易引发程序的崩溃或者产生不可预知的结果。 总结来说,指针作为C语言中的重要概念,我们应该尽早学习和掌握。只要理解指针的原理和用法,我们就能够更加灵活地操作内存,提高程序的效率和功能。通过不断的实践和学习,我们可以逐渐摆脱对指针的恐惧,让指针成为我们编程的得力助手。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值