zoukankan      html  css  js  c++  java
  • <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)  = *(首地址+偏移) 操作. 显然我们只要知道 首地址信息就够了. 即子函数定义时,我们的参数列表,

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

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

     

     

  • 相关阅读:
    linux 命令——48 watch (转)
    linux 命令——47 iostat (转)
    linux 命令——46 vmstat(转)
    linux 命令——45 free(转)
    linux 命令——44 top (转)
    linux 命令——43 killall(转)
    linux 命令——42 kill (转)
    linux 命令——41 ps(转)
    linux 命令——40 wc (转)
    Java for LeetCode 068 Text Justification
  • 原文地址:https://www.cnblogs.com/mokang0421/p/7482548.html
Copyright © 2011-2022 走看看