印度小哥讲解的指针, 真的很好, 这里附上链接:
https://www.bilibili.com/video/BV1bo4y1Z7xf/?spm_id_from=333.999.0.0
1. 程序运行时的四块区域
- 第一块区域是:
code(Text)
, 用来存储程序的指令, - 第二块区域是:
static(Global)
, 用来存储“全局变量和静态变量”. - 第三块区域是:
Stack(栈)
(很重要), 用来存放“局部变量”. - 第四块区域是:
Heap(堆)
, 这个后面再进行讨论.
2. 函数栈帧的创建与销毁
2.1 解释按值传递
下面的函数中, 先执行 main函数
, 毕竟 main函数是一切程序的入口
, 这时候会在 栈顶
创建一个 函数栈帧
, 当执行到 Incrment函数
的时候, 继续在 栈顶
创建一个 函数栈帧
, 此时将 a = 10传递进去
, 但是 函数栈帧
之间是相互独立的, 所以在 Incream
中的 a 是 a'
, 不是 main
函数中的 a
, 此时创建的 a' + 1 = 11
.
然后 Incream函数
执行完毕之后, Incrment 函数
的 函数栈帧
进行销毁, 然后当 main
函数执行到 printf函数
之后继续重复上述行为.
void Incrment(int a) {
a = a + 1;
printf("a = %d\n", a);
}
int main() {
int a;
a = 10;
Incrment(a);
printf("a = %d\n", a);
return 0;
}
2.2 解释按引用(地址)传递
这里直接将 a
的地址进行拷贝过去, 然后在函数中对a
进行修改,
void Incrment(int* p) {
*p = (*p) + 1;
}
int main() {
int a = 10;
Incrment(&a);
printf("a = %d", a);
}
2.2.1 按引用传递中比较另类的情况
这也就说明:p 和 a 一定是相互独立的, 不是同一个变量.
void Incrment(int* p) {
p = NULL;
}
int main() {
int a = 10;
Incrment(&a);
printf("a = %d", a);
}
2.2.2 按引用传递的好处
可以节省很多的空间, 虽然指针也是占用空间的, 但是不需要直接复制过去, 可以节省很多空间.
举例子:下面这张图就很好表示了“按引用(地址)传递”的好处:直接利用指针在原来的地址进行“操作(实现)”, 这样就很好的节省了内存空间, 不用复制一份过去, 再复制回来.