指针与数组

来源:互联网 发布:程序员的思维 编辑:程序博客网 时间:2024/06/15 15:48

1.“指针”是个地址的概念。它本身不是变量,并不分配存储单元,仅表示对象在内存中的地址。

2.数组名同时也是该数组首元素的地址,数组名为地址常量,对该地址进行增减运算来移动指针寻找其他的数组元素,而不是对指针变量进行加减操作。

例:

#include<stdio.h>

int main(void)

{

    int a[3]={1,2,3};

    int *p=a;                                                                                           //  p为指向a的首元素地址的指针变量

    printf(“a=%p\n",a);                                                                        //  a表示数组a[3]的首元素地址,为常量

    printf(&a[0]=%p\n",&a[0]);                                                       //  &a[0]的意义与a相同

    printf(”&a+1=%p\n",a+1);                                                       //  对a进行增量运算,移动指针使其指向a[1]

    printf("&a[0]+1=%p\n",&a[0]+1);                                              //  &a[0]+1与a+1意义相同

    printf("&a=%p\n",&a);                                                                 //  &a的值与a相同,但指向的是整个数组单元

    printf(”&a+1=%p\n",&a+1);                                                        //  对&a移动1,则&a+1指向的是数组末单元下一个单元的地址

    return 0;

}

运行结果:

a=0x7ffe7de5c4a0

&a[0]=0x7ffe7de5c4a0

a+1=0x7ffe7de5c4a4

&a[0]+1=0x7ffe7de5c4a4

&a=0x7ffe7de5c4a0

&a+1=0x7ffe7de5c4ac

说明:尽管a=&a=&a[0],但它们三个都不是变量,更谈不上是同类型的变量,因此可以取值相同但 意义不同,从而进行指针移动时变动大小也可以不同

a是数组首元素的首地址,&a是整个数组的首地址。

—————————————————————————

3. 指向整型指针的指针

先看如下示例:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 int main()
 5 {
 6     int a[5= {12345};
 7     int *= a;
 8     int **point = &p;
 9 
10     cout << "a = " << a << endl
11         << "p = " << p << endl
12         << "&p = " << &<< endl
13         << "point = " << point << endl
14         << "&point = " << &point << endl;
15 
16     for (int i = 0; i < 5; i++)
17     {
18         cout << "&a[" << i << "] = " << &a[i] << endl;
19     }
20     return 0;
21 }
复制代码

运行结果图如下:

我们先看下内存分配图:

从上图可以看出point指针中存放的是p指针的地址,而p指针中存放的是a[0]的地址。所以*point和p是一样的,前者是取point指针中存放的地址(0025F754)中的值,即取地址0025F754中存放的值(0025F760),而后者就是0025F760,所以两者是等价的。**point和a[0]是等价的,前者可以写成*p,*p是取p中存放的地址(0025F760)中的值,即地址0025F760中存放的值1。由上可以得出*point等于p, **point 等于 a[0]。通过上图可以清晰的对付诸如*point++等问题。

————————————————————————————

4. 二维数组的指向整型指针的指针

先看如下示例:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 int main()
 5 {
 6     char *a[] = {"Wel""To""China"};
 7     char **= a;
 8     for(int i = 0; i < 3; i++)
 9     {
10         for (int j = 0; j < strlen(a[i]) + 1; j++)
11         {
12             cout << a[i][j] << "\t" << (void *)&a[i][j] << endl;
13         }
14         cout << endl;
15     }
16     
17     for (int i = 0; i < 3; i++)
18     {
19         cout << "a[" << i << "] = " << (void *) a[i] << endl
20              << "&a[" << i << "] = " << &a[i] << endl;
21     } 
22 
23 
24     cout << "p  = " << p << endl
25          << "&p = " << &<< endl;
26     return 0;
27 }
复制代码

 

运行结果图如下:

我们先看下内存分配图:

由上图可以看出a[0]中存放着'W'的地址,a[1]中存放着'T'的地址,a[2]中存放着'C'的地址,只是这些地址都是指向字符型的,所以直接cout的会输出字符串,而指针p中存放着a[0]的地址,所以*p等于a[0],都是获得'W'的地址,即00A778CCC,而**p和a[0][0]等价都获得了地址00A778CCC中存放的值W。由上图我们可以看到字符地址相隔1个字节,而指针地址相隔4个字节,这样就便于++运算,获得下一个地址了,列如++p后,p就指向a[1],p中存放的是a[1]的地址。


————————————————————————

5.二维数组和指针

以前一直有种误解:  
二维数组的是数组的数组,所以数组的首地址是指向第一个元素指针,而这个元素又是一个数组,所以把数组首地址理解为指向指针的指针。  
如int a[3][2];,以前一直认为a是一个指向int指针的指针,即是一个int**。最近发现这是错的。  
如果int **p=a; 编译就会报错。如果强制转换int **p=(int **)a,则使用p[i][j]访问数组元素时出错。  
首先,因为a的定义为 int a[3][2];则a的类型是int* [3][2]数组类型,或者int* [][2],即指向大小为2的数组的指针,类型与int **不同,所以int **p=a;出错

说明:二维数组的数组名为一个二级指针常量,实际上是一个行指针

例如:
{
int a[4][5];
int (*p)[5]=a;
}
这里a是个二维数组的数组名,相当于一个二级指针常量;
p是一个指针变量,它指向包含5个int元素的一维数组,此时p的增量以它所指向的一维数组长度为单位;
*(p+i)是二维数组a[i][0]的地址;

进一步讨论:
设有整型二维数组a[3][4]如下:
0   1   2   3
4   5   6   7
8   9  10  11 
它的定义为:
    int a[3][4]={{0,1,2,3},{4,5,6,7},{8,9,10,11}}
设数组a的首地址为1000,各下标变量的首地址及其值如图所示。


前面介绍过,C语言允许把一个二维数组分解为多个一维数组来处理。因此数组a可分解为三个一维数组,即a[0]、a[1]、a[2]。每一个一维数组又含有四个元素。



例如a[0]数组,含有a[0][0],a[0][1],a[0][2],a[0][3]四个元素。

数组及数组元素的地址表示如下:从二维数组的角度来看,a是二维数组名,a代表整个二维数组的首地址,也是二维数组0行的首地址,等于1000。a+1代表第一行的首地址,等于1008。如图:



a[0]是第一个一维数组的数组名和首地址,因此也为1000。*(a+0)或*a是与a[0]等效的, 它表示一维数组a[0]0 号元素的首地址,也为1000。&a[0][0]是二维数组a的0行0列元素首地址,同样是1000。因此,a,a[0],*(a+0),*a,&a[0][0]是相等的。

同理,a+1是二维数组1行的首地址,等于1008。a[1]是第二个一维数组的数组名和首地址,因此也为1008。&a[1][0]是二维数组a的1行0列元素地址,也是1008。因此a+1,a[1],*(a+1),&a[1][0]是等同的。

由此可得出:a+i,a[i],*(a+i),&a[i][0]是等同的。

此外,&a[i]和a[i]也是等同的。因为在二维数组中不能把&a[i]理解为元素a[i]的地址,不存在元素a[i]。C语言规定,它是一种地址计算方法,表示数组a第i行首地址。由此,我们得出:a[i],&a[i],*(a+i)和a+i也都是等同的。

另外,a[0]也可以看成是a[0]+0,是一维数组a[0]的0号元素的首地址,而a[0]+1则是a[0]的1号元素首地址,由此可得出a[i]+j则是一维数组a[i]的j号元素首地址,它等于&a[i][j]。


由a[i]=*(a+i)得a[i]+j=*(a+i)+j。由于*(a+i)+j是二维数组a的i行j列元素的首地址,所以,该元素的值等于*(*(a+i)+j)。

【例10-22】
  1. main(){
  2. int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
  3. printf("%d,",a);
  4. printf("%d,",*a);
  5. printf("%d,",a[0]);
  6. printf("%d,",&a[0]);
  7. printf("%d\n",&a[0][0]);
  8. printf("%d,",a+1);
  9. printf("%d,",*(a+1));
  10. printf("%d,",a[1]);
  11. printf("%d,",&a[1]);
  12. printf("%d\n",&a[1][0]);
  13. printf("%d,",a+2);
  14. printf("%d,",*(a+2));
  15. printf("%d,",a[2]);
  16. printf("%d,",&a[2]);
  17. printf("%d\n",&a[2][0]);
  18. printf("%d,",a[1]+1);
  19. printf("%d\n",*(a+1)+1);
  20. printf("%d,%d\n",*(a[1]+1),*(*(a+1)+1));
  21. }


0 0