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

来源:互联网 发布:管理系统常用算法 编辑:程序博客网 时间:2024/06/05 14:07

数组和指针并不是一回事。


什么是定义,什么是声明

定义:

     特点:只能出现在同一个地方     作用:确定对象的类型并且为其分配内存,用于创建新的对象,例如: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地址加上下标,需要的字符就在这个地址中。


对指针的引用

相反,如果声明extern char*p,它将会告诉编译器p是一个指针,它实现的对象是一个字符,为了取得这个字符,必须得到地址p的内容,把它作为字符的地址并且从这个地址中取得这个字符,指针的访问要灵活很多,但是需要增加一次额外的提取。
对指针的引用

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

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

现在看一下当一个外部数组的实际定义是一个指针,但是却以数组的方式对其引用时,会引起什么问题。需要对内存进行直接引用,但是这时编译器所执行的是对内存进行间接引用,之所以会如此,是因为我告诉编译器我们拥有的是一个指针。
对指针进行下标引用

具体过程: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";

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

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;不改变
原创粉丝点击