指针数组和指向数组的指针

指针数组 typename *p[n] : 定义了一个数组,数组的元素是指针;

  例如: *p[3] = {"abc", "defg"};  sizeof(p) = 3*4 =12  (p 为数组名代表整个数组 sizeof(p)返回值是整个数组的大小,sizeof(*p) 第一个元素的大小 即数组的大小)  p[0] = "abc"...

              p = &p[0]  (p+1)=&p[1] ,  符合一般数组的特性,除了数组中的元素是指针以外,和一般的数组没什么区别。数组名p 是个指针常量,不能直接进行指针运算,不过可以传递给函数来进行。可以通过p[x] (0<=x<n) 来对指针数组进行赋值,如: p[2] = "hijklm"; 否则,对数组中的每个指针进行初始化, 必须先分配p[x] 所指向的内存空间! 必须对分配结果进行判断 if ( p[x]=(typename *)malloc(n * sizeof(typename)) == NULL) 失败。

 

指向数组的指针(以二维数组为例) typename (*p)[n]: 定义了一个指向含 n个数据元素数组的指针;

        二维数组int num[2][4] 可以看作是两个 num[4] 的数组构成, 数组名num是个指向第一个元素 ,num[0] 是指向 {num[0][0],  num[0][1],  num[0][2], num[0][3]} ,num[1]同理。num = num[0] = &num[0][0];   num+1 = num[1] = &num[1][0] ; 二维数组名可以看做是一个指向指针数组的指针,num-> { num[0], num[1]}  ->{ num[0][0]....};

         定义:int (*p)[4] ;   p = num;  --->  p = num[0]   p+1 = num[1];   sizeof(p) = 4; sizeof(*p) = 4*4 ;   sizeof(*(p+1)) = 16; sizeof(num) = 2*4*4=32,

         p所指向的4*sizeof(int) bytes的空间的整体, 因为数组是顺序存储结构,所以 p+1 就指向第二列的第一个元素(跨过了4个int的地址空间);

         因为p是指向一个数组一行元素的整体的指针,如果要对数组每个元素进行读写,需要用强制转换,把指向4int的指针转换为一个指向1int的指针,(实际上就是把p所指向的第一个地址传递给一个int *q 指针,因为数组是顺序存储结构,所以只需要知道首地址和长度就可以了)然后用该指针来遍历数组。

       可以把指向数组的指针或数组名传递给函数来对二维数组进行操作, 下面是分别用两种方法来实现print_array 函数:

1.               void print_array1(int (*p_num)[4])                            2           void print_array2(int (*p_num)[4], int n)

                  {  int *q, i;                                                                   {  int *q, i;  

                    q=(int *)p_num;                                                                     q = (int *)p_num;  // 指针类型强制转换

                    for (i =0;i<4;i++){printf("%d/n", *q++)} }                        for(i = 0; i< (4*n);i++){....} }

  两种方法实质上一样,方法1需要在主函数中需要 进行 for ( i =0; i < 2; i++) { print_array1(p); p++} (p 是指向二维数组的指针) 也就是每一行进行一次调用,方法二是从数组头开始,按照存储顺序依次print。因为数组存储的方式也是先行后列,所以两种打印的方式输出一样。

  注意一点: 因为数组名是常量指针,所以在方法1中是不可以直接利用数组名传递给函数的,因为num++是不合法的!

 

 

 

 

有 些人常常会以为,二维数组就是二级指针,这种错误的根源,来自于可以把一个二级指针int **p以p[i][j]这种形式使用。首先把数组称为指针就是 错误的,第一章笔者已经说明了数组名是地址,不能理解为指针。第二,并非能以p[i][j]这种形式使用,那么p就是一个二维数组了,C标准对数组引用的 规定,并没有指定数组引用时[]运算符的左边必须是数组名,而可以是一个表达式。第三,这是一种“巧合”,归根到底是由于C语言的数组实现是数组的嵌套同 时C标准把[]运算符转换为类似*(*(a+i)+j)这样的等价表达式造成的,那两个取值运算符“恰好”可以用于一个二级指针。第四,p与p[i]并不 具有数组类型,sizeof(p)和sizeof(p[i])的结果只是一个指针的大小4字节。而对于一个真正的数组,p与p[i]都是具有数组类型的地 址。

 

 

(i)int *p[3]; 
(ii)int (*q)[3]; 
(iii)int *(t[3]); 
以上三者的区别?(vc++环境下验证): 
(1)p是一个指针数组,此处包含三个整型指针,所以sizeof(p)=12;sizeof(*p)=4;//首地址 
    
(2)q是一个数组指针,指向含有三个元素的整型数组,所以sizeof(q)=4;sizeof(*q)=12; 

(3) 和(1)一样;sizeof(t)=12;sizeof(*t)=4; 

(4)   int *p[3]等价于:typedef        int*    myint; 
                                  myint  p[3]; 
                   int (*p)[3]等价于:typedef     int    intarray[3]; 
                                  intarray  *p; 
(5)   (i)可以这样初试化:int  a[]={1,2,3,4}; 
                 p[0]=a;//*p=a;  
      (ii)可以这样初始化:int  a[3]={1,2,3};//数组元素必须是三个 
                  q =&a; 
(6)p是数组,不可做++操作,q是指针,可以做++操作,q++是当前q指向的地址值加12;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值