C语言阶段(4)——指针

一、C语言的指针

程序是需要载入内存中运行,内存是有范围的,对于32位系统,内存地址范围是0x0000_0000~0xFFFF_FFFF,也就是内存大小为4GB,内存地址指的是内存中单元的编号,编号是固定的。
所以内存地址(存储单元的编号)本质就是一个整数,对于32位系统而言,地址所对应的编号是4字节的正整数。
用户想要访问内存地址下面的数据是比较麻烦的,因为地址比较难记忆,内存地址都是由内核管理,所以C语言规定用户有权利对内存地址进行命名,比如变量名字、数组名字.........,所以标识符就可以和操作系统提供的内存单元建立映射关系。
思考:既然用户可以定义变量来存储数据,那能否把内存地址当成数据存储在一个变量中?
回答:是可以的,因为存储单元的地址本质就是一个整数,如果是在32bit系统下,则只需要4个字节的存储单元就可以完成存储。
思考:既然内存地址可以当做数据存储在一个变量中,那内核如何区分变量中的数据是作为普通数据还是作为内存地址呢?
回答:操作系统不需要区分,但是作为用户而言,需要区分该变量下存储的是地址还是普通整数,所以C语言表中规定:用户如果打算定义一个变量来存储一个内存地址,则需要定义变量的时候指明该变量中存储的是一个地址。
C语言中把用于存储地址的变量称为指针变量,因为通过变量中的地址可以指向某个存储单元!  指针指向的是地址,所以可以把指针理解为地址,也可以把地址当做指针使用,注意:如果打算获取某个地址下的值,必须使用 * 间接运算符 , *地址 == 地址下的值

指针变量定义格式:数据类型  *变量名;   比如 int  *p;  or  char  *p;  or  int * buf[5];

思考:既然指针变量可以存储一个内存地址,那请问内核是否会为指针变量分配内存空间?
回答:当然会分配,因为定义变量的目的就是为了申请内存单元,32bit系统下需要4个存储单元才能记录一个地址,而记录的地址和变量本身的地址是不一样的。变量的存储单元就相当于是一个容器,记录的地址就相当于数据而已。
思考:用户定义了一个指针变量,但是此时并没有打算让该指针变量指向某个内存地址,请问内核分配给指针变量的内存空间中是否会存储一些未知的数据?如果存在,应该如何解决?
回答:是会的,所以为了提高程序的可靠性,为了避免异常出现所以就算不存储有效地址,也应该对定义的指针变量进行初始化,注意:对指针变量进行初始化,则应该把指针变量对应的内存初始化为0,但是0只是一个整数,并不是地址,而指针变量就是应该存储地址。
用户应该把普通整数0进行强制转换,转换为一个地址 0x00000000 --> (void  *)0x00000000
int  *p = (void *)0x00000000; //可读性较差,所以C语言中提供了一个宏定义 NULL 空指针
可以看到,linux系统的内存中有一部分内存是属于 保留区,保留区地址范围就是0x0000_0000 ~ 0x0804_8000,属于用户没有权限访问的内存空间,一旦用户访问这块区域,就会导致段错误。
int  *p = NULL;  //对指针变量进行初始化,目的是防止野指针出现,为了避免段错误的!!!
思考:已经知道内存中有一块保留的空间,程序是没有权限访问的,但是用户能否定义一个指针变量指向这块空间?
回答:是可以的,但是只能用指针变量记录该地址,但是不能通过指针变量间接访问该地址,如果间接访问,则会导致内存异常,发生段错误。
思考:既然指针变量中存储的是一个内存地址,内存地址的本质就是一个整数,所以能否对整数进行算术运算呢?
回答:是可以的,只不过普通整数的算术运算和地址的算术运算的理解是不同的,一般对于普通整数可以进行算术运算,则结果也是一个整数。
但是对于指针变量中存储的地址进行算术运算,一般只能进行加法运算和减法运算,对地址进行加法运算和减法运算,其实就是对地址进行偏移而已,偏移的单位一般是应该以字节为单位。
注意:对于指针变量的偏移,要考虑到变量中存储的地址的数据类型,所以 地址 + 1 不表示存储单元向后偏移1个字节,应该是向后偏移 (1 * 数据类型)个字节。
思考:既然可以用指针变量指向另一个变量的地址,请问能否用指针变量指向数组的地址?
回答:当然可以,就相当利用指针变量来对数组的地址进行备份,提高了访问数组的安全性,而利用指针变量来指向数组的地址,被称为数组指针!!!!     int buf[5];   int  *p = buf;
运算符的优先级和结合性
()> [] > *
如果此时用户需要访问数组中的元素,可以通过数组下标 and 指针访问,两者的区别如下:
笔试题:请分析以下程序,根据自己对程序的理解回答出程序的运行效果,不许讨论和抄袭!
笔试题:请分析以下程序,根据自己对程序的理解回答出程序的运行效果,不许讨论和抄袭!
思考:用户打算定义一个二维数组,并且用一个指针变量来存储数组的地址,现在想用指针变量来访问二维数组中的元素,请问如何访问?
思考:既然数组可以存储同一类型的数据,请问能否在一个数组中存储指针变量的地址???
回答:是可以的,如果在一个数组中,每个元素都是一个指针,则C语言中把这种结构称为指针数组。

指针数组的定义格式: 数据类型  *数组名[元素个数];      // 比如  int  *buf[5];

注意:[]后缀运算符 优先级高于 *间接运算符 ,所以 buf[5] 作为一个整体,剩余部分就是数组中元素的类型,所以 int  *就是数组中元素的类型,其中int是用于修饰指针指向的地址中数据的类型。
思考:既然可以使用一个指针变量来存储另一个变量的地址,能否定义一个指针变量,然后来存储另一个指针变量的地址?如果可以,那如何可以访问到最终内存地址下的数据?
回答:是可以的,如果一个指针变量中存储的地址是另一个指针变量的地址,则把这种结构称为二级指针。

二级指针定义格式: int  data; //整型变量  int  *p1 = &data; //指针变量  int **p2 = &p1;

练习:用户现在定义一个int buf[5] = {1,2,3,4,5}; 现在用户定义一个数组指针来存储数组的地址, int  *p = buf; 请问 printf(“%d\n”,*p++);   printf(“%d\n”,(*p)++);  请问两句话的输出结果?
字符串常量本身就表示第一个字符的地址

A
ABC

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值