结构体指针在函数中改变,但是函数运行完毕后回到主函数发现他没变(改变的是形参结构体指针)

如果你用的是结构体指针,是否遇到了在函数中改变他,但是函数运行完毕后回到主函数发现他没变的问题?本文给你讲明白

函数没有改变结构体的值?

void bbb(struct node *p)
{
	
}

对p操作了半天,回主函数一看没反应?先别急。

先举个很简单的例子,我们都知道,在函数中无论如何你改变形参,主函数里的实参都没反应,下边的a就是一个例子。这个函数调用之后,主函数中不会有反应。我们就会用指向他的指针,也就是他的地址来进行传参,这样就可以直接修改地址的值,相当于从娘胎里就给你变形。

void aaa(int a)
{
	a = 9999;
}

所以我们一般这么写

int main()
{
	int b = 5;
	aaa(&b);
}
void aaa(int *a)
{
	*a = 9999;
}

但是我发现很多人在结构体指针的时候就不明白了,而且今天工作中也遇到了这个问题。就是

typedef struct Node
{
	ElementType data;
	struct Node* next;
	struct Node* prior;
} LNode, * LinkList;

printfStructData(headNode, structLength);//输出链表每个元素
deleteStructElement(headNode, 2);//删除某个元素
printfStructData(headNode, structLength);//输出链表每个元素

代码在最下边,这里截取一部分说
我这里的headNode按理说在每次函数的调用里都对他进行了遍历,那为甚么函数退出来后他没变呢?
因为我传进去的是

void printfStructData(LinkList pNode, uint nowStructLength); //打印链表数据

是一个结构体指针
这个结构体指针相当于形参,也就是相当于上文的void aaa(int a) { a = 9999; }这句中的a,我们怎么操作a,都没反应。有人要问了,那我是指针呀,上面说的void aaa(int *a)这句就是一个指针,可以改变实参。这里其实是搞混了。
在上边中我要改变的是a,是一个变量。所以我要对他的地址进行传递,因为他的地址只有一个。
在下边这个结构体指针中,我要改变的是headNode结构体指针。把这个指针看作变量,是不是要找这个变量的地址?那指针的地址是什么,是不是指向这个指针的指针?所以我们如果要改变这个指针的话,就是要找到指向这个指针的指针,然后对这个地址的值进行操作,这样子操作的才是结构体指针。所以我们经常能见到void aaa(struct node **a)这样的操作,这样就是操作结构体指针。

在这里插入图片描述
在这里插入图片描述
我们可以看到,刚进函数的时候,形参pNode的值和实参headNode的值是一样的(注意,是值,不是地址,想看地址的话要写成&pNode)
在这里插入图片描述
执行完这一句之后,我们来看看监控

在这里插入图片描述
在这里插入图片描述

这个形参的地址已经变了,实参没反应,不懂。这是因为中间这栏是他们的值!!!

想看看他们的地址嘛(●ˇ∀ˇ●)
在这里插入图片描述
这样子的哦,可以明显看到,他们地址根本不在一起,pNode是形参,用完就销毁哦!这样子就知道了吧,要操作&headNode才行哦!其实他也很普通。
所以想改变他的话,就用

void bbb(struct node **p)
{
	
}

吧!
visio studio真好用!都给我用!vsAssist真好用!

不过平心而论,在实际中应用时(如下边的代码),不改变头节点这个结构体指针其实是好事,这样我每次都相当于从头节点开始找,不用管他现在的位置在哪,函数中操作完了就完了,不影响我主函数。

实现的是一个双向链表。标准的全套数据结构在内网,拷贝不出来,变量名比较规范,这里是外边我懒得重新写了,下边的已经很详细能看懂了。

没头文件,直接全复制进去就能运行

#include "stdio.h"
#include "stdlib.h"

//宏定义
#define ElementType int
#define uint unsigned int

ElementType pa[6] = { 1, 2, 2, 3, 5, 7 };
ElementType pb[5] = { 2, 3, 4, 6, 8 };
ElementType* pc;
uint MaxLength1 = 6;
uint MaxLength2 = 5;
uint structLength = 0;

//结构体定义
typedef struct Node
{
	ElementType data;
	struct Node* next;
	struct Node* prior;
} LNode, * LinkList;

//标记作用的结构体定义
LinkList presentNode; //当前指向的结构体
LinkList headNode;    //头结点
LinkList finalNode;   //指向最后一个结构体

//运行是否成功标志位定义
uint FLAG;

//函数声明
//一级函数
void structInit(LNode* pNode);                               //结构体初始化
void printfStructData(LinkList pNode, uint nowStructLength); //打印链表数据
//增:
void structInsert(LNode* pNode, ElementType insertLocation, uint insertData); //在指定位置插入
void structInsertArray(LinkList pNode, ElementType* pData, uint dataLength);  //在末尾插入数组
//删
void deleteStructElement(LinkList pNode, uint deleteLocation);
//改
void changeStructElement(LinkList pNode, uint changeLocation, ElementType structData);
//查
void findStructElement(LinkList pNode, uint findLocation);
//二级函数(不会直接调用,一般是被一级函数用)
void checkNodeInsertLocation(uint flag); //检查结构体插入位置是否合理
void checkNodeCreat(LNode* Node);        //检查结构体是否创建成功
void checkError(uint flag);              //问题处理
void checkNodeIsEmpty(LNode* Node);      //检查链表是否为空链表

void main()
{
	LNode* Node1 = (LNode*)(malloc(sizeof(LNode)));
	checkNodeCreat(Node1);
	structInit(Node1);
	structInsertArray(headNode, pa, MaxLength1);
	printfStructData(headNode, structLength);
	deleteStructElement(headNode, 2);
	printfStructData(headNode, structLength);
	findStructElement(headNode, 3);
	printfStructData(headNode, structLength);
	changeStructElement(headNode, 3, 99);
	printfStructData(headNode, structLength);
	while (1)
		;
}

/*
功能:初始化新建的链表
parameter:新建的链表的头结点
*/
void structInit(LNode* pNode)
{
	pNode->data = 0;
	pNode->prior = pNode;
	pNode->next = pNode;
	headNode = pNode;
	finalNode = pNode;
	presentNode = pNode;
}

/*
输出链表的每一个数据
parameter:
pNode:头结点
nowStructLength:当前链表长度
*/
void printfStructData(LinkList pNode, uint nowStructLength)
{
	uint flag = 0;
	while (nowStructLength != 0)
	{
		nowStructLength--;
		pNode = pNode->next;
		printf("%d", pNode->data);
		if (nowStructLength != 0)
		{
			printf("->");
		}
	}
	printf("\n");
}

/*
错误检索
功能:函数返回值检测,检测函数是否运行成功,如果失败,则报出对应的错误
parameter: 其他函数的返回值
*/
void checkError(uint flag)
{
	if (flag == 401)
		printf("\nERROR:401. Insert location is wrong. Can not be 0 or greater than structLength.\n");
	else if (flag == 501)
		printf("\nERROR:501. Creat struct is defated\n.");
	else if (flag == 502)
		printf("\nError:502. List is empty.\n");
}

/*
检查结构体是否创建成功
*/
void checkNodeCreat(LNode* Node)
{
	if (Node == NULL)
	{
		checkError(501);
	}
}

/*
检查链表是否为空
*/
void checkNodeIsEmpty(LNode* Node)
{
	if (Node->next == Node && Node->prior == Node)
	{
		checkError(502);
	}
}
/*
检查插入位置是否越界
parameter:
insertLocation:插入的位置
*/
void checkNodeInsertLocation(uint insertLocation)
{
	if (insertLocation < 1 || insertLocation > structLength + 1) //如果是空结构体,插入第一个,插入位置等于1,structLength+1=1,刚好不大于
		checkError(401);
}

/*
功能:给双向链表的指定位置插入数据
parameter:
pNpde:头结点
insertLocation:插入位置
insertData:插入数据值
eg:
插入位置:2,插入数据:6
插入前:头结点 1 2 3 4
插入后:头结点 1 6 2 3 4
*/
void structInsert(LinkList pNode, ElementType insertLocation, uint insertData)
{
	int i = 0;
	LNode* newNode = (LNode*)(malloc(sizeof(LNode)));
	checkNodeCreat(newNode);
	checkNodeInsertLocation(insertLocation);
	for (i = 0; i < insertLocation; i++)
	{
		pNode = pNode->next;
	}
	newNode->data = insertData;
	pNode->prior->next = newNode;
	newNode->prior = pNode->prior;
	newNode->next = pNode;
	pNode->prior = newNode;

	structLength++;
}

/*
功能:在结构体末尾连续插入一串数组。主要是用来结构体初始化,给刚创建的空链表赋一些值
parameter:
pNpde:要插入的链表的头结点
pData:传入的数组
dataLength:传入的数组的长度
*/
void structInsertArray(LinkList pNode, ElementType* pData, uint dataLength)
{
	uint flag;

	for (flag = 0; flag < dataLength; flag++)
	{
		structInsert(pNode, structLength + 1, *pData++);
	}
}

/*
功能:给双向链表的指定位置删除数据
parameter:
pNpde:头结点
insertLocation:删除位置
eg:
删除位置:2
插入前:头结点 1 2 3 4
插入后:头结点 1 3 4
*/
void
deleteStructElement(LinkList pNode, uint deleteLocation)
{
	int i = 0;
	checkNodeCreat(pNode);
	checkNodeInsertLocation(deleteLocation);
	for (i = 0; i < deleteLocation; i++)
	{
		pNode = pNode->next;
	}
	printf("要删除的结点值为:%d\n", pNode->data);
	pNode->prior->next = pNode->next;
	pNode->next->prior = pNode->prior;
	free(pNode);

	structLength--;
}

/*
查找某一个结点的值
*/
void findStructElement(LinkList pNode, uint findLocation)
{
	int i = 0;
	checkNodeCreat(pNode);
	checkNodeInsertLocation(findLocation);
	for (i = 0; i < findLocation; i++)
	{
		pNode = pNode->next;
	}
	printf("要查找的元素值为%d\n", pNode->data);
}

void changeStructElement(LinkList pNode, uint changeLocation, ElementType structData)
{
	int i = 0;
	checkNodeCreat(pNode);
	checkNodeInsertLocation(changeLocation);
	for (i = 0; i < changeLocation; i++)
	{
		pNode = pNode->next;
	}
	pNode->data = structData;
	printf("删除的元素为%d\n", pNode->data);
}
  • 13
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值