指针与数组的关系区别
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
初始化的局部字符数组影响效率,一般应该尽量避开(应该使用的情况下则不要犹 豫)
实际上编译系统将数组元素的形式 a[i]转换成*(a+i),然后才进行运算。对 于一般数组元素的形式:<数组名>[<下标表达式>],编译程序将其转换成:*(< 数组名>+<下标表达式>),其中下标表达式为:下标表达式*扩大因子。整个式
子计算结果是一个内存地址,最后的结果为:*<地址>=<地址所对应单元的地址 的内容>。由此可见,C 语言对数组的处理,实际上是转换成指针地址的运算。
5.指针与字符数组
C 语言中许多字符串操作都是由指向字符数组的指针及指针的运算来实现 的。因为对于字符串来说,一般都是严格的顺序存取方式,使用指针可以打破这 种存取方式,更为灵活地处理字符串。
另外由于字符串以′\0′作为结束符,而′\0′的 ASCII 码是 0,它正好是 C 语言的逻辑假值,所以可以直接用它作为判断字符串结束的条件,而不需要用 字符串的长度来判断。C 语言中类似的字符串处理函数都是用指针来完成,使程 序运行速度更快、效率更高,而且更易于理解。
3.指针与一维数组
理解指针与一维数组的关系,首先要了解在编译系统中,一维数组的存储组 织形式和对数组元素的访问方法。
一维数组是一个线形表,它被存放在一片连续的内存单元中。C 语言对数组 的访问是通过数组名(数组的起始地址)加上相对于起始地址的相对量(由下标 变量给出),得到要访问的数组元素的单元地址,然后再对计算出的单元地址的 内容进行访问。通常把数据类型所占单元的字节个数称为扩大因子。
2.指向数组元素的指针
若有如下定义: int a[10], *pa; pa=a; 则 p=&a[0]是将数组第 1 个元素的地址赋给了指针变量 p。 实际上,C 语言中数组名就是数组的首地址,所以第一个元素的地址可以用 两种方法获得:p=&a[0]或 p=a。 这两种方法在形式上相像,其区别在于:pa 是指针变量,a 是数组名。值得 注意的是:pa 是一个可以变化的指针变量,而 a 是一个常数。因为数组一经被 说明,数组的地址也就是固定的,因此 a 是不能变化的,不允许使用 a++、+ +a 或语句 a+=10,而 pa++、++pa、pa+=10 则是正确的。由此可见,此时 指针与数组融为一体。
一.指针与数组的联系:
指针与数组是 C 语言中很重要的两个概念,它们之间有着密切的关系,利 用这种关系,可以增强处理数组的灵活性,加快运行速度,本文着重讨论指针与 数组之间的联系及在编程中的应用。
1.指针与数组的关系
当一个指针变量被初始化成数组名时,就说该指针变量指向了数组。如: char str[20], *ptr; ptr=str; ptr 被置为数组 str 的第一个元素的地址,因为数组名就是该数组的首地址, 也是数组第一个元素的地址。此时可以认为指针 ptr 就是数组 str(反之不成立), 这样原来对数组的处理都可以用指针来实现。如对数组元素的访问,既可以用下 标变量访问,也可以用指针访问。
而不是 5,在 i 需要值的时候去 0x8291 这个地址去取出值给 i(这里的 i 是全局 的或者静态变量,这时候才能在编译阶段确定地址)。
所以在 Test1.cpp 中,把 array 的地址给了 array,假设这个地址是 0x34fe,但 是由于数组的特性 array == &array,所以这里是正常的。而在 Test2.cpp 中,ar ray 是个指针,所以会去 0x34fe 中取出值给 array,所以 array = 0x0007(数组的第 一个值,这里要做地址,因为是给指针用) 这就是看到的 Test2()的输出结果。显然 array[1]会死机,因为 0x0007 地址是没有 被分配的,并且是给操作系统用的而不是给用户用的。
4//main.cpp
int array[3] = {7, 8, 9}; //全局变量 int main() { Test1(); Test2(); return 0; } //Test1.cpp extern int array[3]; void Test1() { cout << array[1] << endl; } //Test2.cpp extern int *array; //这个地方是不同的 void Test2() { cout << array << endl; cout << array[1] << endl; } Test1()和 Test2()的输出结果相同吗? 编译一下再看看,就发现执行 Test2 会有奇怪的结果,第一条语句的输出是 7,第 二条语句会死机。而 Test1()却一切正常。 这是为什么? 原因在编译器。在 Test1.cpp 中,由于使用了 extern 所以编译的时候要先用占位 符将 array 标志一下,在连接的时候用 main.cpp 中的 array 进行替换。当编译器 给变量赋值的时候,他认为这个值是该变量的地址。就好比:int i = 5;在编译 器中编译后会把 5 的地址 0x8291 记录
1)指向数组元素的指针变量 若有如下说明: int a[3][4]; int *p; p=a; p 是指向整型变量的指针;p=a 使 p 指向整型二维数组 a 的首地址。 *(*(p+1)+2)表示取 a[1][2]的内容;*p 表示取 a[0][1]的内容,因为 p 是指 向整型变量的指针;p++表示 p 的内容加 1,即 p 中存放的地址增加一个整型 量的字节数 2,从而使 p 指向下一个整型量 a[0][1]。 2)指向由 j 个整数组成的一维数组的指针变量 当指针变量 p 不是指向整型变量,而是指向一个包含 j 个元素的一维数组。 如果 p=a[0],则 p++不是指向 a[0][1],而是指向 a[1]。这时 p 的增值以一维数 组的长度为单位。
3.对于问题:为什么用 strcpy()函数时,
char a[3] = "abc"; strcopy(a,"end"); -------------------没有错。 用----------------char *a = "abc"; strcopy(a,"end"); ------------------运行时就有错呢?
解释如下: char *a = "abc"; abc 是一个字符串常量,有它自己的存储空间,因为分配在只 读数据块,我们无法直接访问。这样赋值后,a 只能读,不能写 所以 strcpy(a, "end")不行,只有当你为 a 分配非常量的存储空间后才行 如: char *a = new char[4]; strcpy(a, "end"); printf("%s", a); delete []a;
二.指针与数组的区别:
1.把数组作为参数传递的时候,会退化为指针
数组名作为函数形参时,在函数体内,其失去了本身的内涵,仅仅只是一个 指针;很遗憾,在失去其内涵的同时,它还失去了其常量特性,可以作自增、自 减等操作,可以被修改。 所以,数组名作为函数形参时,其沦落为一个普通指针!它的贵族身份被剥夺, 成了一个地地道道的只拥有 4 个字节的平民。 典型的情况是 void func(int A[]) {
下面的程序成立吗? int intArray[10]; intArray++;
读者可以编译之,发现编译出错。原因在于,虽然数组名可以转换为Fra Baidu bibliotek向其 指代实体的指针,但是它只能被看作一个指针常量,不能被修改。
而指针,不管是指向结构体、数组还是基本数据类型的指针,都不包含原始 数据结构的内涵,在 WIN32 平台下,sizeof 操作的结果都是 4。 顺便纠正一下许多程序员的另一个误解。许多程序员以为 sizeof 是一个函数,而 实际上,它是一个操作符,不过其使用方式看起来的确太像一个函数了。语句 s izeof(int)就可以说明 sizeof 的确不是一个函数,因为函数接纳形参(一个变量), 世界上没有一个 C/C++函数接纳一个数据类型(如 int)为"形参"。
//sizeof(A)得到的是 4bytes } int main() {
int a[10]; //sizeof(a) 得到的结果是 40bytes funct(a); }
2、数组名可作为指针常量
根据结论 2,数组名可以转换为指向其指代实体的指针,所以程序 1 中的第 5 行数组名直接赋值给指针,程序 2 第 7 行直接将数组名作为指针形参都可成立。
数组与指针暗中结合在一起。因此,任何能由下标完成的操作,都可以用指 针来实现,一个不带下标的数组名就是一个指向该数组的指针。
4.指针与多维数组
用指针变量可以指向一维数组,也可以指向多维数组。但在概念上和使用上, 多维数组的指针比一维数组的指针要复杂一些。
例如,在一个三维数组中,引用元素 c[i][j][k]的地址计算最终将换成:*(*(* (c+i)+j)+k)。了解了多维数组的存储形式和访问多维数组元素的内部转换公式 后,再看当一个指针变量指向多维数组及其元素的情况。
5.数组和指针的分配
数组是开辟一块连续的内存空间,数组本身的标示符代表整个数组,可以用 si zeof 取得真实的大小;指针则是只分配一个指针大小的内存,并可把它的值指向 某个有效的内存空间 [全局的和静态的] char *p= "hello "; 一个指针,指向只读数据块(section)里的 "hello ",可被编译器放入字符串池(也就 是说, 你在写一个 char *q= "hello ",可能和 p 共享数据) char a[]= "hello "; 一个数组,分配在可写数据块(section),不会被放到字符串池中 [局部] char *p= "hello "; 一个指针,指向只读数据块(section)里的 "hello ",可被编译器放入字符串池(也就 是说, 你在写一个 char *q= "hello ",可能和 p 共享数据),另外,在函数中可以返回 它的地址,也就是说,指针是局部变量,他指向的数据却是全局的. char a[]= "hello "; 一个数组,分配在堆栈上,初始化由编译器进行(短的话直接用指令填充,长的就从 全局字符串表拷贝),不会被放到字符串池中(但是却可能从字符串池中拷贝过来), 也不应该返回 它的地址. [代码中的字面字符串] printf( "%s\n ", "hello "); 这两个字面常量( "%s\n "和 "hello "),都在只读数据块里 [用途] 全局指针 用于不需要修改内容,却可能会修改指针的情况(当然,不修改也没人反对) 全局数组,用于不需要修改地址,却需要修改内容的场合 既需要修改指针,有需要修改内容怎么办呢?定义一个数组,在定义一个指针指向 它就可以了 函数中如果不需要修改字符串的内容,应该尽量用 char*p= "xxx "这种写法.