淺談 C 字符串?dāng)?shù)組的內(nèi)存布局


首先感謝秋豪大佬對(duì)文章的校對(duì)以及耐心的指導(dǎo) 先獻(xiàn)上我的膝蓋 or2
整理了四種常見的使用 C 語言字符串?dāng)?shù)組的形式
分別對(duì)這以下幾種的內(nèi)存布局進(jìn)行分析

char* array[] = {
    "line1",
    "line10",
    "line100",
    "line1000",
};
char **array = {
    "line1",
    "line10",
    "line100",
    "line1000"
};
char array[][4] = {
    "line1",
    "line10",
    "line100",
    "line1000"
};
char array[][0x10] = {
    "line1",
    "line10",
    "line100",
    "line1000"
};
char * array = {
    "line1",
    "line10",
    "line100",
    "line1000"
};

默認(rèn)讀者已經(jīng)有了以下基本知識(shí):

  1. C 語言基礎(chǔ)
  2. GDB 調(diào)試器的使用
  3. Linux 內(nèi)存布局

環(huán)境

Ubuntu 18.04 x64

參考資料

Linux 程序 64 位內(nèi)存布局:


image.png

image.png
gdb-peda$ vmmap
Start              End                Perm      Name
0x0000555555554000 0x0000555555555000 r-xp      /home/sun/Desktop/c/research/a.out
0x0000555555754000 0x0000555555755000 r--p      /home/sun/Desktop/c/research/a.out
0x0000555555755000 0x0000555555756000 rw-p      /home/sun/Desktop/c/research/a.out
0x00007ffff79e4000 0x00007ffff7bcb000 r-xp      /lib/x86_64-linux-gnu/libc-2.27.so
0x00007ffff7bcb000 0x00007ffff7dcb000 ---p      /lib/x86_64-linux-gnu/libc-2.27.so
0x00007ffff7dcb000 0x00007ffff7dcf000 r--p      /lib/x86_64-linux-gnu/libc-2.27.so
0x00007ffff7dcf000 0x00007ffff7dd1000 rw-p      /lib/x86_64-linux-gnu/libc-2.27.so
0x00007ffff7dd1000 0x00007ffff7dd5000 rw-p      mapped
0x00007ffff7dd5000 0x00007ffff7dfc000 r-xp      /lib/x86_64-linux-gnu/ld-2.27.so
0x00007ffff7fdd000 0x00007ffff7fdf000 rw-p      mapped
0x00007ffff7ff7000 0x00007ffff7ffa000 r--p      [vvar]
0x00007ffff7ffa000 0x00007ffff7ffc000 r-xp      [vdso]
0x00007ffff7ffc000 0x00007ffff7ffd000 r--p      /lib/x86_64-linux-gnu/ld-2.27.so
0x00007ffff7ffd000 0x00007ffff7ffe000 rw-p      /lib/x86_64-linux-gnu/ld-2.27.so
0x00007ffff7ffe000 0x00007ffff7fff000 rw-p      mapped
0x00007ffffffdd000 0x00007ffffffff000 rw-p      [stack]
0xffffffffff600000 0xffffffffff601000 r-xp      [vsyscall]

第一種

char* array[] = {
    "line1",
    "line10",
    "line100",
    "line1000",
};

首先該變量為一個(gè)數(shù)組,元素的類型為指向字符的指針奉芦,在定義時(shí)就包含四個(gè)元素多望,那么在棧中就占有 4 * WORD_SIZE = 32 字節(jié)的空間,這 32 字節(jié)的空間用來分別存放指向真正字符串的指針爆安。
在使用 execve 這個(gè)函數(shù)的時(shí)候叛复,參考 man 手冊,即可發(fā)現(xiàn)扔仓,參數(shù)的類型即為這種類型:

EXECVE(2)                  Linux Programmer's Manual                 EXECVE(2)

NAME
       execve - execute program

SYNOPSIS
       #include <unistd.h>

       int execve(const char *filename, char *const argv[],
                  char *const envp[]);
[----------------------------------registers-----------------------------------]
RAX: 0x555555554805 ("line1000")
RBX: 0x0
RCX: 0x555555554760 (<__libc_csu_init>: push   r15)
RDX: 0x0
RSI: 0x7fffffffdbb8 --> 0x7fffffffdfb7 ("/home/sun/Desktop/c/research/a.out")
RDI: 0x1
RBP: 0x7fffffffdac0 --> 0x7fffffffdad0 --> 0x555555554760 (<__libc_csu_init>:   push   r15)
RSP: 0x7fffffffda90 --> 0x5555555547f0 --> 0x696c0031656e696c ('line1')
RIP: 0x5555555546c2 (<function1+88>:    leave)
R8 : 0x7ffff7dd0d80 --> 0x0
R9 : 0x7ffff7dd0d80 --> 0x0
R10: 0x2
R11: 0x3
R12: 0x555555554560 (<_start>:  xor    ebp,ebp)
R13: 0x7fffffffdbb0 --> 0x1
R14: 0x0
R15: 0x0
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x5555555546b2 <function1+72>:       xor    rdx,QWORD PTR fs:0x28
   0x5555555546bb <function1+81>:       je     0x5555555546c2 <function1+88>
   0x5555555546bd <function1+83>:       call   0x555555554540 <__stack_chk_fail@plt>
=> 0x5555555546c2 <function1+88>:       leave
   0x5555555546c3 <function1+89>:       ret
   0x5555555546c4 <function2>:  push   rbp
   0x5555555546c5 <function2+1>:        mov    rbp,rsp
   0x5555555546c8 <function2+4>:        lea    rax,[rip+0x121]        # 0x5555555547f0
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffda90 --> 0x5555555547f0 --> 0x696c0031656e696c ('line1')
0008| 0x7fffffffda98 --> 0x5555555547f6 --> 0x6c003031656e696c ('line10')
0016| 0x7fffffffdaa0 --> 0x5555555547fd --> 0x303031656e696c ('line100')
0024| 0x7fffffffdaa8 --> 0x555555554805 ("line1000")
0032| 0x7fffffffdab0 --> 0x555555554760 (<__libc_csu_init>:     push   r15)
0040| 0x7fffffffdab8 --> 0x2d54ce84036a2500
0048| 0x7fffffffdac0 --> 0x7fffffffdad0 --> 0x555555554760 (<__libc_csu_init>:  push   r15)
0056| 0x7fffffffdac8 --> 0x55555555473a (<main+14>:     mov    eax,0x0)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x00005555555546c2      10      }
gdb-peda$ p array
$2 = {0x5555555547f0 "line1", 0x5555555547f6 "line10", 0x5555555547fd "line100",
  0x555555554805 "line1000"}
gdb-peda$ x /32xb array
0x7fffffffda90: 0xf0    0x47    0x55    0x55    0x55    0x55    0x00    0x00
0x7fffffffda98: 0xf6    0x47    0x55    0x55    0x55    0x55    0x00    0x00
0x7fffffffdaa0: 0xfd    0x47    0x55    0x55    0x55    0x55    0x00    0x00
0x7fffffffdaa8: 0x05    0x48    0x55    0x55    0x55    0x55    0x00    0x00
gdb-peda$

第二種

char **array = {
    "line1",
    "line10",
    "line100",
    "line1000"
};

這種寫法在編譯的時(shí)候會(huì)存在 Warning:

?  ~ gcc ./main.c 
./main.c:2:5: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
     "line1",
     ^~~~~~~
./main.c:2:5: note: (near initialization for ‘a(chǎn)rray’)
./main.c:3:5: warning: excess elements in scalar initializer
     "line10",
     ^~~~~~~~
./main.c:3:5: note: (near initialization for ‘a(chǎn)rray’)
./main.c:4:5: warning: excess elements in scalar initializer
     "line100",
     ^~~~~~~~~
./main.c:4:5: note: (near initialization for ‘a(chǎn)rray’)
./main.c:5:5: warning: excess elements in scalar initializer
     "line1000"
     ^~~~~~~~~~
./main.c:5:5: note: (near initialization for ‘a(chǎn)rray’)
excess elements in scalar initializer
過多的元素在變量的初始化中

C 語言中有兩個(gè)概念:(參考 C11-§6.2.5 Types)

  • scalar type
  • aggregate types

可以簡單記憶為:包含單個(gè)值的變量類型為scalar type褐奥,而多個(gè)值的變量為aggregate types
注意有一個(gè)容易搞錯(cuò)的地方:union 類型為scalar type, 因?yàn)樵趦?nèi)存中同時(shí)只能包含一個(gè)數(shù)據(jù)

image.png

image.png

這里的 Warning 就是警告我們:

char ** 是一個(gè)標(biāo)量,但是我們使用了用來初始化聚合類型的方式來初始化了

這樣翘簇,我們在花括號(hào)中后面的值則會(huì)被忽略掉

[----------------------------------registers-----------------------------------]
RAX: 0x5555555546b4 --> 0x31656e696c ('line1')
RBX: 0x0 
RCX: 0x555555554630 (<__libc_csu_init>: push   r15)
RDX: 0x7fffffffdbf8 --> 0x7fffffffe01e ("rvm_version=1.29.3 (latest)")
RSI: 0x7fffffffdbe8 --> 0x7fffffffdffb ("/home/sun/Desktop/c/research/a.out")
RDI: 0x1 
RBP: 0x7fffffffdae0 --> 0x7fffffffdb00 --> 0x555555554630 (<__libc_csu_init>:   push   r15)
RSP: 0x7fffffffdae0 --> 0x7fffffffdb00 --> 0x555555554630 (<__libc_csu_init>:   push   r15)
RIP: 0x55555555460a (<function+16>: pop    rbp)
R8 : 0x7ffff7dd0d80 --> 0x0 
R9 : 0x7ffff7dd0d80 --> 0x0 
R10: 0x2 
R11: 0x3 
R12: 0x5555555544f0 (<_start>:  xor    ebp,ebp)
R13: 0x7fffffffdbe0 --> 0x1 
R14: 0x0 
R15: 0x0
EFLAGS: 0x206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x5555555545fe <function+4>: lea    rax,[rip+0xaf]        # 0x5555555546b4
   0x555555554605 <function+11>:    mov    QWORD PTR [rbp-0x8],rax
   0x555555554609 <function+15>:    nop
=> 0x55555555460a <function+16>:    pop    rbp
   0x55555555460b <function+17>:    ret    
   0x55555555460c <main>:   push   rbp
   0x55555555460d <main+1>: mov    rbp,rsp
   0x555555554610 <main+4>: sub    rsp,0x10
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdae0 --> 0x7fffffffdb00 --> 0x555555554630 (<__libc_csu_init>:  push   r15)
0008| 0x7fffffffdae8 --> 0x555555554625 (<main+25>: mov    eax,0x0)
0016| 0x7fffffffdaf0 --> 0x7fffffffdbe8 --> 0x7fffffffdffb ("/home/sun/Desktop/c/research/a.out")
0024| 0x7fffffffdaf8 --> 0x100000000 
0032| 0x7fffffffdb00 --> 0x555555554630 (<__libc_csu_init>: push   r15)
0040| 0x7fffffffdb08 --> 0x7ffff7a05b97 (<__libc_start_main+231>:   mov    edi,eax)
0048| 0x7fffffffdb10 --> 0x1 
0056| 0x7fffffffdb18 --> 0x7fffffffdbe8 --> 0x7fffffffdffb ("/home/sun/Desktop/c/research/a.out")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x000055555555460a  40  }
gdb-peda$ p array
$1 = (char **) 0x5555555546b4
gdb-peda$ x /32xb array
0x5555555546b4: 0x6c    0x69    0x6e    0x65    0x31    0x00    0x00    0x00
0x5555555546bc: 0x01    0x1b    0x03    0x3b    0x40    0x00    0x00    0x00
0x5555555546c4: 0x07    0x00    0x00    0x00    0x14    0xfe    0xff    0xff
0x5555555546cc: 0x8c    0x00    0x00    0x00    0x24    0xfe    0xff    0xff
gdb-peda$ p *array
$2 = 0x31656e696c <error: Cannot access memory at address 0x31656e696c>
gdb-peda$ p **array
Cannot access memory at address 0x31656e696c
gdb-peda$ 

可以看到我們在訪問:*array 的時(shí)候報(bào)錯(cuò):

gdb-peda$ p *array
$2 = 0x31656e696c <error: Cannot access memory at address 0x31656e696c>

是因?yàn)?array 的類型為指針類型撬码,并且我們在初始化的時(shí)候它的值為:line1
在訪問的時(shí)候,line1 被當(dāng)成了一個(gè)地址去訪問版保,而它當(dāng)然不是一個(gè)合法的地址呜笑,所以報(bào)錯(cuò)。
當(dāng)我們將代碼進(jìn)行調(diào)整:

int function(){
    char ** array = {
        "12345678AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
        "line10",
        "line100",
        "line1000"
    };
}

int main(int argc, char* argv[]){
    function();
}

編譯后再進(jìn)行調(diào)試找筝,可以發(fā)現(xiàn)蹈垢,array所在的棧空間存儲(chǔ)的數(shù)據(jù)為:

12345678AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

而后面的 line10, line100 等被忽略

[----------------------------------registers-----------------------------------]
RAX: 0x5555555546b8 ("12345678", 'A' <repeats 52 times>)
RBX: 0x0 
RCX: 0x555555554630 (<__libc_csu_init>: push   r15)
RDX: 0x7fffffffdbf8 --> 0x7fffffffe01d ("rvm_version=1.29.3 (latest)")
RSI: 0x7fffffffdbe8 --> 0x7fffffffdffa ("/home/sun/Desktop/c/research/a.out")
RDI: 0x1 
RBP: 0x7fffffffdb00 --> 0x555555554630 (<__libc_csu_init>:  push   r15)
RSP: 0x7fffffffdae8 --> 0x555555554625 (<main+25>:  mov    eax,0x0)
RIP: 0x55555555460b (<function+17>: ret)
R8 : 0x7ffff7dd0d80 --> 0x0 
R9 : 0x7ffff7dd0d80 --> 0x0 
R10: 0x2 
R11: 0x3 
R12: 0x5555555544f0 (<_start>:  xor    ebp,ebp)
R13: 0x7fffffffdbe0 --> 0x1 
R14: 0x0 
R15: 0x0
EFLAGS: 0x206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x555555554605 <function+11>:    mov    QWORD PTR [rbp-0x8],rax
   0x555555554609 <function+15>:    nop
   0x55555555460a <function+16>:    pop    rbp
=> 0x55555555460b <function+17>:    ret    
   0x55555555460c <main>:   push   rbp
   0x55555555460d <main+1>: mov    rbp,rsp
   0x555555554610 <main+4>: sub    rsp,0x10
   0x555555554614 <main+8>: mov    DWORD PTR [rbp-0x4],edi
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdae8 --> 0x555555554625 (<main+25>: mov    eax,0x0)
0008| 0x7fffffffdaf0 --> 0x7fffffffdbe8 --> 0x7fffffffdffa ("/home/sun/Desktop/c/research/a.out")
0016| 0x7fffffffdaf8 --> 0x100000000 
0024| 0x7fffffffdb00 --> 0x555555554630 (<__libc_csu_init>: push   r15)
0032| 0x7fffffffdb08 --> 0x7ffff7a05b97 (<__libc_start_main+231>:   mov    edi,eax)
0040| 0x7fffffffdb10 --> 0x1 
0048| 0x7fffffffdb18 --> 0x7fffffffdbe8 --> 0x7fffffffdffa ("/home/sun/Desktop/c/research/a.out")
0056| 0x7fffffffdb20 --> 0x100008000 
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x000055555555460b  40  }
gdb-peda$ p array
$1 = (char **) 0x5555555546b8
gdb-peda$ x /32xb array
0x5555555546b8: 0x31    0x32    0x33    0x34    0x35    0x36    0x37    0x38
0x5555555546c0: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0x5555555546c8: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
0x5555555546d0: 0x41    0x41    0x41    0x41    0x41    0x41    0x41    0x41
gdb-peda$ 

第三種:第二位長度小于最長的字符串

char array[][4] = {
    "line1",
    "line10",
    "line100",
    "line1000"
};

該變量為一個(gè)二維數(shù)組袖裕,第二維的長度為 4曹抬,二維數(shù)組在內(nèi)存中事實(shí)上是一維存儲(chǔ)的(整個(gè)內(nèi)存空間都可以視為一維的,只是存在了數(shù)據(jù)結(jié)構(gòu)才會(huì)將一維擴(kuò)展為各種各樣的結(jié)構(gòu))急鳄,那么我們需要訪問二維數(shù)組的其中一個(gè)元素谤民,事實(shí)上是通過偏移來計(jì)算出來的,那么編譯器就必須要求我們在定義二維數(shù)組的時(shí)候指定第二維的大小疾宏,如果不指定张足,則無法通過索引來訪問二維數(shù)組的一個(gè)元素(事實(shí)上二維數(shù)組的一個(gè)元素就是一個(gè)一維數(shù)組)
在這個(gè)例子中,這個(gè)變量是一個(gè)棧變量(根據(jù)下面 gdb 調(diào)試日志可以看出地址 0x7f 坎藐,該空間為椢梗空間)哼绑,存儲(chǔ)在棧中,地址為 0x7fffffffdaa0碉咆,并且是線性存儲(chǔ)抖韩。由于在定義時(shí),二維數(shù)組的第二位長度為 4疫铜,編譯器就會(huì)將長度大于 4 的字符串截?cái)嗝。涣粝虑八膫€(gè)字節(jié),那么如果我們使用索引去訪問它的第二個(gè)元素:也就會(huì)訪問到 0x7fffffffdaa0 + 4 = 0x7fffffffdaa4壳咕,也就是第二個(gè) line席揽。

[----------------------------------registers-----------------------------------]
RAX: 0x656e696c656e696c ('lineline')
RBX: 0x0
RCX: 0x555555554760 (<__libc_csu_init>: push   r15)
RDX: 0x0
RSI: 0x7fffffffdbb8 --> 0x7fffffffdfb7 ("/home/sun/Desktop/c/research/a.out")
RDI: 0x1
RBP: 0x7fffffffdac0 --> 0x7fffffffdad0 --> 0x555555554760 (<__libc_csu_init>:   push   r15)
RSP: 0x7fffffffdaa0 ("linelinelineline`GUUUU")
RIP: 0x555555554718 (<function3+66>:    leave)
R8 : 0x7ffff7dd0d80 --> 0x0
R9 : 0x7ffff7dd0d80 --> 0x0
R10: 0x2
R11: 0x3
R12: 0x555555554560 (<_start>:  xor    ebp,ebp)
R13: 0x7fffffffdbb0 --> 0x1
R14: 0x0
R15: 0x0
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x555555554708 <function3+50>:       xor    rdx,QWORD PTR fs:0x28
   0x555555554711 <function3+59>:       je     0x555555554718 <function3+66>
   0x555555554713 <function3+61>:       call   0x555555554540 <__stack_chk_fail@plt>
=> 0x555555554718 <function3+66>:       leave
   0x555555554719 <function3+67>:       ret
   0x55555555471a <function4>:  push   rbp
   0x55555555471b <function4+1>:        mov    rbp,rsp
   0x55555555471e <function4+4>:        lea    rax,[rip+0xcb]        # 0x5555555547f0
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdaa0 ("linelinelineline`GUUUU")
0008| 0x7fffffffdaa8 ("lineline`GUUUU")
0016| 0x7fffffffdab0 --> 0x555555554760 (<__libc_csu_init>:     push   r15)
0024| 0x7fffffffdab8 --> 0x2d54ce84036a2500
0032| 0x7fffffffdac0 --> 0x7fffffffdad0 --> 0x555555554760 (<__libc_csu_init>:  push   r15)
0040| 0x7fffffffdac8 --> 0x55555555474e (<main+34>:     mov    eax,0x0)
0048| 0x7fffffffdad0 --> 0x555555554760 (<__libc_csu_init>:     push   r15)
0056| 0x7fffffffdad8 --> 0x7ffff7a05b97 (<__libc_start_main+231>:       mov    edi,eax)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x0000555555554718      29      }
gdb-peda$ p array
$5 = {"line", "line", "line", "line"}
gdb-peda$ x /32xb array
0x7fffffffdaa0: 0x6c    0x69    0x6e    0x65    0x6c    0x69    0x6e    0x65
0x7fffffffdaa8: 0x6c    0x69    0x6e    0x65    0x6c    0x69    0x6e    0x65
0x7fffffffdab0: 0x60    0x47    0x55    0x55    0x55    0x55    0x00    0x00
0x7fffffffdab8: 0x00    0x25    0x6a    0x03    0x84    0xce    0x54    0x2d
gdb-peda$ x /4s array
0x7fffffffdaa0: "linelinelineline`GUUUU"
0x7fffffffdab7: ""
0x7fffffffdab8: ""
0x7fffffffdab9: "%j\003\204\316T-\320\332\377\377\377\177"
gdb-peda$

第三種:第二位長度大于最長的字符串

char array[][0x10] = {
    "line1",
    "line10",
    "line100",
    "line1000"
};

這次定義二維數(shù)組的第二位尺寸的時(shí)候大于了最長字符串的長度,可以看到編譯器就會(huì)按照我們定義的尺寸為我們在棧上分配內(nèi)存谓厘,得到的矩陣是一個(gè)非常規(guī)整方正的矩陣幌羞。
這種情況是可以通過索引訪問的,訪問的結(jié)果為得到一個(gè)固定長度的字符數(shù)組(包括后面的若干個(gè)空字節(jié))

[----------------------------------registers-----------------------------------]
RAX: 0x30303031656e696c ('line1000')
RBX: 0x0
RCX: 0x0
RDX: 0x0
RSI: 0x7fffffffdbb8 --> 0x7fffffffdfb7 ("/home/sun/Desktop/c/research/a.out")
RDI: 0x1
RBP: 0x7fffffffdad0 --> 0x5555555547f0 (<__libc_csu_init>:      push   r15)
RSP: 0x7fffffffdac8 --> 0x5555555547dd (<main+34>:      mov    eax,0x0)
RIP: 0x5555555547a8 (<function3+210>:   ret)
R8 : 0x7ffff7dd0d80 --> 0x0
R9 : 0x7ffff7dd0d80 --> 0x0
R10: 0x2
R11: 0x3
R12: 0x555555554560 (<_start>:  xor    ebp,ebp)
R13: 0x7fffffffdbb0 --> 0x1
R14: 0x0
R15: 0x0
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x5555555547a0 <function3+202>:      je     0x5555555547a7 <function3+209>
   0x5555555547a2 <function3+204>:      call   0x555555554540 <__stack_chk_fail@plt>
   0x5555555547a7 <function3+209>:      leave
=> 0x5555555547a8 <function3+210>:      ret
   0x5555555547a9 <function4>:  push   rbp
   0x5555555547aa <function4+1>:        mov    rbp,rsp
   0x5555555547ad <function4+4>:        lea    rax,[rip+0xc0]        # 0x555555554874
   0x5555555547b4 <function4+11>:       mov    QWORD PTR [rbp-0x8],rax
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdac8 --> 0x5555555547dd (<main+34>:     mov    eax,0x0)
0008| 0x7fffffffdad0 --> 0x5555555547f0 (<__libc_csu_init>:     push   r15)
0016| 0x7fffffffdad8 --> 0x7ffff7a05b97 (<__libc_start_main+231>:       mov    edi,eax)
0024| 0x7fffffffdae0 --> 0x1
0032| 0x7fffffffdae8 --> 0x7fffffffdbb8 --> 0x7fffffffdfb7 ("/home/sun/Desktop/c/research/a.out")
0040| 0x7fffffffdaf0 --> 0x100008000
0048| 0x7fffffffdaf8 --> 0x5555555547bb (<main>:        push   rbp)
0056| 0x7fffffffdb00 --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x00005555555547a8      29      }
gdb-peda$ p array
$3 = {"line1", '\000' <repeats 26 times>, "line10", '\000' <repeats 25 times>,
  "line100", '\000' <repeats 24 times>, "line1000", '\000' <repeats 23 times>}
gdb-peda$ x /64xb array
0x7fffffffda30: 0x6c    0x69    0x6e    0x65    0x31    0x00    0x00    0x00
0x7fffffffda38: 0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0x7fffffffda40: 0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0x7fffffffda48: 0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0x7fffffffda50: 0x6c    0x69    0x6e    0x65    0x31    0x30    0x00    0x00
0x7fffffffda58: 0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0x7fffffffda60: 0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0x7fffffffda68: 0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
gdb-peda$ p array[0]
$4 = "line1", '\000' <repeats 26 times>
gdb-peda$

第四種

char * array = {
    "line1",
    "line10",
    "line100",
    "line1000"
};

這種和第二種相同庞呕,同樣編譯器警告我們初始化一個(gè)標(biāo)量的時(shí)候參數(shù)過多新翎,這里不再贅述
事實(shí)上這種寫法是不合邏輯的
貼出 gdb 日志

[----------------------------------registers-----------------------------------]
RAX: 0x5555555547f0 --> 0x696c0031656e696c ('line1')
RBX: 0x0
RCX: 0x555555554760 (<__libc_csu_init>: push   r15)
RDX: 0x0
RSI: 0x7fffffffdbb8 --> 0x7fffffffdfb7 ("/home/sun/Desktop/c/research/a.out")
RDI: 0x1
RBP: 0x7fffffffdad0 --> 0x555555554760 (<__libc_csu_init>:      push   r15)
RSP: 0x7fffffffdac8 --> 0x555555554758 (<main+44>:      mov    eax,0x0)
RIP: 0x55555555472b (<function4+17>:    ret)
R8 : 0x7ffff7dd0d80 --> 0x0
R9 : 0x7ffff7dd0d80 --> 0x0
R10: 0x2
R11: 0x3
R12: 0x555555554560 (<_start>:  xor    ebp,ebp)
R13: 0x7fffffffdbb0 --> 0x1
R14: 0x0
R15: 0x0
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x555555554725 <function4+11>:       mov    QWORD PTR [rbp-0x8],rax
   0x555555554729 <function4+15>:       nop
   0x55555555472a <function4+16>:       pop    rbp
=> 0x55555555472b <function4+17>:       ret
   0x55555555472c <main>:       push   rbp
   0x55555555472d <main+1>:     mov    rbp,rsp
   0x555555554730 <main+4>:     mov    eax,0x0
   0x555555554735 <main+9>:     call   0x55555555466a <function1>
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffdac8 --> 0x555555554758 (<main+44>:     mov    eax,0x0)
0008| 0x7fffffffdad0 --> 0x555555554760 (<__libc_csu_init>:     push   r15)
0016| 0x7fffffffdad8 --> 0x7ffff7a05b97 (<__libc_start_main+231>:       mov    edi,eax)
0024| 0x7fffffffdae0 --> 0x1
0032| 0x7fffffffdae8 --> 0x7fffffffdbb8 --> 0x7fffffffdfb7 ("/home/sun/Desktop/c/research/a.out")
0040| 0x7fffffffdaf0 --> 0x100008000
0048| 0x7fffffffdaf8 --> 0x55555555472c (<main>:        push   rbp)
0056| 0x7fffffffdb00 --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x000055555555472b      38      }
gdb-peda$ p array
$6 = 0x5555555547f0 "line1"
gdb-peda$ x /32xb array
0x5555555547f0: 0x6c    0x69    0x6e    0x65    0x31    0x00    0x6c    0x69
0x5555555547f8: 0x6e    0x65    0x31    0x30    0x00    0x6c    0x69    0x6e
0x555555554800: 0x65    0x31    0x30    0x30    0x00    0x6c    0x69    0x6e
0x555555554808: 0x65    0x31    0x30    0x30    0x30    0x00    0x00    0x00
gdb-peda$

參考:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子值骇,更是在濱河造成了極大的恐慌疾牲,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件构拳,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)盏混,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來惜论,“玉大人许赃,你說我怎么就攤上這事」堇啵” “怎么了混聊?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長乾巧。 經(jīng)常有香客問我句喜,道長,這世上最難降的妖魔是什么沟于? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任咳胃,我火速辦了婚禮,結(jié)果婚禮上旷太,老公的妹妹穿的比我還像新娘展懈。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布存崖。 她就那樣靜靜地躺著冻记,像睡著了一般。 火紅的嫁衣襯著肌膚如雪金句。 梳的紋絲不亂的頭發(fā)上檩赢,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音违寞,去河邊找鬼贞瞒。 笑死,一個(gè)胖子當(dāng)著我的面吹牛趁曼,可吹牛的內(nèi)容都是我干的军浆。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼挡闰,長吁一口氣:“原來是場噩夢啊……” “哼乒融!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起摄悯,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤赞季,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后奢驯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體申钩,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年瘪阁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了撒遣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡管跺,死狀恐怖义黎,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情豁跑,我是刑警寧澤廉涕,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站贩绕,受9級(jí)特大地震影響火的,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜淑倾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一馏鹤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧娇哆,春花似錦湃累、人聲如沸勃救。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蒙秒。三九已至,卻和暖如春宵统,著一層夾襖步出監(jiān)牢的瞬間晕讲,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國打工马澈, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瓢省,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓痊班,卻偏偏與公主長得像勤婚,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子涤伐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時(shí)...
    歐辰_OSR閱讀 29,321評(píng)論 8 265
  • 一馒胆、Java 簡介 Java是由Sun Microsystems公司于1995年5月推出的Java面向?qū)ο蟪绦蛟O(shè)計(jì)...
    子非魚_t_閱讀 4,154評(píng)論 1 44
  • 指針是C語言中廣泛使用的一種數(shù)據(jù)類型。 運(yùn)用指針編程是C語言最主要的風(fēng)格之一凝果。利用指針變量可以表示各種數(shù)據(jù)結(jié)構(gòu)祝迂; ...
    朱森閱讀 3,424評(píng)論 3 44
  • 注: 效果:水彩邊界 筆刷:水彩及其他 FIN
    拾壹曰11閱讀 266評(píng)論 0 2
  • 因?yàn)槲业木窒尢啵咸鞝斂偸遣环判钠骶唬o我安排很多能忍耐我壞脾氣的家人液兽,給我以最大的包容,還給我安排三個(gè)榜樣掌动,讓我可...
    悠然_3c09閱讀 1,558評(píng)論 0 3