指针数组基本理解
指针数组,顾名思义,是由指针组成的数组,也就是说,定义一个数组,里面存储的内容为指针。
再具体点,指针数组里面,保存的是一组内存地址,每个内存地址都指向一段内存空间。
示例代码
#include <stdio.h>int main(int argc, char *argv[]){char *names[] = {"Alan", "Frank","Mary", "John", "Lisa"};printf("%s\n", names[0]);} ~
gdb分析
(gdb) p names
$9 = {0x5555555547c4 “Alan”, 0x5555555547c9 “Frank”, 0x5555555547cf “Mary”, 0x5555555547d4 “John”,
0x5555555547d9 “Lisa”}
(gdb) x/8x &names
0x7fffffffd940: 0xc4 0x47 0x55 0x55 0x55 0x55 0x00 0x00
(gdb) p &names
$10 = (char ()[5]) 0x7fffffffd940
(gdb) p &names[0]
$11 = (char **) 0x7fffffffd940
(gdb) x/8x 0x5555555547c4
0x5555555547c4: 0x41 0x6c 0x61 0x6e 0x00 0x46 0x72 0x61
(gdb) x/s 0x5555555547c4
0x5555555547c4: “Alan”
(gdb) x/8x 0x7fffffffd940
0x7fffffffd940: 0xc4 0x47 0x55 0x55 0x55 0x55 0x00 0x00
上面是使用gdb的调试结果:
names对应的内存地址:0x7fffffffd940
(gdb) p &names $10 = (char ()[5]) 0x7fffffffd940
我们将0x7fffffffd940所在一段内存空间打印出来:
(gdb) x/40x 0x7fffffffd940 地址 所存储的值 0x7fffffffd940: 0xc4 0x47 0x55 0x55 0x55 0x55 0x00 0x00 0x7fffffffd948: 0xc9 0x47 0x55 0x55 0x55 0x55 0x00 0x00 0x7fffffffd950: 0xcf 0x47 0x55 0x55 0x55 0x55 0x00 0x00 0x7fffffffd958: 0xd4 0x47 0x55 0x55 0x55 0x55 0x00 0x00 0x7fffffffd960: 0xd9 0x47 0x55 0x55 0x55 0x55 0x00 0x00
(gdb) p/x names $34 = {0x5555555547c4, 0x5555555547c9, 0x5555555547cf, 0x5555555547d4, 0x5555555547d9}
再打印下names
(gdb) p names $9 = {0x5555555547c4 “Alan”, 0x5555555547c9 “Frank”, 0x5555555547cf “Mary”, 0x5555555547d4 “John”, 0x5555555547d9 “Lisa”}
然后就可以根据这些子字符串首地址,访问到子字符串,比如此处的0x5555555547c4
(gdb) x/s 0x5555555547c4 0x5555555547c4: “Alan”
names指向的就是数组,数组中保存的都是各个子字符串的首地址
根据这些首地址,就能完整的将子字符串读取出来,比如此处的首地址0x5555555547c4,对应的字符串就是Alan。
(gdb) x/8x &names[1]
0x7fffffffd948: 0xc9 0x47 0x55 0x55 0x55 0x55 0x00 0x00
指针数组用法
(gdb) p/x names[1] $26 = 0x5555555547c9 (gdb) p/x &names[1] $27 = 0x7fffffffd948
&names[1]: 表示该指针内存地址
names[1]: 表示该指针内存地址中存储的值,也就是指针所指向的地址
(gdb) p/x names + 0 $37 = 0x7fffffffd940 (gdb) p/x names + 1
$38 = 0x7fffffffd948
(gdb) p/x names + 2
$39 = 0x7fffffffd950
(gdb) p/x names + 3
$40 = 0x7fffffffd958
(gdb) p/x names + 4
$41 = 0x7fffffffd960
(gdb) p/x names + 5
$42 = 0x7fffffffd968
names + i:其实就是跳转到内存的下一个地址。对应到代码中,其实就是访问数组的下一个元素。但是此处没有越界检查,即使超过了数组的范围,也是可以的。
数组越界会发生什么?
int main(int argc, char *argv[]){char *names[] = {"Alan", "Frank","Mary", "John", "Lisa"};printf("%s\n", names[0]);printf("%s\n", names[1]);printf("%s\n", names[2]);printf("%x\n", names[5]);printf("%x\n", names[6]);}
比如上面的代码:
输出结果: Alan
Frank
Mary
91876e00
541a67c0
即使超过了数组的范围,还是能打印出来,只是出来的内容,都是无效的。
小结
对于内存来说,指针、数组啥的,都没有任何意义。它只有最基础的内存空间,给你存放东西的。
至于里面存的是地址,还是寸的具体有意义的内容,如一段ascii码,它都不关心。
谁会去关心?
我们的程序会去关心,说白了,我们的程序会去将内存地址翻译为普通变量的值
、指针的值、指针数组的值。
