C---看图学指针和多级指针---入门篇

本文涉及到的代码是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);

}

age 的地址为: 008FFE98
* p_age 指针的值:19


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

4.多级指针的原理

1.一级指针图示:
在这里插入图片描述

  • 在堆内存中保存数据的地址为00B8A000
  • 指针b在栈内存的地址为00B8A004,但指针变量b会保存堆内存的地址00B8A000,方便指针找到堆内存
  • *b的过程是先找到指针变量b对应的堆内存地址,然后再算出来这个地址对应的值,即为10

2.二级指针的图示:
在这里插入图片描述

  • 二级指针c,因为指向了一级指针b,根据一级指针的原理,C指针(指针变量c存放具体的地址值),应该存放的是b指针的内存地址,即为00B8A004
  • 二级指针**c指向一级指针b,按照一级指针的原理,b变量存放的是其指向内存的地址,**c指向b,所以c(c指针变量才能存储值,c指针本身只有指向关系)指针存放的是b指针的内存地址 (很重要!很重要!很重要!)
  • 栈内存上存放的都是内存地址,因为**c指向b,b指向a(堆内存存放的是具体的数值),所以b取值的话,直接找到堆内存,**c取值的话,先找到b,最终还是找到a变量。
  • 无论是二级指针还是多级指针,都按照二部分划分,指针类型(int * 或int ** 或int ***)和指针变量 (p),指针变量赋值保存被指向的内存地址,指针类型负责规定是一级指针、二级指针、或三级指针
#include <stdio.h>

int main() {
	int a = 10;
	int* b = &a;
	int** c = &b;
	printf("a的值:%d\n", a);			// a的实际值
	printf("a的地址:%p\n", &a);			// a的地址值
	printf("==================\n");

	printf("b的地址:%p\n", b);			//一级指针b指向变量a,那b保存的值为a的地址值
	printf("&b的地址:%p\n", &b);		//一级指针b,对应的&b是指针b的真实地址,
	printf("*b的值:%d\n", *b);			//指针b指向变量的真实的值
	printf("==================\n");

	printf("c的地址:%p\n", c);			// 二级指针的指针变量的值为:被指向指针的真实地址,即b的真实地址&b
	printf("&c的地址:%p\n", &c);		// 二级指针c,本身的地址&c
	printf("*c的地址:%p\n", *c);		// 二级指针c,所指向内存空间所保存的真实的值,即b指针保存的真实值,而b指针真实保存的是a的地址,即&a
	printf("**c的值:%d\n", **c);		// 二级指针,最终指向栈内存的值

	return 0;

}

// 如上结果为:

a的值:10
a的地址:00A3FB94
==================
b的地址:00A3FB94
&b的地址:00A3FB88
*b的值:10
==================
c的地址:00A3FB88
&c的地址:00A3FB7C
*c的地址:00A3FB94
**c的值:10





学习文章:https://www.cnblogs.com/lulipro/p/7460206.html#commentform

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章