C语言[]作用小结
数组中[]是如何起作用的,要想回答这个问题,首先要明白[]里数字的作用
首先为什么数组要从0而不是开始编号1?
是因为数组的索引值是一个偏移量,以数组中第一个元素开始偏移,有点参考系和参照物的味道
例如一维数组a[0]表示目标元素到数组第一个元素有0个偏移量
#include"stdio.h";
int main() {
一维数组a[i]:
int a[10] = { 30,1,22,64,7,85,3,4,5,9 };
int* p1 = a;
//指针变量存储的是地址,C语言用数组名简化表示数组的首地址
p1 = &a[3];//*p1直接指向地址对应的值a[3]
printf("*(p1 + 2)加的不是数值而是偏移量\n");
printf("% d\n", *p1 + 2);
printf("*p1与2都是数字,是数值相加,加的是值64+2=66\n");
总结:
- a[i]=*(a + i)
- 减少一个[]对应增加一个*,反之也成立
- []前面好像必须紧跟着一个地址或者一个字母(简化表示的地址)
二维数组b[i][j]:
先说结论,效仿一维数组,翻过书的也都知道,对于二维数组b[i][j]*(b[i] + j)*(*(b + i) + j)==*((b[i])+j)
为了验证一维数组的总结,查询优先级()和[]都是从左往右结合顺序,利用()改变运算顺序
int b[4][3] = { {110,120,130} ,{210,220,230},{310,320,330},{410,420,430} };
//printf("%d\n", b([2][1]));
//printf("%d\n", b[2]([1]));
//printf("%d\n", (b[2])([1]));
printf("%d\n", (b[2])[1]);//320
//经过测试只有↑成立,结合一维数组,一个光字母代表的是一位数组的首地址
//有理由猜测这里二维数组名b代表的也是一个首地址
printf("%d\n", **b);//110
//再次请出()改变运算顺序
printf("%d\n", *(*(b + 0) + 0));//110
//是否眼熟,这不就是b[0][0]吗?
printf("%d\n", *(*(b + 1) + 1));//220
printf("%d\n", *((*b) + 2));//*(*(b + 0) + 2)130
printf("%d\n", *(*(b + 2)));//*(*(b + 2) + 0)310
//从结果上来看,上面两个+2,第一个+ 2加的是列,第二个+ 2加的是行
//列很好理解,举个例子
printf("%d\n", *(&b[2][0] + 1));//21 320,&表示的意思是取b[2][0]的地址,之后在进行偏移1
//减少一个[]对应增加一个*,你可能就会认为b[2]==&b[2][0],
printf("%d\n", *(b[2] + 1));//320果然成立
//那么这有如何, 先别急着认为报错
printf("%d\n", *((&(b[2]))[1] + 1));//420
//&(b[2])再取一遍地址是什么东西 ? 还能取地址的地址 ? 要解释这个问题还得分清二维数组的行地址
和列地址的区别
//因为别忘了[]里还有数字, 并且数字作用的对象也至关重要
//对于地址, 经过if判定b[2] == &b[2], & b[2] == &b[2][0], b[2] == &b[2][0]都成立
//b[2] == &b[2] == &b[2][0] ?
//一位数组说过减少一个[]对应增加一个*, 为什么b[2] == &b[2][0]能后面少一个[]或前面增一个&也能成立
//这也是折磨我的问题
//还是应用上述结论b[2] == &b[2][0]
//& b[2] == &(&b[2][0]), 再来减少一个[]对应增加一个*, & (&(*(*(b + 2) + 0))), *& 相互抵消,剩下(b + 2) = &b[2],
//虽然&b[2]等价于&b[2][0]但是单独的b[2]==&b[2][0]也就是*(b+2),&b[2]可以看成(b+2)
//所以更应该将b[0] = *(b + 0), & b[2] = (b + 2)这样理解
//这就是行的表示方法,举个例子b[2][1]中[1]对[1]前面的b[2]也就是b[2]=*(b+2)做运算
printf("%d\n", (*(b + 2))[1]);//320,[1]对*(b + 2)作用*(b + 2)是列地址(&b[2][0])[1]运算规则为*((b+2)[1])等同于*(*((b+2)+1))
//为了说明二维和一位的区别这个问题, 再看个实例
printf("%d\n", *(b + 2)[1]);//410,[1]对*(b + 2)作用(b + 2)是行地址(&b[2])[1]在这里[1]对(b +2)作用,(b+2)是行地址*(&b[2])[1]
//就藏在上面两个式子里
printf("%d\n", **(&b[2] + 1));//410
//足够仔细的话, 观察有两个*, 一个[](相当于一个*), 一个& 号, 总共两个** (*&相互抵消), 最后总是有两个*, 且所有的二维数组都满足这个
//printf("%d\n", *((*(b + 2))[1]));原样替换报错原因最后有3个*
//printf("%d\n", *(&b[2] + 1));输出地址也可以理解了原因最后有1个*
//挑战一下:
printf("%d\n", *((*b) + 1));//120可以说明*b是b[0][0]的地址 *b=&b[0][0]加列地址
printf("%d\n", *((*b + 1) + 2));//210
printf("%d\n", *((*(b + 1)) + 2));//230
printf("%d\n", *b[2] + 1);//311 b[2] == &b[2][0]很好理解 310+1 311
printf("%d\n", *((&b[0][0]) + 2) + 1);//131
printf("%d\n", *((*(b + 2) + 1) + 1));//330第一个+ 1,*(b + 2)是b[2]加的是&b[2][0]
printf("%d\n", *(&(b[2]))[1]);//410
printf("%d\n", *((*b + 2) + 1));//210
printf("%d\n", *(b[2] + 1));//21 320
//回顾
//b[2][1]是怎么表示出来的b[i][j]*(b[i] + j)*(*(b + i) + j)
//为什么C语言数组从a[0]开始,在C语言中索引量不是一一对应,非要[]里的数值对应的是偏移量
//就像挑战一下里的最后一道题*((*b + 2) + 1)*(*b + 2 + 1)*(*b + 3)==*(*(b+0) + 3)
printf("%d\n", *(*(b + 2) + 4));//420如果把*(b + 2)等价于&b[2][0]分开看
printf("%d\n", *(*b + 6));//310
//加深理解偏移量也可以为负数
printf("%d\n", *(b + 1)[-1]);//110
//为什么要这样做的原因是由于计算机在存储器中以连续字节的形式保存宇符, 也就是一维数组排列的,利用索引计算出元素在存储器中的位置
//b[M][N]元素b[i][j]的地址是(*b) + i * N + j 值是 * ((*b) + i * N + j)
//碰见加地址的就是加元素 不是行定加列是把二维数组按序号排成一个一维数组
int(*q)[4] = b;//明明只有3列,这里却是以四个元素为列,佐证二维数组在计算机也是一位排列的
printf("%d\n", *(*(q + 1)));//220
printf("%d\n", *q[1]);//220
int* p2 = b[1];
printf("%d\n", *p2);//210
int* p3 = b[1] + 1;//*(b+1)+ 1
printf("%d\n", *p3);//220
//知道原理后这些也简单了吧