C语言的数组和指针_《C专家编程》读书笔记

数组和指针并非一回事。


什么是定义,什么是声明

定义:

特色:只能出如今同一个地方
     做用:肯定对象的类型而且为其分配内存,用于建立新的对象,例如:int my_array[100];

声明

特色:能够出现屡次      
    做用:描述对象的类型,用于指代其余地方定义的对象,例如:extern int my_array[];

如何区分定义和申明

声明至关于普通的声明:它所说明的并不是自身,而是描述其余地方的建立的对象。
   定义是特殊的声明:它在定义的时候已经分配了内存空间。

extern对象的声明告诉编译器对象的类型和名字,对象的内存分配在别处进行。因为并未在声明中为数组分配空间。随意不须要提供关于数组长度的信息,对于多维数组,须要提供除了左边第一维以外的其余维度的长度 ——这就给了编译器足够的信息产生相应的代码。数组


数组和指针如何访问。数据结构

什么是左值,什么是右值:

1:什么是“地址y”“地址y的内容”,这是一个很是微妙的地方,在大多数的语言中使用同一个符号来表示这两样东西。编译器会根据上下文环境来判断他的具体含义。
以一个简单的赋值为例:
X=Y;
首先看看X:
在这个上下文中,X的含义是X所表明的地址,这被称为左值,左值在编译时可知,左值表示存储结果的地方。
再看看Y:
在这个上下文环境中,Y的含义是Y所表明的地址的内容。这被称为右值,右值直到运行时才知,如无特别说明,右值表示“Y的内容”。函数

C语言引入了“可修改左值”这个术语,它表示左值容许出如今赋值语句的左边,这个概念是为了与数组名区分,数组名也用于肯定对象在内存中的位置,也是左值。可是它不能做为赋值对象。所以,数组名这个左值是左值可是不是能够修改的左值。通俗地讲,只能给能够修改的东西赋值。

数组下标的引用

数组的下标引用
数组的下标引用
具体过程:
   char a[9]="abcdefgh"; ... c=a[i];
   编译器符号表具备一个地址9980
       运行时步骤1:取i的值,将它与9980相加
       运行时步骤2:取得地址(9980+i)的内容

这就是为何extern char a[]与extern char a[100]等价的缘由。这两个声明都表示a是一个数组,也就是一个内存地址,数组内的字符能够从这个地址找到。编译器不须要知道数组到底有多长,由于它只会产生偏离起始地址的偏移地址。从数组取一个数字符,只要简单地从符号表显示的a地址加上下标,须要的字符就在这个地址中。ui


对指针的引用

相反,若是声明extern char*p,它将会告诉编译器p是一个指针,它实现的对象是一个字符,为了取得这个字符,必须获得地址p的内容,把它做为字符的地址而且从这个地址中取得这个字符,指针的访问要灵活不少,可是须要增长一次额外的提取。指针


对指针的引用
对指针的引用
具体过程:
char*p ...  c=*p;
编译器符号表有一个符号p,它的地址为4624
       运行时步骤1:取地址4624的内容,就是‘5081’
       运行时步骤2:取地址5081的内容。

定义指针可是以数组方式引用

如今看一下当一个外部数组的实际定义是一个指针,可是却以数组的方式对其引用时,会引发什么问题。须要对内存进行直接引用,可是这时编译器所执行的是对内存进行间接引用,之因此会如此,是由于我告诉编译器咱们拥有的是一个指针。code


对指针进行下标引用
对指针进行下标引用
具体过程:
char*p="abcdefgh";    ...    c=p[i];
编译器符号表具备一个p,地址为4624
       运行时步骤1:取地址4624的内容,即‘5081’。
       运行时步骤2:取得i的值,而且将它与5081相加。
       运行时步骤3:取地址[5081+i]的内容。

数组和指针其余的区别

指针 数组
保存数据的地址 保存数据
间接访问数据,首先取得指针的内容,把它做为地址,而后从这个地址提取数据若是指针有一个下标[I],就把指针的内容加上I做为地址,从中提取数据 直接访问数据,a[I]只是简单地以a+I为地址取得数据。
一般用于动态数据结构 一般用于存储固定数目且数据类型相同的元素
相关的函数为malloc(),free() 隐式分配和删除
一般指向匿名数据 自身即为数据名

数组和指针指向字符串时

数组和指针均可以在它们的定义中用字符串常量进行初始化,尽管看上去同样可是底层的实现机制却不一样。对象

指针

定义指针时,编译器并不为指针所指向的对象分配空间,它只是分配指针自己的空间,除非在定义的同时赋给指针一个字符串常量进行初始化,游戏

char *p="breadfruit";

注意只有字符串常量才是如此,不能期望其为浮点数之类的常量分配空间,如:ip

float *pip=3.141;/* 错误,没法经过编译*/

在ANSI C 中初始化指针时所建立的字符串常量被定义为只读,若是试图经过指针修改这个字符串的值,程序就会出现未定义的行为。在游戏编译器中,字符串常量被存放在只容许读取的文本段中,以防止它被修改。内存

数组

数组也能够用字符串常量进行初始化:

char a[]="gooseberry";

与指针相反,由字符串常量初始化的数组是能够修改的,其中单个字符在之后能够改变,好比下面的语句:

strncpy(a,"black",5);

就将数组的值修改成“blackberry”

何时数组和指针相同

在实际的应用中数组和指针能够交换的状况要比二者不能交换的状况更为常见。
让咱们分别考虑“声明”和“使用”这两种状况
1:声明
1) 外部数组的声明
2) 数组的定义(记住,定义是声明的一种特殊状况,它分配内存空间,并可能提供一个初始值)。
3) 函数参数的声明
全部做为函数参数的数组名老是能够经过编译器转换为指针。
数组的声明就是数组,指针的声明就是指针,二者不能混淆,数组老是能够写成指针的形式二者能够互换。

何时数组和指针相同
何时数组和指针相同

数组和指针参数是如何被编译器修改的
实参 所匹配的参数
数组的数组 char c[8][10] ; char(*)[10];数组指针
指针数组 char *c[15] ; char **c; 指针的指针
数组指针(行指针) char(*c)[64]; char (*c)[64] 不改变
指针的指针 char **c; char **c;不改变
相关文章
相关标签/搜索