数组、指针、数组指针、指针数组

数组和指针的区别与联系(详细)_cherrydreamsover的博客-CSDN博客_数组和指针的区别

1、实际上并不存在多维数组,所谓的多维数组本质上是用一维数组模拟的。

2、数组名是一个常量(意味着不允许对其进行赋值操作),其代表数组首元素的首地址。

3、数组与指针的关系是因为数组下标操作符[],比如,int a[3][2]相当于*(*(a+3)+2) 。

4、指针是一种变量,也具有类型,其占用内存空间大小和系统有关,一般32位系统下,sizeof(指针变量)=4。

5、指针可以进行加减算术运算,加减的基本单位是sizeof(指针所指向的数据类型)。

6、对数组的数组名进行取地址(&)操作,其类型为整个数组类型。

7、对数组的数组名进行sizeof运算符操作,其值为整个数组的大小(以字节为单位)。

8、数组作为函数形参时会退化为指针。

 int a[4]={1,2,3,4};
 int *ptr1=(int *)(&a+1);//指向a数组后面的内存单元,&a+1表示向后移16个存储单元
 int *ptr2=(int *)((int)a+1);//数组名表示数组的首地址,表示a的存储单元的地址增加一个字节

C语言规定,数组名代表数组的首地址,也就是第0号元素的地址。所以a==&a[0],理解“对数组名取地址”这一表达式的含义时一定要记住:数组名是“数组”这种变量的变量名,这样,&a就好理解了,它取的是“数组”这种变量的地址&a+1自然也就要跨过整个数组,所有元素长度总和,这么长的一个长度。例如:int a[4],那么&a+1就要跨过4个int的长度
 

如果定义一个这样的二维数组int a[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}};则其在内存中的表示可能下面这样的。

在内存中二维数组是按照行主序进行存储的,如果对全部元素都赋初值(即提供全部初始数据),则定义数组时对第一维的长度可以不指定,但第二维的长度不能省。 二维数组其实是一个包含数组的数组, 即数组的每一个元素还是一个数组。

//定义一个一维数组
int arr[4];
                               //此列表示类型
arr //数组首元素的地址            int *
arr + 1                           int *
arr[1]                            int
arr[1] + 1                        int
 
//定义一个二维数组
int brr[3][4];
 
brr                               int (* brr)[4] //数组指针
brr + 1                           int (* brr)[4] 
brr[1]                            int *
brr[1] + 1                        int *
brr[1][1]                         int
brr[1][1] + 1                     int

a 数据类型是 int (*p)[4],指向二维数组的第一行,

a+1 就是在a的基础上移动一个一维数组的长度,指向二维数组的第二行,

二维数组的名字代表二维数组第0行的首地址(注意它是代表一行元素的首地址,而不是第0行第0列元素的首地址)

a[0]的数据类型 int (*p),a[0] 相当于 &a[0][0];

a[0]+1就是在a[0]的基础上移动一个元素的长度,指向第二个格子


下面到底哪个是数组指针,哪个是指针数组呢:
A)
int *p1[10];
B)
int (*p2)[10];

  • p1 先与“[]”结合,构成一个数组的定义,数组名为p1,int *表示数组元素类型。所以p1是一个数组,包含10 个指向int 类型数据的指针,即指针数组首先它是一个数组,数组的元素都是指针,数组占多少个字节由数组本身的大小决定,每一个元素都是一个指针,在32 位系统下任何类型的指针永远是占4 个字节。它是“储存指针的数组”的简称。
  • p2 先与“*”号结合,构成一个指针的定义,指针变量名为p2,int表示数组元素类型。数组在这里并没有名字,是个匿名数组。所以p2 是一个指针,它指向一个包含10 个int 类型数据的数组,即数组指针首先它是一个指针,它指向一个数组。在32 位系统下任何类型的指针永远是占4 个字节,至于它指向的数组占多少字节,不知道,具体要看数组大小。它是“指向数组的指针”的简称。

我们可以借助下面的图加深理解:

数据类型的判定
1、对于复杂的数据类型,先看优先级。 “[]”的优先级比“*”要高,“()”的优先级比“[]”高

  • int (*p) [4]             数组指针(数组的指针)
  •  int  *p [4]              指针数组(保存整型指针的数组)
  •  int (*p) ()              函数指针 (指向函数的指针)
  •  int *p ()                指针函数(返回指针的函数)

2、 判断数据类型的方法

  • 确定它的属性(是否为数组、指针、函数等),挑选优先级最高的属性;
  • 如果指针,考虑指向的内容;
  • 如果是数组,考虑长度跟类型;
  • 如果是函数,考虑参数列表和返回值。

访问二维数组的四种方式

  1. 当成一维数组来访问二维数组
  2. 使用数组指针的方式访问二维数组
  3. 使用指针数组的方式访问二维数组
  4. 使用指针的指针&指针数组
#include<stdio.h>
#include<string.h>
void main()  
{
	/******遍历二维数组的4种方式********/

	int arr[4][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
	int (*p1)[4] ;		//定义数组指针
	int  *p2[4];		//定义指针数组
	int  *p = NULL;     
	int i,j,k;
//**方法1:当成一维数组来访问二维数组
	printf("当成一维数组来访问二维数组\n");
	p = arr[0];
	for(i = 0 ;i<16;i++)
	{
		printf("arr[%d] = %d,",i,*(p+i));
	
	}
	printf("\n--------------------------------------------------------\n");


//**方法2:使用数组指针的方式访问二维数组


	p1 = arr;			//指向含有四个元素一维数组的首地址
	printf("使用数组指针的方式访问二维数组arry\n");

	for(i = 0;i<4;i++)
	{
		for(j = 0;j<4;j++)
		{
			printf("arr[%d][%d]= %d \t",i,j,*(*(p1 + i)+j) );
					
		}
		printf("\n"); 

	}

//**方法3:使用指针数组的方式访问二维数组
	printf("使用指针数组的方式访问二维数组arry\n");
	for(k = 0 ;k<4;k++)      
	{
		p2[k] = arr[k];  //每个指针指向行元素,存储每行首地址
	}
	for(i = 0;i<4;i++)
	{
		for(j = 0;j<4;j++)
		{
			printf("arr[%d][%d]= %d \t",i,j,*(p2[i]+j)); //p2[i]已经存储并指向每行的首地址了

		}
		printf("\n");

	}
	printf("\n--------------------------------------------------------\n");

	//方法4:使用指针的指针&指针数组
	printf("使用指针的指针&指针数组访问二维数组\n");
	int **pointer;//指向指针的指针
	int *pp[4];//指针数组
	for(i = 0; i < 4; i++)
		pp[i] = arr[i];
		pointer = pp;
	for(i = 0; i < 4; i++)
	{
		for(j = 0; j < 4; j++)
			printf("arr[%d][%d]= %d \t", i,j,*(*(pointer + i) + j));
		printf("\n");
	}

//**(附)二维数组的每行起始地址的表示方法
	for(i = 0 ;i <4 ;i++)
	{
		printf("使用arr+i表示二维数组arr第%d行的起始地址为:   %-8d\n",i+1,arr+i); 
		printf("使用*(arr+i)表示二维数组arr第%d行的起始地址为:%-8d\n",i+1,*(arr+i));
		printf("使用arr[i]表示二维数组arr第%d行的起始地址为:  %-8d\n",i+1,arr[i]);
		printf("使用&arr[i]表示二维数组arr第%d行的起始地址为: %-8d\n",i+1,&arr[i]);
			printf("\n--------------------------------------------------------\n");
	}		
	printf("这是断点");
	return ;			
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值