数组与指针初识

一、指针

1.指针是什么?

指针本质是一种数据类型(如int double),在内存中占4个字节(例如int *p)

任何数据类型我们都可以把他想象成一个模具,任何一个模具都有特定的大小,形状。假设形状有个“int”的数据类型,相当于一个占4个byte的模具(32位系统),拿着模具在内存上咔咔咔,不同大小的内存就分配好了,当然别忘了给它们取个好听的名字(int a)。
同理指针也是一个这样的模具,他在内存中占4个byte,指针大小不随类型改变而改变,如int *p;
double *p1都是占4个byte(这里说的都是32位系统)。可以测试一下 sizeof(void *)

2.指针在内存中是什么样的呢
在这里插入图片描述
这里可以理解为指针类似的生活例子:
假设有一个盒子(4byte),里面存放了一把钥匙,钥匙上有一个牌子上面写着钥匙的编号名字,
以及钥匙对应的哪一个珠宝盒子的序列号(即内存地址)。利用钥匙打开珠宝盒子(*),取出珠宝。

在这里插入图片描述

2. 星号(*)如何理解?
星号(*)就像一把钥匙,打开某块地址空间的门,取出里面的数据。使用指针的时候,需要这把钥匙来读写某块内存。

3.理解int *p = NULL 和 *p= NULL的区别
(1) int *p = NULL;在这里插入图片描述
这句代码的意思是:定义一个指针变量 p,其指向的内存里面保存的是 int 类型的数据;在定义变量 p 的同时把 p 的值设置为0x00000000,而不是把*p 的值设置为 0x00000000。这个过程叫做初始化,是在编译的时候进行的。

(2)int *p; *p = NULL;
在这里插入图片描述
这句代码的意思是:定义了一个int型指针变量p,其指向
的内存里面保存的是 int 类型的数据;但是这时候变量 p 本身的值是多少不得而知,也就是说现在变量 p 保存的有可能是一个非法的地址。所以给非法地址赋值会报告一个内存访问错误。

*(3)int i= 10;int *p = &i; p= NULL;
在这里插入图片描述
定义一个定义了一个int型指针变量p,指向变量i的地址,p指向的内存里面存放的是10。
在这里插入图片描述
r当执行到*p =NULL; p的自身值并没有改变,但是p指向的内存里的值变成了0。
注意 NULL 就是 NULL,它被宏定义为 0:
#define NULL 0

二、数组

1.什么是数组?
数组是一种复合的数据类型,数组(Array)是有序的元素序列。 若将有限个类型相同的变量的集合命名,那么这个名称为数组名。

2.数组的内存布局
例如:int a[5];
在这里插入图片描述
3.数组名字的含义
数组名字作为右值时,代表数组首元素的首地址,而不是数组的首地址。这里&arr[0]和&arr 到底有什么区别呢? arr[0]是一个元素, a rr是整个数组,虽然&arr[0]和&arr的值一样,但其意义不一样。
在这里插入图片描述

在这里插入图片描述
目前数组第一个元素为0。
在这里插入图片描述
第一个元素变成了5。

4数据各个位置表示含义以及所占内存。
在这里插入图片描述
结合上诉指针的概念不难理解其结果。

三、指针与数组的关系

结论:他们之间没有任何关系!
1.为什么我们总是觉得他们很相似呢?
是因为访问方式相似。
例如
A),char *p = “abcdef”;
B),char a[] = “123456”;
2.以指针的形式访问和以下标的形式访问指针
例子 A)定义了一个指针变量 p, p 本身在栈上占 4 个 byte, p 里存储的是一块内存的首地址。这块内存在静态区,其空间大小为 7 个 byte,这块内存也没有名字。对这块内存的访问完全是匿名的访问。比如现在需要读取字符‘e’ ,我们有两种方式:
1),以指针的形式: *(p+4)。先取出 p 里存储的地址值,假设为 0x0000FF00,然后加上 4 个字符的偏移量,得到新的地址0x0000FF04。然后取出 0x0000FF04 地址上的值。
2),以下标的形式: p[4]。编译器总是把以下标的形式的操作解析为以指针的形式的操作。 p[4]这个操作会被解析成:先取出 p 里存储的地址值,然后加上中括号中 4 个元素的偏移量,计算出新的地址,然后从新的地址中取出值。也就是说以下标的形式访问在本质上与以指针的形式访问没有区别,只是写法上不同罢了。

3.以指针的形式访问和以下标的形式访问数组
例子 B)定义了一个数组 a, a 拥有 7 个 char 类型的元素,其空间大小为 7。数组 a 本身在栈上面。对 a 的元素的访问必须先根据数组的名字 a 找到数组首元素的首地址,然后根据偏移量找到相应的值。这是一种典型的“具名+匿名”访问。比如现在需要读取字符‘5’ ,
我们有两种方式:
1), 以指针的形式: *(a+4)。 a 这时候代表的是数组首元素的首地址, 假设为 0x0000FF00,
然后加上 4 个字符的偏移量,得到新的地址 0x0000FF04。然后取出 0x0000FF04 地址上的值。
2),以下标的形式: a[4]。编译器总是把以下标的形式的操作解析为以指针的形式的操作。 a[4]这个操作会被解析成: a 作为数组首元素的首地址,然后加上中括号中 4 个元素的偏移量,计算出新的地址,然后从新的地址中取出值。
由上面的分析,我们可以看到,指针和数组根本就是两个完全不一样的东西。只是它们都可以“以指针形式”或“以下标形式”进行访问。一个是完全的匿名访问,一个是典型的具名+匿名访问。一定要注意的是这个“以 XXX 的形式的访问”这种表达方式。
另外一个需要强调的是:上面所说的偏移量 4 代表的是 4 个元素,而不是 4 个 byte。只不过这里刚好是 char 类型数据 1 个字符的大小就为 1 个 byte。记住这个偏移量的单位是元素的个数而不是 byte 数,在计算新地址时千万别弄错了。

5.a和&a的区别
正如前面所提到的数组名a作为右值,代表的是数组的首元素的首地址,也就是&a[0],这里&a[0]的类型前面也提到了是int型。sizeof(&a[0])==4; &a代表数组的首地址,数组的长度为sizeof(T)乘以数组个数。不难分析以下代码。

main()
{
int a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1); 
printf("%d,%d",*(a+1),*(ptr-1)); //输出结果为2,5
}
对指针进行加 1 操作,得到的是下一个元素的地址,
而不是原有地址值直接加 1。所以,
一个类型为 T 的指针的移动,以 sizeof(T) 为移动单位。 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值