从计算理解数组
公式法(基础)
数组是我们C语言中最常用的数据结构之一,我们必须熟练掌握.
数组名就是这整个数组的首地址,这里我们记为a, 我们常常苦恼 a+1,&a+1,a[0]+1究竟指向的是哪个元素.
我曾试图写出所有数组的首地址通项转换公式,但发现写出来的意义不大,不容易记,只是摆着好看,而我们平常用得最多的数组的维度都不会超过三维,那么我们只要把握低维度的公式就足以应付日常编程了.
由于一维过于简单,这里就不讨论了,只着重讨论二维和三维数组.
运用下面的公式,可以准确算出数组首地址变化后的值.
符号的定义:
T 表示任意的类型
a 表示数组的首地址
k 表示某一偏移量
SIZET 表示T类型的大小(单位字节)
val(x) 表示x的值,下面表示数组首地址的值
m,n,k 表示任意自然数
补充公式(解引用与数组引用转换公式
):
对任一数组a来说,取自然数q,m,n,k,均满足
a[m]+k <=> *(a+m)+k
a[m][n]+k <=> *(*(a+m)+n)+k
a[q][m][n]+k <=> *(*(*(a+q)+m)+n)+k
直观法(推荐)
从数字中把握数组是准确的,但是却并不直观,下面是直观对数组首地址的运算的理解
T**** //体 元素
T*** //面 元素
T** //行 元素
T* //个 元素
T //值
例如 T* + 1
则表示跳到下一个元素
例如 T** + 1
则表示跳到下一行元素(究竟跳过了多少个元素由一行中有多少个元素决定)
每当想要得知指向哪一个元素时,先判断类型,再根据类型进行推理,这种直观方法会更常用一些.
具体是,忽略类型的大小(即SIZET),代之以元素的个数来表示偏移的距离,从而推算出指向了哪个元素.
代码
下面给出测试代码以验证公式的准确性,不包含解引用与数组引用转换公式
#include "pch.h"
#include<stdio.h>
#include <iostream>
using namespace std;
#define q 5
#define m 4
#define n 3
const int k = 2;
typedef int T;
int main()
{
T a[m][n];
T b[q][m][n];
const int valueofa = (int)a;
printf("value of a: %d
", valueofa);
const int valueofb = (int)b;
printf("value of b: %d
", valueofb);
const int SIZET = sizeof(T);
printf("SIZET: %d
", SIZET);
printf("
");
//atest
printf("&a+k : %d --- %d+%d*%d*%d*%d
", &a + k,valueofa,k,m,n,SIZET);
printf("a+k : %d --- %d+%d*%d*%d
", a + k, valueofa, k, n, SIZET);
printf("*a+k : %d --- %d+%d*%d
", *a + k, valueofa, k, SIZET);
printf("
");
//btest
printf("&b+k : %d --- %d+%d*%d*%d*%d*%d
", &b + k, valueofb, k, q, m, n, SIZET);
printf("b+k : %d --- %d+%d*%d*%d*%d
", b + k, valueofb, k,m, n, SIZET);
printf("*b+k : %d --- %d+%d*%d*%d
", *b + k, valueofb, k,n, SIZET);
printf("**b+k: %d --- %d+%d*%d
", **b + k, valueofb, k, SIZET);
return 0;
}
执行结果:
value of a: 19921648
value of b: 19921400
SIZET: 4
&a+k : 19921744 --- 19921648+2*4*3*4
a+k : 19921672 --- 19921648+2*3*4
*a+k : 19921656 --- 19921648+2*4
&b+k : 19921880 --- 19921400+2*5*4*3*4
b+k : 19921496 --- 19921400+2*4*3*4
*b+k : 19921424 --- 19921400+2*3*4
**b+k: 19921408 --- 19921400+2*4