指针数组基本理解

指针数组,顾名思义,是由指针组成的数组,也就是说,定义一个数组,里面存储的内容为指针。
再具体点,指针数组里面,保存的是一组内存地址,每个内存地址都指向一段内存空间。

示例代码

  1. #include <stdio.h>
  2. int main(int argc, char *argv[])
  3. {
  4. char *names[] = {
  5. "Alan", "Frank",
  6. "Mary", "John", "Lisa"
  7. };
  8. printf("%s\n", names[0]);
  9. } ~

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:其实就是跳转到内存的下一个地址。对应到代码中,其实就是访问数组的下一个元素。但是此处没有越界检查,即使超过了数组的范围,也是可以的。

数组越界会发生什么?

  1. int main(int argc, char *argv[])
  2. {
  3. char *names[] = {
  4. "Alan", "Frank",
  5. "Mary", "John", "Lisa"
  6. };
  7. printf("%s\n", names[0]);
  8. printf("%s\n", names[1]);
  9. printf("%s\n", names[2]);
  10. printf("%x\n", names[5]);
  11. printf("%x\n", names[6]);
  12. }

比如上面的代码:

输出结果: Alan

Frank

Mary

91876e00

541a67c0

即使超过了数组的范围,还是能打印出来,只是出来的内容,都是无效的。

小结

对于内存来说,指针、数组啥的,都没有任何意义。它只有最基础的内存空间,给你存放东西的。
至于里面存的是地址,还是寸的具体有意义的内容,如一段ascii码,它都不关心。

谁会去关心?
我们的程序会去关心,说白了,我们的程序会去将内存地址翻译为普通变量的值
、指针的值、指针数组的值。