<C和指针---读书笔记8>

数组 , 数组是C语言的一种数据类型。 我们先从一维数组讲起.

声明和初始化

type  数组名[n]  : 声明了一个数组,它由n个元素组成,且这n个元素均是 type类型。

编译器进行初始化时,会为其分配 n个type型存储空间. 如int a[4];

在声明时, 编译器需要为其分配空间,所以需要知道数组的长度信息,类型信息。

int b[] ; 就是非法的。 int b[] = {1,2,3,4};是允许的。原则就是能提供长度信息与否。

数组名的纠纷

我们知道a[0]表示元素0、a[1]表示元素1. 那单字母a表示什么?按道理应该是整个数组的简写。

但实际上并非如此简单。其实,在编译器进行编译时,会有一个记录表格: 它记录了代号---地址的关系.

显然,如果仅仅是int x ; 它记录 x --- addr_880 . 以后访问x,都是去访问的880地址。

指针变量也是如此, int *p ,它也会记录 p ---- addr_990 .

但到了数组名这里就不一样了,因为数组名不是一个变量,它不拥有自己的存储领地, 但编译器仍然记录了下来对应关系.

它记录的是:   数组名 ------ 首个元素的地址 . 

我们已经知道了记录的关系了,那在编译过程中,遇到数组名, 编译器将会做什么操作?

下标的引用

在普通的操作中,我们接触到的b[2]。编译器遇到这种形式: 都会先把它们翻译成间接操作*(b+2) .

为什么要翻译成间接操作呢?  因为它本质上想表达的意思是:  访问数组b的第三个元素。

因为编译器没有记录各个不同元素的地址信息,只记录了首元素的地址信息,并对标给了数组名b,所以要把这里作为突破口.

*(b+2)  = *(首地址+偏移)。 很明显,编译器在执行这个b+2中,如果只是简简单单的+2,就没有任何的物理意义了。

编译器执行的将是:  b + 2* sizeof (int),从而能顺利的访问 b[2]元素。

指针的介入

我们知道,指针变量,可以指向任意内容.如果我们把指针指向了 数组的第一个元素.

int arry[10] ;

int *ap = arry;  (把地址存入ap变量内)  

int *ap = arry +2  (把"地址+2 * sizeof (int) "存入ap变量内,即把元素2的地址存入指针变量内)

这时候,对指针进行间接访问, 均是访问的元素2.   

ap

指针常量,指向元素2   (编号从0开始)

*ap

左值:存入元素2内;  右值,获取元素2内的值

Ap[0]

从字面上,我们觉得这是错的,因为ap是个指针啊,它又不是数组,你怎么对它进行这种操作呢?

其实:我们记得下标引用时 间接访问的一种伪装。所以这个依旧是间接访问的一种 *(arry + 0) = *ap

用作左值:存入元素2内;右值,获取元素2内的值

Ap+6

Ap是一个指针,指针的加法 = + 6*sizeof(int)

所以是指向 元素8

*ap+6

arry[2]的内容+6

*(ap+6)

用作左值:存入元素8内;右值,获取元素8内的值

ap[6]

同理, ap[6] = *(arry + 6) ,跟上面一样

&ap

显然是获取指针变量的地址。

Ap[-1]

Ap[-1] = *(arry -1 ) ,

用作左值:存入元素1内;右值,获取元素1内的值

Ap[9]

Ap[9] = *(arry +9)  超出了范围。是很冒风险的事

2[aary]

依旧是合法的,很奇怪是吧,

2[arry] = *(2+arry) = *(arry+2)

指针表示还是b[n]表示

我们可以通过定义一个指针,并让它指向数组的首地址,通过加减指针变量,完成访问。 也可以通过b[n]来访问数组元素。

各有利弊,b[n]看起来易读、易于维护。指针形式效率 ≥ b[n]形式

数组用作函数参数

在子函数定义时,我们时常会把一个数组当成参数的一份子. 

在子函数body中,我们通常也会对其进行访问操作,使用的无非是指针,或者b[n]形式。 最终编译器都将这些操作

转换成了*(b+2)  = *(首地址+偏移) 操作. 显然我们只要知道 首地址信息就够了. 即子函数定义时,我们的参数列表,

只要指定一个数组名就可以了,不必指定长度了. 

在函数调用前的 函数原型声明时, 传进来的参数也是要是一个数组的首地址就够了,你可以用数组名的方式,也可以用指针的方式.

 

 

原文地址:https://www.cnblogs.com/mokang0421/p/7482548.html