下面的例子都是有利于理解指针的运用的。我之前就总结过,但是没有形成博客。直到昨天,我在写一个平衡二叉树的插入的时候,发现自己对于指针的运用还是不特别熟悉,所以决定总结一下,以便之后更好的编程。尤其是写有关树的代码,真的是避不开指针。困难只有克服,今天你逃避了,迟早有一天你又会遇到他的。
关于测试点3,至于会不会出现这个bug,我在几个编译器上面都没有测试出来。但是我还是认为会出现这样的问题,所以如果大家有自己的看法,欢迎评论区讨论!!!
// Demo_3.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include"pch.h"
#include<stdio.h>
#include<stdlib.h>
//第一个测试
/*
void fun(int *p)
{
*p = 3;
}
int main()
{
int a = 10;
//自己可以画一个内存四区图来分析这个问题
//此时函数fun()函数应该要改变a的值
fun(&a);
printf("%d", a);
return 0;
}
*/
//第二个测试
/*
void fun(int *p)
{
*p = 3;
}
int main()
{
int a = 10;
int *q = &a;
fun(q);
printf("%d\n", a);
fun(&a);
printf("%d\n", a);
//通过画内存四区图分析,a的值的确已经被改变了,但是q的值是没有改变的
//什么意思呢?就是说,fun()函数没有改变q的值,它的值还是原来a的地址。
//因为a的地址上面的值被改变了,所以*q的值也就被改变了。但是q的值是没有
//改变的。这里我称*q的值为“超值”,而q的值就是“值”
printf("%d", *q);
return 0;
}
*/
//第三个测试
/*
void fun(int *p)
{
int a = 9;
p = &a;
}
int main()
{
int a = 10;
int *q = &a;
//这里其实是有一个隐藏的bug的。因为在fun()函数中,,int a=9就是一个局部变量
//当fun()函数返回的时候,就会导致其实那里的内存就是一个不可知的内存。但是这个
//不一定会输出“烫烫烫”,因为可能在你输出的时候并没有释放内存给别人使用。
//***:我认为就是在一个函数中进行指针的赋值,你要保证的你得地址是一个堆内存
//地址才好。这样子就就不会出现你的指针指向的是一个被释放的内存空间。
fun(q);
int b = 10;
printf("%d", *q);
return 0;
}
*/
//第四个测试
/*
void fun(int **p)
{
int *q = (int*)malloc(sizeof(int));
*q = 50;
*p = q;
}
void fun1(int *p)
{
int *q = (int*)malloc(sizeof(int));
*q = 50;
p = q;
}
int main()
{
int *q = NULL;
//我写这个测试原因就在于提出一个结论:“你要想通过函数来改变指针的值(注意,
//不是超值,仅仅是指针的值),那么就一定要通过指针的指针来改变这个指针的值。”
//这个问题就在你大二的时候出现过,其实这个也是可以通过画内存四区图来看出的。
fun(&q);
//fun1(q);
printf("%d", *q);
return 0;
}
*/
//第五个测试
/*
typedef struct Node
{
int data;
struct Node *lchild;
struct Node *rchild;
}Node;
void fun(Node *node)
{
node->data = 50;
node->lchild = (Node*)malloc(sizeof(Node));
node->rchild = (Node*)malloc(sizeof(Node));
}
int main()
{
//这里例子我想要说明的就是野指针的问题。也就是说:对于node来说,他现在没有一个
//具体的指向,或者说指向的是NULL。那么你调用fun()函数的时候,就会导致程序去向
//地址0的位置写入50,然后在地址0后4个字节的位置写入一个malloc()函数分配的地址
//因为地址0是操作系统保护的位置,所以是不能被用户的程序写入数据的。
//Node *node = NULL;
Node *node = (Node*)malloc(sizeof(Node));
fun(node);
return 0;
}
*/
//我先介绍几个我自己的定义,有利于后面概念的理解:
//1.指针的附加值:因为有的指针是一个结构体的指针,例如Node *node。那么node->data就是
//指针node的附加值
//2.指针的原始值:这个就是指针的值,也可以说是指针的指向。int *p=&a;那么指针p的值
//就是&a
//前面说过,你想要通过函数改变指针的值,就要使用指针的指针。但是如果你想要改变的是
//指针的附加值,例如node->lchild,那么其实就可以通过指针Node *node的来改变。这个
//也是可以通过画内存四区图得出的。这个也是你在写一些树的代码的时候,你应该深有体会
//但是如果你想要通过指针的指针来改变也是可以的。下面我就使用这样的一个例子,同时解决
//上面的野指针的问题
//第六个测试
/*
typedef struct Node
{
int data;
struct Node *lchild;
struct Node *rchild;
}Node;
void fun(Node **node)
{
*node = (Node*)malloc(sizeof(Node));
(*node)->data = 50;
(*node)->lchild = (Node*)malloc(sizeof(Node));
(*node)->rchild = (Node*)malloc(sizeof(Node));
}
int main()
{
Node *node = NULL;
//fun()函数中使用了一个指针的指针来改变node->lchild和node->rchild。但是这个仅仅
//是这个函数的附加效果,主要的原因,就是为了给node赋值。因为我现在想要改变指针
//node的值,并且是通过函数来改变,所以仅仅只能使用指针的指针才能达到改变实参node
//的效果。这个也是可以通过画内存四区图弄清楚的。
fun(&node);
return 0;
}
*/
//测试点6主要就是为了验证我之前说的一些结论。因为每一次在编程的时候不可能就每一次还
//去画一个内存四区图。所以,就给出了如下结论,这里总结一下:
//1.你想要通过函数改变指针的值,就要使用指针的指针
//2.改变一个指针的值,但是这个指针是另外一个指针的附加值,那么可以仅仅使用一个指针
//就可以达到改变的效果了。