文章目录
本文涉及到的代码是C写的,但是在C++上一样适用
0.背景知识–堆和栈的理解
堆和栈的学习:https://blog.csdn.net/pt666/article/details/70876410(这个是基础)
个人理解:(可能有不准确的地方,欢迎指正)
1.当我们在程序中初始化一个变量的时候,首先在栈内存里面建立一个叫age的变量,存储下来
2.系统然后在堆内存中,开辟一块空间,存储具体的值19,例如内存地址为:0fxx02
3.然后栈内存变量age的值即为ofxx02这个地址值
4.程序如果想调用age的时候,直接先找个变量的地址,然后再去这个地址找对应的值
1.C中对变量赋值的理解
#include <stdio.h>
#include<string.h>
#include<stdlib.h>
int main(void)
{
int age = 20;
printf("age = %d\n", age);
printf("age的地址:%p\n", &age);
age = 30;
printf("age = %d\n", age);
printf("age的地址:%p\n", &age);
}
// 如上的结果为:
age = 20
age的地址:006FFD04 #
age = 30
age的地址:006FFD04
以上代码解析:
-
1.最初的时候,age存储的情况
-
2.后续程序对变量重新赋值,相当于把之前存20值的内存地址006FFD04,重新存储为30.(隐藏的含义是内存地址不变,值改变了!)
2.指针和内存地址的理解
指针,是C语言中的一个重要概念及其特点,也是掌握C语言比较困难的部分。指针也就是内存地址,指针变量是用来存放内存地址的变量,不同类型的指针变量所占用的存储单元长度是相同的,而存放数据的变量因数据的类型不同,所占用的存储空间长度也不同.
- &用来取一个变量的地址
- * 用来取一个地址(指针)的值
1.case1:获取变量的地址和指针的值
#include <stdio.h>
int main(void) {
int age = 19;
int* p_age = &age;
printf("age 的地址为: %p\n", &age);
printf("* p_age 指针的值:%d\n", *p_age);
printf("p_age 指针的值:%x\n", p_age);
}
age 的地址为: 00DAFC58
* p_age 指针的值:19
p_age 指针的值:dafc58
- age的地址值与指针的值p_age其实是一个值,即p_age 与 &age 这两个相等
- 所以,在对p_age赋值的时候,int * p_age = &age ,可以把int * 看成一个整体,代表是指针类型,且这个指针指向的是int类型的数据
2.case2:对指针的值重新赋值
#include <stdio.h>
int main(void)
{
int age = 19;
int* p_age = &age;
printf("age 的地址为: %p\n", &age);
printf("* p_age 指针的值:%d\n", *p_age);
*p_age = 20;
printf("age 的地址为: %p\n", &age);
printf("* p_age 指针的值:%d\n", *p_age);
printf("age的值为:%d\n", age);
}
age 的地址为: 009FF898
* p_age 指针的值:19
age 的地址为: 009FF898
* p_age 指针的值:20
age的值为:20
难理解的是,为什么第二次打印*p_age是20:
1.因为p_age指针已经指向了age变量的内存地址,即int p_age = &age
2.所以 p_age相当于是堆内存的地址,*p_age = 20 ,就是上面讲到的赋值的原理过程。
3.case3:改变指针的指向
#include <stdio.h>
int main(void)
{
int age = 19;
int* p = &age;
printf("age 的地址为: %p, age的值为: % d\n", &age, age);
printf("* p 指针的值:%d, p的值为:%p\n", *p, p);
int height = 185;
p = &height; //改变了指针的指向,对应的p存储的地址也就改变了
printf("===========================\n");
printf("age 的地址为: %p, age的值为: % d\n", &age, age);
printf("* p指针的值:%d, p的值为:%p\n", *p, p);
printf("height 的地址为: %p, height的值为: % d\n", &height, height);
}
age 的地址为: 004FFC3C, age的值为: 19
* p 指针的值:19, p的值为:004FFC3C
===========================
age 的地址为: 004FFC3C, age的值为: 19
* p指针的值:185, p的值为:004FFC24
height 的地址为: 004FFC24, height的值为: 185
原理如下:
1.最终的时候,指针指向了变量age,*p的值是age的值,p对应age的内存地址
2.后来,指针指向改变了,改为指向height变量,*p的值是height的值,p对应的也就变为height的内存地址了
3.三种参数传递方式:
参考:https://blog.csdn.net/cocohufei/article/details/6143476
1.按值传递参数(不推荐)
按值传递的过程为:首先计算出实参表达式的值,接着给对应的形参变量分配一个存储空间,该空间的大小等于该形参类型的,然后把以求出的实参表达式的值一一存入到形参变量分配的存储空间中,成为形参变量的初值,供被调用函数执行时使用。这种传递是把实参表达式的值传送给对应的形参变量,故称这种传递方式为“按值传递”。(我读了好几遍,是不是感觉有点拗口,其实就是我上面说的赋值的过程)
#include <stdio.h>
void swap(int i, int n)
{
int t;
t = i;
i = n;
n = t;
printf("%d %d\n", i, n);
printf("%p %p\n", &i, &n);
}
int main()
{
int i = 20, n = 30;
printf("%p %p\n", &i, &n);
printf("===================\n");
swap(i, n);
printf("===================\n");
printf("%d %d\n", i, n);
return 0;
}
// 结果如下:
006FF958 006FF94C
===================
30 20
006FF874 006FF878
===================
20 30
- 调用swap函数本身没有对原始实参进行操作,只有原始实参对应的地址或对应的值变动了,才算对原始实参操作了。
- 虽然在swap函数中形参i, n发生了变化,但对swap函数执行完回收了形参i,n,main函数的实参i,n仍为调用前的值
2.按地址传递参数(感觉很NB,但不实用,特殊场合除外)
#include <stdio.h>
void swap(int*, int*); # 定义的2个变量是,需要传递的为指针,即地址的值
int main()
{
int a = 20, b = 30;
printf("a = %d ,b=%d \n", a, b);
swap(&a, &b);
printf("a = %d ,b=%d \n", a, b);
system("pause");
return 0;
}
void swap(int* x, int* y)
{
int t = *x;
*x = *y;
*y = t;
}
a = 20 ,b=30
a = 30 ,b=20
3.引用传递参数(C++专享,C不支持)
有关这个,请移步我的另一篇博文:
https://blog.csdn.net/chenmozhe22/article/details/106116120
学习文章:https://www.cnblogs.com/lulipro/p/7460206.html#commentform