指针与数组的区别和联系

转载:

一.指针与数组的联系:

指针与数组是C语言中很重要的两个概念,它们之间有着密切的关系,利用这种关系,可以增强处理数组的灵活性,加快运行速度,本文着重讨论指针与数组之间的联系及在编程中的应用。

1.指针与数组的关系

  当一个指针变量被初始化成数组名时,就说该指针变量指向了数组。如:

  char str[20], *ptr;

  ptr=str;

  ptr被置为数组str的第一个元素的地址,因为数组名就是该数组的首地址,也是数组第一个元素的地址。此时可以认为指针ptr就是数组str(反之不成立),这样原来对数组的处理都可以用指针来实现。如对数组元素的访问,既可以用下标变量访问,也可以用指针访问。

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则是正确的。由此可见,此时指针与数组融为一体。

3.指针与一维数组

  理解指针与一维数组的关系,首先要了解在编译系统中,一维数组的存储组织形式和对数组元素的访问方法。

  一维数组是一个线形表,它被存放在一片连续的内存单元中。C语言对数组的访问是通过数组名(数组的起始地址)加上相对于起始地址的相对量(由下标变量给出),得到要访问的数组元素的单元地址,然后再对计算出的单元地址的内容进行访问。通常把数据类型所占单元的字节个数称为扩大因子。

  实际上编译系统将数组元素的形式a[i]转换成*(a+i),然后才进行运算。对于一般数组元素的形式:<数组名>[<下标表达式>],编译程序将其转换成:*(<数组名>+<下标表达式>),其中下标表达式为:下标表达式*扩大因子。整个式子计算结果是一个内存地址,最后的结果为:*<地址>=<地址所对应单元的地址的内容>。由此可见,C语言对数组的处理,实际上是转换成指针地址的运算。

  数组与指针暗中结合在一起。因此,任何能由下标完成的操作,都可以用指针来实现,一个不带下标的数组名就是一个指向该数组的指针。

4.指针与多维数组

  用指针变量可以指向一维数组,也可以指向多维数组。但在概念上和使用上,多维数组的指针比一维数组的指针要复杂一些。

  例如,在一个三维数组中,引用元素c[i][j][k]的地址计算最终将换成:*(*(*(c+i)+j)+k)。了解了多维数组的存储形式和访问多维数组元素的内部转换公式后,再看当一个指针变量指向多维数组及其元素的情况。

  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的增值以一维数组的长度为单位。

5.指针与字符数组

  C语言中许多字符串操作都是由指向字符数组的指针及指针的运算来实现的。因为对于字符串来说,一般都是严格的顺序存取方式,使用指针可以打破这种存取方式,更为灵活地处理字符串。

另外由于字符串以′\0′作为结束符,而′\0′的ASCII码是0,它正好是C语言的逻辑假值,所以可以直接用它作为判断字符串结束的条件,而不需要用字符串的长度来判断。C语言中类似的字符串处理函数都是用指针来完成,使程序运行速度更快、效率更高,而且更易于理解。

二.指针与数组的区别:

1.把数组作为参数传递的时候,会退化为指针

数组名作为函数形参时,在函数体内,其失去了本身的内涵,仅仅只是一个指针;很遗憾,在失去其内涵的同时,它还失去了其常量特性,可以作自增、自减等操作,可以被修改。

所以,数组名作为函数形参时,其沦落为一个普通指针!它的贵族身份被剥夺,成了一个地地道道的只拥有4个字节的平民。

典型的情况是

void func(int A[])

{

//sizeof(A)得到的是4bytes

}

int main()

{

int a[10]; //sizeof(a) 得到的结果是40bytes

funct(a);

}

2、数组名可作为指针常量

  根据结论2,数组名可以转换为指向其指代实体的指针,所以程序1中的第5行数组名直接赋值给指针,程序2第7行直接将数组名作为指针形参都可成立。

 下面的程序成立吗?

int intArray[10];

intArray++;

  读者可以编译之,发现编译出错。原因在于,虽然数组名可以转换为指向其指代实体的指针,但是它只能被看作一个指针常量,不能被修改。

  而指针,不管是指向结构体、数组还是基本数据类型的指针,都不包含原始数据结构的内涵,在WIN32平台下,sizeof操作的结果都是4。

顺便纠正一下许多程序员的另一个误解。许多程序员以为sizeof是一个函数,而实际上,它是一个操作符,不过其使用方式看起来的确太像一个函数了。语句sizeof(int)就可以说明sizeof的确不是一个函数,因为函数接纳形参(一个变量),世界上没有一个C/C++函数接纳一个数据类型(如int)为"形参"。

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;

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记录

而不是5,在i需要值的时候去0x8291这个地址去取出值给i(这里的i是全局的或者静态变量,这时候才能在编译阶段确定地址)。

所以在Test1.cpp中,把array的地址给了array,假设这个地址是0x34fe,但是由于数组的特性array == &array,所以这里是正常的。而在Test2.cpp中,array是个指针,所以会去0x34fe中取出值给array,所以array = 0x0007(数组的第一个值,这里要做地址,因为是给指针用)

这就是看到的Test2()的输出结果。显然array[1]会死机,因为0x0007地址是没有被分配的,并且是给操作系统用的而不是给用户用的。

5.数组和指针的分配

数组是开辟一块连续的内存空间,数组本身的标示符代表整个数组,可以用sizeof取得真实的大小;指针则是只分配一个指针大小的内存,并可把它的值指向某个有效的内存空间

[全局的和静态的

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 "这种写法.

初始化的局部字符数组影响效率,一般应该尽量避开(应该使用的情况下则不要犹豫)

转载:原文地址:http://blog.chinaunix.net/uid-21411227-id-1826897.html

时间: 2024-11-18 06:01:00

指针与数组的区别和联系的相关文章

指针和数组的区别

针的操作: 允许:1)同类型指针的赋值 2)与整形的加减运算 3)指向同一数组内指针的减运算和比较 4)赋 ‘0’ 或与 ‘0’ 比较 不允许:1)两指针的相加,相乘除,位移或mask 2)与float,double类型相加 3)不通过类型转换,直接赋予除void*之外的其它类型指针 指针与数组的相同点: 1,a[i]可以用*(a+i)表示 2, 当传递给函数作为实参时,则都是一个地址 指针和数组的区别: 1,数组是一块连续区域,要么是在静态存储区被创建(如全局数组),要么是在栈上被创建.数组名

C语言中使用指针与数组的区别

在c语言中,指针和数组名都表示地址,但两者却有很大的不同之处,对于初学者来说一定要弄清楚两者的区别. 首先,我举个简单的例子: char *p1="hello!";  //定义字符型指针p1,并将指针p1指向字符串"hello!"的首地址. char s[10]="hello!";  //定义数组s,并将其初始化赋值. 然而,如果char s[10]; s="hello!";这样就会报错,为什么呢?原因很简单,因为数组名是常量

指针和数组的区别及混淆

1.char* a和char a[] 指针是不分配内存的,它指向的是系统的只读的内存,而数组是分配内存的,就是将系统的只读的内存里面的值复制到它的内存里面,因此可读写. char p[]="abc123ABC" char *p="abc123ABC"; char* p是定义的一个指针..他指向的字符窜"abc123ABC" 是存在不可修改的区域(代码区)的.. 而char p[]是一个数组..他的内容存在栈区可以修改 char p[]="

【指针篇】C语言:指针与数组的区别,数组指针与指针数组的剖析。

指针就是指针,指针变量在 32位系统下,永远占 4  个byte ,其值为某一个内存的地址.指针可以指向任何地方,但是不是任何地方你都能通过这个指针变量访问到. 数组就是数组,其大小与元素的类型和个数有关.定义数组时必须指定其元素的类型和个数.数组可以存任何类型的数据,但不能存函数. 说起指针,就让我们想到数组.而数组和指针也是有区别的.指针,指的是描述一个变量的地址:我们可通过指针的偏移来指向下一个地址.数组,是描述相同元素的一个集合:数组名是常量地址,不可自加不可修改. 我们可以通过数组的下

转:浅谈C/C++中的指针和数组(一)

转自:http://www.cnblogs.com/dolphin0520/archive/2011/11/09/2242138.html 浅谈C/C++中的指针和数组(一) 指针是C/C++的精华,而指针和数组又是一对欢喜冤家,很多时候我们并不能很好的区分指针和数组,对于刚毕业的计算机系的本科生很少有人能够熟练掌握指针以及数组的用法和区别.造成这种原因可能跟现在大学教学以及现在市面上流行的很多C或者C++教程有关,这些教程虽然通俗易懂,但是在很多关键性的地方却避而不谈或者根本阐述不清楚,甚至很

指针 指针与数组 指针与字符串 指针与函数 结构体与指针 宏

指针 指针与数组 指针与字符串 指针与函数?? 指针与数组 1.数组名:数组元素首地址 eg: int array[3]={1,3,6}; 这里array 恒等于&array[0] 2.int *p = a; int *p = 0; int a[]={0}; 3.int *p = a; 均指向数组的首地址 *p是? *(p+1)是?(*p)+1是? *(p+1)决定向下移动几个字节是类型 4.指针可以当数组名使用 p[1] = 3; 恒等于a[1] ;恒等于*(p+1);恒等于*(a+1) 5.

什么是指针?什么是数组?指针和数组的关系?

形象地讲,我们可以把计算机的内存看作一条长街上的一排房屋,每个房间都可以容纳数据并通过一个房号来表识.而表示每个房间房号的值我们可以称为地址.或许这样的比喻有局限性,毕竟真实地计算机内存是以数以万计的bit位组成. ⑴初始化: ①最简单的以 int *p 为例,初始化时内存里开辟了四个字节的空间. ▇▇▇▇ ②另一个声明 ,现在,我们有两个变量,下图中显示了后面那个未知内容的内存. char ch = 'a': char cp = &a; ▇→▇▓←(?) (cp)      (ch) ⑵&quo

指针与数组的关联3 --声明

当我们在调用函数时,传递数组,就是把数组首元素的地址传递给函数,本质也就是给函数传递了一个指针变量.这时候我们会想那么数组是不是跟指针是一样的.为了验证,我们可以给一个项目里创建一个新的源文件,里面创建一个指针变量和是个数组,然后在另一个文件中用数组的方法声明指针,在用指针的方法声明这个数组进行调试,看下结果会如何. 我们创建一个test.c文件用来编写主函数,test1.c创建变量编写内容如下: test.c: #include <stdio.h> extern char*arr; exte

C语言学习笔记(六) 指针和数组

使用C语言就必然会使用到指针和数组.看下面的代码: int main(int argc, char** argv){     int a[4] = {1,3,5,7};     int *p = a;     int i;     for (i=0; i<4;i++){         printf("i=%d, p[i]=%d, *(p+i)=%d, a[i]=%d, *(a+i)=%d\n",                 i, p[i], *(p+i), a[i], *(