Pointers to Pointers,即二级指针。
一级指针和二级指针的值都是指向一个内存单元:
- 一级指针指向的内存单元存放的是源变量的值,
- 二级指针指向的内存单元存放的是一级指针的地址。
下面,我们通过如下代码展示二级指针的底层实现:
#include <stdio.h> int main(){ int a = 777; int* b = &a; int** c = &b; *b = 888; **c = 999; printf("a=%d\n", a); return 0; }
假设:
- 栈的基地址为0,即rbp寄存器指向0;
- 栈的指针寄存器rsp指向地址为-32。
则,c语言语句**c = 999
的底层实现过程如下图所示:
底层实现中,汇编语言首先找到c的值,通过c的值找到b的值,通过b的值找到a,并赋值999给a。
具体汇编代码如下:
.file "hlist.c" .text .section .rodata .LC0: .string "a=%d\n" .text .globl main .type main, @function main: .LFB0: .cfi_startproc pushq %rbp movq %rsp, %rbp subq $32, %rsp // rsp 减去 32 movq %fs:40, %rax movq %rax, -8(%rbp) xorl %eax, %eax movl $777, -28(%rbp) // 地址为-28处的存储单元的值为777,即a赋值为777 leaq -28(%rbp), %rax // 将-28地址(a的地址)赋给%rax movq %rax, -24(%rbp) // 将-28(64位,8字节)值给地址为-24的存储单元 leaq -24(%rbp), %rax // 将-24地址(b的地址)赋给%rax movq %rax, -16(%rbp) // 将b的地址赋值给地址为-16的存储单元 movq -24(%rbp), %rax // 将b的值(a的地址)赋值给%rax movl $888, (%rax) // a = 888 movq -16(%rbp), %rax // 将c的值(b的地址)赋值给%rax movq (%rax), %rax // 将b的值赋值给%rax movl $999, (%rax) // a = 999 movl -28(%rbp), %eax movl %eax, %esi leaq .LC0(%rip), %rdi movl $0, %eax call printf@PLT movl $0, %eax movq -8(%rbp), %rdx xorq %fs:40, %rdx je .L3 call __stack_chk_fail@PLT .L3: leave .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size main, .-main .ident "GCC: (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0" .section .note.GNU-stack,"",@progbits