C语言指针和数组那些事儿

指针

题外话:指针真的是学习C语言来觉得最棘手的一部分,很多东西仅仅停留在表面,真正底层的东西却一无所知。有时候越学反而越觉得不懂了,这一篇就稍微总结一下指针的那些事儿。

  1. 关于指针的内存布局:
    首先: int *p;
    很明显,这里定义了一个指针p,那p所占的内存空间是多大呢,我们用sizeof§测试一下,值为8。也就是说一个类型‘int *在内存上占了8个字节的空间。然后把这8个字节的空间命名为p。同时限定这8个字节的空间只能存储某个内存地址,即使你存入任何数据,都将被当作地址处理。

    我们把 p成为指针变量,p里面存储的内存地址出的内存成为p所指向的内存,指针变量p里存储的任何数据都将被当作地址来处理。

我们可以这样简单的理解一下:一个基本的数据类型加上定义指针的符号星号,就构成了一个指针类型的模子,这个模子的大小是一定的,与星号前面的数据类型没有关系,星号前面的数据类型只是说明了指针所指向内存里存储的数据类型,所以,在64位系统下,不管什么类型的指针,其大小都为8byte。

  1. 定义指针的星号如何理解?

    那,这个*怎么理解呢?举一个现实生活中的例子,当你回家走到家门口时,要进房子的第一件事情就是拿出钥匙来开锁。同样的,去读写一块内存也是需要一把钥匙的,这个型号就是我们的钥匙,在使用指针的时候,没有它,是不可能去实现读写一块内存的。

  2. int *p=NULL和 星号p=NULL的区别

    这个问题看起来很简单,但是仔细想想就会有 没什么差别啊 这种感觉。
    我们通过编译器查看p的值为:0x00000000.这句代码的意思是:定义一个指针变量p,祁志祥的内存里面保存的数据类型是int类型;在定义p的同时,把p的值定位0x00000000,而不是把**p的值定为0x00000000.这个过程叫做初始化,是在编译的时候进行的。

    了解过了初始化,再来一个和刚才很相似的代码:

int *p;
*p=NULL;

第一行代码的解释:定义了一个指针变量p,祁志祥的内存里面保存的是int类型的数据;但这个时候变量p的值不知道,也有可能变量p保存了一个非法地址。

第二行代码:给*p赋值为NULL,即给p指向的内存赋值为NULL。但由于p指向的内存有可能是非法的,所以编译器在调试的时候很可能报告一个内存访问的错误。现在,我们将上面的代码稍微改一下:

int i=10;
int *p=&i;
*p=NULL;

再次调试一下,p所指向的内存由10变为0;而p本身的值,即内存地址并没有发生变化这个栗子到这儿,就很清楚了。

  1. 指针与数组

    指针就是指针,指针在32位系统下永远占4byte,在64位系统下永远占8byte.其值为某一个内存的地址,指针可以指向任何地方,但不是任何地方你都能通过这个指针访问到。
    数组呢?数组其大小与元素的类型和个数有关。定义数组是必须指定其元素的个数和类型。数组可以存任何类型的的数据(除了函数哈)。
    所以,指针绝不是数组,两者绝对不可以画等号!!这个误区连我们的的C语言老师都误导了我们这些初学者。
    但其实在某些地方,这两者之间有着很相似的地方。
    先给几行代码:

char *p=''abcdef'';//A
char a[]=''123456''//B

栗子A定义了一个指针变量p,p本身在栈上占了8byte。p里面储存了一块内存的首地址,这块内存在静态区。其空间大小为7byte。这块内存也木有名字,,要对他访问也是匿名访问。比如现在要读取’e’,有两种方式。

第一种:以指针的形式:*(p+4)。先取出p里面存储的地址值,然后再加上4个字符的偏移量。得到新的地址,再取新地址上的值.

第二种:以下标的形式。p[4],编译器总是把以下标的形式的操作解析为以指针的形式进行操作。p[4]的这个操作会被解释成:先取出p里存储的地址值,然后加上中括号中四个元素的偏移量,计算出新的地址,然后取新地址的值,也就是说,以下标的形式访问与指针形式访问从本质上没有什么区别。就是写法上不一样。但具体的内容还是要知道。

栗子B定义了一个数组a,a拥有7个char类型的元素,其空间大小为7。数组a本身在栈上面。对a的元素的访问必须先根据数组的名字a找到数组首元素的首地址,然后根据偏移量找到它的值。这是典型的“具名+匿名”的访问。也有两种方法。

第一种:以指针的形式*(a+4),a这时候代表的是数组首元素的首地址,然后再加上四个字符的偏移量,得到新的地址,再取出新地址的值。
第二种:以下标的形式:a[4]。a作为数组首元素的首地址,然后将上中括号中四个元素的偏移量,计算出新的地址,然后从新地址中取出值。

综上分析,数组和指针根本就是两码事,只不过在访问时,都可以"以指针形式"和“以下标的形式”两种方式进行,但实际意义却完全不同。一个是完全匿名的访问,一个是“具名+匿名”访问。一定要注意这一点

另外,关于这个例子的解释还有一个地方要强调的是:上面所说的4个偏移量代表的是四个元素。不是4 byte,只不过这里刚好是char类型一个字符的大小就为1 byte。记住这个偏移量单位是元素个数而不是byte数,在计算地址时可别弄错了奥。

5.a和&a的区别
再来一个栗子:

int main()
{
  int a[5]={1,2,3,4,5};
  int *ptr=(int *)(&a+1);
  printf("%d %d",*(a+1),*(ptr-1));
  }

这里打印出来的值是多少呢?这是有关于指针加减操作的问题。
对指针进行加1操作,得到的是下一个元素的地址,而不是这一个元素的地址值加一。所以一个类型为T的指针移动,以sizeof(T)为移动单位
因此对上题来说,a是一个一维数组,数组中有5 个元素,ptr是一个int类型的指针。

&a+1:取数组a的首地址,改地址上的值加上sizeof(a)的值,即&a+5*sizeof(int),也就是下一个元素的首地址,显然当前指针已经越过了数组的界限。

(int *)(&a+1):则是把上一部计算出来的地址,强制转换成int 星号类型,赋值给ptr。

*(a+1):a,&a的值是一样的,但意思不一样,a是数组首元素的首地址,也就是a[0]的首地址,&a是数组的首地址,a+1是数组下一元素的首地址,即a[1]的首地址。&a+1是下一个数组的首地址,所以输出为2。

*(ptr-1):因为ptr是指向a[5],并且ptr是int *类型,所以它是指向a[4],输出结果为5。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值