C/C++有一个经典的swap函数---交换两个变量的值,最常见的实现方式是通过指针传递变量地址,这样就能在函数内部直接修改原变量的值。比如,对于两个整型(int)变量a和b,可以这样写:
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main(){
int a = 10, b = 20;
swap(&a, &b); //这里要传变量的地址:
printf("a = %d\n", a);
}
swap函数的参数为什么要用指针?要搞清楚这问题,首先要回顾一下指针。
▲图1
图1说明了指针的用法。这里指针的类型是char*,即指向char的指针。pChar变量只能存储char变量的地址。存储在ch中的值通过指针修改,实现了间接访问(操作)。
在vscode里面编辑好代码,并点击右上角的run按钮(假设已经安装了插件),此时操作系统会创建一个进程,其内存布局如图2
▲图2
一个进程在自已的内存区域中至少包括四个基本部分:代码段、数据段、堆和栈。
代码段(TextSegment):存放程序的执行代码,即编译器编译完成的机器码
数据段(Data Segment):初始化的全局变量和静态变量(读写)
堆(Heap):动态内存分配的区域(如使用malloc申请内存)
栈(Stack):用于存放函数的局部变量、调用返回地址等
现在来看看main函数是怎么一步步执行的。对于每一个函数调用,进程都会留出部分栈空间,来保存该函数所有的变量和变量值。这些空间称为“栈帧”。在main函数的栈帧中,a和b 作为局部变量被保存,如图3所示。
▲图3
调用函数swap时,将创建新的栈帧,如图4所示。每次函数调用都会创建新的栈帧,该栈帧用来维护函数所有的变量和值。 swap函数的栈帧中,a和b同样是局部变量,只不过其值是地址,而且还可以对该地址的变量值进行修改。这样才能实现对a和b的交换。swap函数执行完后,其栈帧会被清空。
▲图4
如果swap函数不传递变量地址
#include<stdio.h>
void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
printf("Adress of a is %p\n", &a);
}
int main(){
int a = 10, b = 20;
printf("Adress of a is %p\n", &a);
swap(a, b);
printf("a = %d\n", a);
}
▲图5
可以看到,a的地址是不同的,且无法实现a和b交换。