李迟按:经常碰到些笔试题、面试题,将指针、数组、字符串操作及内存的一些东西发挥到极点,本人以为,以内存角度看问题,有时会更清晰。不过,本人能力不怎么行,写完这篇文章后一段时间,又忘了二维数组和指针的指针了。一来年纪大了,记忆力不行,二来一没碰这些东西就会忘得很快。
本文涉及大量内存地址及十六进制数据。无耐性及无此爱好者可飘过。
说明: 以PC平台为参照,以C语言二维数组及指针数组为对象,测试u-boot中的内存地址及数据。所有数据从Secure CRT上复制得到,绝无人工干预,天然绿色产品,可信度极高。文本涉及代码及数据均以学习研究为目的,代码非实际使用,不作权威解释,任何后果概与山人无关。
山人对指针的指针有莫名的恐惧,尤其自身水平不高情况下。而且,绝口不谈一些计算机科学的著名名词,对那些算法、数据结构、需求分析、设计模式、程序设计、部署等等名词亦有恐惧(学习数据结构阴影至今仍在),因而基本上平时绝口不提。
时过境迁,如今山人也有一定的编码经验,对那些教材中出现的代码亦有自己的认识,对i+++++i这类形式的题目也有清醒的认识。 闲话休提,上代码:
1 | #include <common.h> |
在u-boot命令行下测试结果:
1 | LATE2440 $ pointer_test |
数组a的大小好确认:4(成员个数)*4(int类型大小) = 16;数组b也好确认:3(成员个数)4(指针大小) = 12;数组c是一个二维数组,元素为一指针,3组,每组2个元素,共6个元素,指针大小为4,因此大小为:64 = 24。
现在查看一下数组a所在的地址:
1 | LATE2440 $ md.b 33fa622c |
其后有4个元素,分别为3、38、f和49,变成十进制则是3、56、15和73。
下面看一下数组b的地址:
1 | LATE2440 $ md.b 33fa623c |
前面三个地址分别为:33fa3933、33fa40f1和33fa40f9,就是b[0]、b[1]和b[2]的地址,再看看这些地址:
1 | LATE2440 $ md.b 33fa3933 |
第一个字符串便是“linux”。
1 | LATE2440 $ md.b 33fa40f1 |
前面两个字符串就是“windows”和“mac os”。
后面我们可以看到,在PC平台上,三者其实是紧挨在一起的。这里只有后两个字符串是在一起(33fa40f1+8 = 33fa40f9)。这里我们也可以看到字符串在内存中是以“\0”结尾的(如“windows.”后的点号,实际数据是0),不过在代码上体现不出来。以后我们要注意,在内存分配时需要对字符串(指针)额外关照,至少要分配多一个字节给它。
不过我们也看到了,这三个字符串前面后面都有字符串(u-boot本身的),如:
1 | LATE2440 $ md.b 33fa3900 |
这说明了它们占领了别人的“领域”,而且,在测试结果中我们意外地看到,*a[3]
和*a[4]
分别是b[0]和b[2]的地址,限于能力,这里不作解释,留日后技术提高了再研究。
下面是在PC平台(fedora9)的测试结果:
1 | [latelee@FightNow linux-cc]$ ./a.out |
最后几行都打印了null,因为这的确是没有数据的,不过在u-boot中就死机了。
用gdb查看:
1 | (gdb) p b |
PS:对于元素的访问,array[i]与array+i不太一样,跟具体类型有关,这从代码中亦能看出来。
写这篇文章的原因是在CU论坛上看到有人在讨论二维数组的帖子。看了一下他们的讨论,发现自己啥也不懂,于是借助u-boot来看看,结果发现,自己真的是不太懂。原来自己已经很久没有看C语言的书籍了。看来最近忙着移植,没时间看书了,一些基本概念也不清楚了。身为一个代码工人,除了表示惭愧外,要努力学习了。
山人记于即日