数组和指针的区别与联系(详细)_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、 判断数据类型的方法
- 确定它的属性(是否为数组、指针、函数等),挑选优先级最高的属性;
- 如果指针,考虑指向的内容;
- 如果是数组,考虑长度跟类型;
- 如果是函数,考虑参数列表和返回值。
访问二维数组的四种方式
- 当成一维数组来访问二维数组
- 使用数组指针的方式访问二维数组
- 使用指针数组的方式访问二维数组
- 使用指针的指针&指针数组
#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 ;
}