浅谈C中的指针和数组(五)

 

前面写了一些C指针和数组的一些知识,但是还有一些很重要的知识没有交代,这里做一个补充。

首先看一下,普通变量(指针也是变量)和数组名查看地址的方式是不同的。

查看数组变量的地址,不需要使用 & 。C,C++语言中,对数组变量的操作,就相当于直接对该数组变量的地址的操作。

 

#include<stdio.h>
#include<stdlib.h>

int main(void)
{

    int arr[3]={1,2,3};
    int a = 4;
    int *p = &a;
    printf("%p\n", &a);
    printf("%p\n", &p);
    printf("%p\n", arr);
    printf("%p\n", p);

    system("pause");
    return 0;
}

 

执行的结果:

可以看出,对于普通的变量(包括指针变量),想查看其地址,都要加上&符号,表示打印其编译器符号表中的对应于变量符号的地址。否则打印的就是符号表中对应的地址的内存单元中存放的数据。

但是数组的名字不用加&符号,直接打印的就是符号表中的地址。

二维数组

实际上C语言没有多维数组,有的只是数组的数组。

指针与多维数组

(主要指二维数组)

int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};

在说之前,说明一件事,数组的地址直接是在编译的时候写在编译器的符号表中的,不需要想指针变量那样间接取址。符号表的表项中有一项是类型,地址的加减的调整量就是根据这个类型确定调整量大小的。

数组名自它定义时起就确定下来,不能通过赋值的方式使该数组名指向另外一个数组。

换个角度看世界:

如首行一样,将首行视为一个元素,一个特殊的元素,这个“特殊的”元素是一个一维数组。那么这个二维数组是由是由三个“特殊的”元素组成的一个“特殊的”一维数组。

a是这个“特殊的”一维数组的名称,也就是首地址,也就是第一个元素的地址,也就是第一行的首地址,是指首行一整行,并不是指某个具体元素。那么我们称之为“行指针”。同理:a+0,a+1,a+2,都是行指针。

结论:

表示形式

含义

指针类型

a或者a+0

指向第0

行指针

a+1

指向第1

行指针

a+2

指向第2

行指针

 

接下来,我们来放大观看首行,首行的元素分别是:a[0][0],a[0][1],a[0][2],a[0][3]。将其看作一个独立的一维数组,那么 a[0]就是这个数组的名称,也就是这个数组的首地址,也就是第一个元素的地址,也就是a[0]+0。a[0]和a[0]+0都是指具体的元素,那么我们称之为“列指针”。

结论:(第0行视为一维数组)

表示形式

含义

指针类型

a[0]

是一维数组的名称,也是它的首地址,而且是第1个元素的地址(a[0]+0

列指针

a[0]+1

0行,第2个元素的地址

列指针

a[0]+2

0行,第3个元素的地址

列指针

 

两个重要概念:行指针和列指针。

行指针:指的是一整行,不指向具体元素。

列指针:指的是一行中某个具体元素。

可以将列指针理解为行指针的具体元素,行指针理解为列指针的地址。

那么两个概念之间的具体转换是:

*行指针----列指针(修改符号表中的类型,修改指向的内存空间的大小)

&列指针----行指针

从上面看来,一个指针变量(暂且把数组名当做指针,其实不是)包括两个方面:指向的地址和指针的类型。

根据以上转换公式:

行指针

转换成:列指针

列指针等价表示

内容

内容等价表示

含义

aa+0

*a

a[0]

*a[0]

*(*a)

a[0][0]

a+1

*(a+1)

a[1]

*a[1]

*(*(a+1))

a[1][0]

a+2

*(a+2)

a[2]

*a[2]

*(*(a+2))

a[2][0]

对于元素a[1][2],其地址用列指针表示为a[1]+2,等价表示为*(a+1)+2,那么内容是*(*(a+1)+2)

 

 

列指针

行指针

等价表示

含义

a[0]

&a[0]

&a&(a+0)

0

a[1]

&a[1]

&(a+1)

1

a[2]

&a[2]

&(a+2)

2

 

示例1:用列指针输出二维数组。

#include <stdio.h>

void main()
{
   int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};

   int *p= a[0];   // 列指针的定义法

   for(; p < a[0] + 12; p++)//这里要知道数组是按行还是按列存储的
   {
     printf("%d ",*p);
   }

    return;
}

  

示例2:用行指针输出整个二维数组。

#include <stdio.h>

void main()
{
   int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23};

   int (*p)[4]= &a[0]; // 行指针定义法或者int (*p)[4]= a;

   int i, j;
   for(i = 0; i < 3; i++)
   {
		for(j = 0; j < 4; j++)
	   {
			printf("%d ",*(*(p + i) + j));
	   }	   
   }
     
    return;
}

  

看一下sizeof和&符号对二维数组的操作:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    int a[2][3] = {{1,2,3},{4,5,6}};
    //这里的a代表行指针,指向数组第一行
    //a[0]代表列指针,指向第0行的首个元素的地址
    //sizeof和&两个操作会使数组变大
    printf("%d\n", sizeof(a));
    printf("%d\n", sizeof(a[0]));
    system("pause");

    return 0;
}

  

执行结果:

产生这种结果的原因在前面指针和数组名的相同点(它们都能以数组或者下标的形式访问)中做了说明,这属于那两个特例,就是说在sizeof和&操作符的时候,大小是不一样的,操作形式也会发生变化。

 

 


 

 

指针和数组的内容到这里全部笔记做完了,最后补充一点点C语言的定义和声明的部分:

对二维数组的访问,看到其实没有多次的访问内存取地址:

 

posted @ 2014-12-05 18:01  stemon  阅读(271)  评论(0编辑  收藏  举报