c语言学习-11.22~23日数组指针博客

对于上一次博客的补充:

zippo[4][2]

 

zippo

等价于&z[0]

二维数组首元素的地址(每个元素都是内含两个int类型元素的一维数组)

 

zippo+2

等价于&z[2]

二维数组的第3个元素(即一维数组)的地址

 

*(zippo+2)

等价于&z[2][0]

二维数组的第3个元素(即一维数组)的首元素(1个int类型的值)地址

 

*(zippo+2)+1

等价于&z[2][1]

二维数组的第3个元素(即一维数组)的第2个元素(也是一个int类型的值)地址

 

*(*(zippo+2)+1)

等价于zippo[2][1]

二维数组的第3个一维数组元素的第2个int类型元素的值

 

开始今天的博客:

1.指向多维数组的指针

声明一个指针变量pz指向一个二维数组

zippo[n][m]

int (*pz)[m];

但是

int *pax[n];

pax是一个内含n个指针元素的数组,每个元素都指向int的指针

 

2.指针的兼容性

指针之间的赋值比数值类型之间的赋值更严格。例如,不用类型转换就可以把int 类型的值赋给double类型的变量,但是两个int类型的指针不能这样做。

int n=5;

double x;

int * p1=&n;

double * pd=&x;

x=n; //强制转换

pd=p1; //编译时错误

 

更复杂的类型也是如此。

假设有如下声明:(指针替换成地址比较好理解)

int * pt;

int (*pa)[3];

int ar1[2][3];

int ar2[3][2];

int **p2; //指向一个指针的指针

 

有如下的语句:

pt=&ar1[0][0]; //都是指向int的指针

pt=ar1[0]; //都是指向int的指针

pt=ar1; //无效

 

pa=ar1; //都是指向内含3个int类型元素数组的指针

pa=ar2; //无效

p2=&pt; //都是指向int *的指针

*p2=ar2[0]; //都是指向int的指针

p2=ar2; //无效

 

对于多重解引用

例如,考虑下面的代码:

int x=20;

const int y=23;

int * p1=&x;

const * p2=&y;

const ** pp2;

p1=p2; //不安全--把const指针赋给非const指针

p2=p1; //有效--把非const指针赋给const指针

pp2=&p1; //不安全--嵌套指针类型赋值

 

 

 

把const指针赋给非const指针不安全,因为这样可以使用新的指针改变const指针指向的数据。(编译器可能给出警告)关于这一部分详情请看11.16日的博客

 

3.函数和多维数组

3种等价语法(声明形参):

#define ROWS 3

#define COLS 4

void a(int ar [][COLS],int rows);

//第一个[]表明ar是一个指针

void b(int [][COLS],int); //省略形参名,没问题

int c(int (*ar)[COLS],int rows);//另一种语法

也可以在第一对方括号协商大小,但是编译器会忽略该值。

 

一般而言,声明一个指向N维数组的指针时,只能省略最左边方括号的值:

int sum4d(int ar[][12][20][30],int rows)

等价于

int sum4d(int (*ar)[12][20][30],int rows)

这里ar指向一个12×20×30的int数组

 

4.变长数组

变长数组有一些限制:

变长数组必须是自动存储类别,这意味着无论在函数中声明还是作为函数形参声明,都不能使用static或extern存储类别说明符。而且不能在声明在初始化他们。

这里的“变”指的是:在创建数组时,可以使用变量指定数组的维度。

 

首先,要声明一个带二维变长数组参数的函数,如下所示:

int sum2d(int rows,int cols,int ar[rows][cols]); //ar是一个变长数组(VLA)

在形参列表中申明ar之前必须先声明两个形参,因为ar需要这两个形参作为维度。

也可以这样写:

int sum2d(int,int,int ar[*][*]); //ar是一个变长数组(VLA),省略了维度形参名。

 

需要注意的是,在函数定义的形参列表中声明的变长数组并未实际创建数组。和传统的语法类似,变长数组名实际上是一个指针。这说明带变长数组形参的函数实际上是在原始数组在处理数组,因此可以修改传入的数组。

 

变长数组还允许动态内存分配(以后再说)

 

5.复合字面量(简单概括)

int diva[2]={10,20};//正常

(int [2]){10,20};//复合字面量(匿名数组)

 

因为复合字面量是匿名的,所以不能先创建再使用它,必须在创建的同时使用它。使用指针记录地址就是一种用法。

 

int * pt1;

pt1=(int [2]){10,20};

 

还可以把复合字面量作为实际参数传递给带有匹配形式参数的函数:

int sum(const int ar[],int n);

...

int total3;

total3=sum((int []){4,4,4,5,5,5},6)

这种用法的好处是,把信息传入函数前不必先创建数组,这是复合字面量的典型用法。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值