【ZZULI数据结构实验一】多项式的三则运算

news2024/11/15 20:09:07

【ZZULI数据结构实验一】多项式的四则运算

  • ♋ 结构设计
  • ♋ 方法声明
  • ♋ 方法实现
    • 🐇 定义一个多项式类型并初始化---CreateDataList
    • 🐇 增加节点---Getnewnode
    • 🐇 打印多项式类型的数据-- PrintPoly
    • 🐇 单链表的尾插--Listpush_back
    • 🐇 多项式相加--PolyAdd
    • 🐇 多项式相减-- PolySub
    • 🐇 多项式相乘--PolyMult
    • 🐇 销毁单链表--Destroy
  • ♋ 测试
  • 优化

📃博客主页: 小镇敲码人
🚀 欢迎关注:👍点赞 👂🏽留言 😍收藏
🌏 任尔江湖满血骨,我自踏雪寻梅香。 万千浮云遮碧月,独傲天下百坚强。 男儿应有龙腾志,盖世一意转洪荒。 莫使此生无痕度,终归人间一捧黄。🍎🍎🍎
❤️ 什么?你问我答案,少年你看,下一个十年又来了 💞 💞 💞

前言:本篇博客旨在个人学习,实现了多项式的加减乘运算,对代码的正确性不作100%的保证。

♋ 结构设计

这里我们使用带头单链表来存储多项式的数据(各项系数及其幂次),也可以用顺序表来存数据,但是这样头插不太方便,而且需要另外创建一个节点类型放一个项的系数和幂次。如果你对单链表还留有疑问,可以看看博主的这篇文章单链表详解
这个和下面的方法声明都放到头文件里。
在这里插入图片描述

typedef struct DataList
{
	int coe;//系数
	int power;//幂次
	struct DataList* next;
}List;

♋ 方法声明

List* CreateDataList();//输入数据并构造数据单链表的函数

List* PolyAdd(List* A,List* B);//实现多项式相加

List* PolySub(List* A,List* B);//实现多项式相减

List* PolyMult(List* A,List* B);//实现多项式相乘

List* Getnewnode(int coe_, int power_);//申请一个节点,并初始化

void PrintPoly(List* A);//打印多项式

void Listpush_back(List* C, int coe_,int power_);//尾插节点

void Destroy(List* A);//销毁节点

♋ 方法实现

方法实现放到.c文件里。

在这里插入图片描述

🐇 定义一个多项式类型并初始化—CreateDataList

初始化就是放数据的过程,这里直接走一个循环,然后申请空间就可以了,如果你对申请空间有疑问,请看博主这篇文章C语言动态内存管理,这里我们规定输入数据时,应该先输入幂次大的节点(先输入系数,再输入幂次),然后下一次节点链接我们直接头插就可以保证多项式类型的节点从左到右是按照幂次升序存储的(方便后序的四则运算),单链表的头插比尾插简单(尾插需要找尾)

这里当然你也可以乱输入,增加一个排序函数就可以(按照幂次排)。小小实验我们并不需要这么麻烦,直接输入让它有序就可以了(dog。

这里我们选择带头的单链表,是为了避免头插时没有数据的判空。

代码实现:

List* CreateDataList()
{
	int coe_ = 0, power_ = 0;//初始化两个临时变量,用于输入每个节点的数据
	printf("请依次按照幂次从大到小输入数据,先输入多项式的系数,后输入幂次:\n");//提示信息
	List* Head = Getnewnode(-1, -1);//设置空的头节点
	while(scanf("%d%d", &coe_, &power_) != EOF)
	{
	  List* newnode = Getnewnode(coe_, power_);
	  newnode->next = Head->next;
	  Head->next = newnode;
	  printf("请依次按照幂次从大到小输入数据,先输入多项式的系数,后输入幂次:\n");//提示信息,每次输入数据前都打印一次,这里会多打印一次无伤大雅
	} 
	return Head;//返回头节点
}

🐇 增加节点—Getnewnode

我们在很多地方都需要申请节点,而且要初始化,为了不造成代码冗余,我们把其单独作为一个函数写出来,用的时候直接调用就好了。

代码实现:

List* Getnewnode(int coe_, int power_)
{
	List* newnode = (List*)malloc(sizeof(List));//在堆上申请空间
	if (newnode == NULL)//如果申请失败
	{
		printf("malloc Failed\n");
		exit(-1);
	}
	//初始化新节点
	newnode->coe = coe_;
	newnode->power = power_;
	newnode->next = NULL;//注意next要置空,否则会造成野指针的问题
	return newnode;//返回新节点
}

🐇 打印多项式类型的数据-- PrintPoly

这个函数就是单纯的打印,为了方便我们后序打印多项式类型看相加和相乘、以及相减的结果,当然你也可以通过调试查看。

代码实现:

void PrintPoly(List* A)//打印多项式
{
	assert(A);//防止A为空,我们不能对空解引用,assert函数相当于暴力检查
	List* cur = A->next;//从头节点的下一个节点开始遍历,因为头节点不存数据
	if (cur == NULL)//cur为空
		printf("多项式为空\n");
	while (cur != NULL)//cur不为空
	{
		
		if (cur->coe > 0 && cur != A->next)
			printf("+%d*(x^%d)", cur->coe, cur->power);
		else
			printf("%d*(x^%d)", cur->coe, cur->power);
		cur = cur->next;
	}
	printf("\n");
}

🐇 单链表的尾插–Listpush_back

在多项式相加的函数里面我们会用到单链表的尾插,如果你对其原理不太熟悉,请自行翻阅博主之前的博客。

代码实现:

void Listpush_back(List* C, int coe_, int power_)//尾插数据
{
	assert(C);//C不为空

	List* newnode = Getnewnode(coe_, power_);//申请新节点并初始化
	List* tail = C;
	while (tail->next)//找尾节点
	{
		tail = tail->next;
	}
	tail->next = newnode;//把新节点链接到尾节点的后面
}

🐇 多项式相加–PolyAdd

我们的多项式相加的思路类似双指针,O(N)时间复杂度内完成。

下面我们画图来分析一下这个过程:

在这里插入图片描述

  • 注意:这里为什么是尾插到C中呢?因为尾插才能保证C中数据是按幂次升序的,因为A和B中的数据都是按幂次升序排列的,我们为什么不把数据放到A和B中的其中一个呢,因为这样会改变A和B的内容,后面我们可能会对A、B做其它操作。

代码实现:

List* PolyAdd(List* A, List* B)
{
	assert(A && B);//断言,防止A或者B为空指针

	List* C = Getnewnode(-1, -1);//创建新的链表C,我们不希望改变链表A和B的值,所以把它们相加的结果存入C中
	List* curA = A->next;
	List* curB = B->next;
	while (curA && curB)//A和B的当前位置都不能为空
	{
		if (curA->power == curB->power)//如果当前幂次相等,A和B的系数相加,幂次不变,尾插到C中
		{
			int new_coe = curA->coe + curB->coe;
			if (new_coe != 0)
				Listpush_back(C, new_coe, curA->power);
			curA = curA->next;
			curB = curB->next;
		}
		else if (curA->power < curB->power)//如果B大,尾插curA
		{
			Listpush_back(C, curA->coe, curA->power);
			curA = curA->next;
		}
		else//否则尾插curB
		{
			Listpush_back(C, curB->coe, curB->power);
			curB = curB->next;
		}
	}
	//如果两个链表还有一个剩余,把剩下的数据尾插到C中
	while (curA)
	{
		Listpush_back(C, curA->coe, curA->power);
		curA = curA->next;
	}
	while (curB)
	{
		Listpush_back(C,curB->coe, curB->power);
		curB = curB->next;
	}
	return C;//返回相加的结果链表的头节点指针
}

🐇 多项式相减-- PolySub

多项式相减的大致思路都和多项式相加是一样的,有一个地方要注意,因为是A-B,当B中式子多时,A中对应项的系数就是0,要给B的系数加上负号。

代码实现:

// 定义PolySub函数,接受两个多项式链表A和B作为参数,返回相减后的多项式链表C  
List* PolySub(List* A, List* B)  
{  
    // 断言A和B都不为空,确保传入的多项式链表是有效的  
    assert(A && B);  
  
    // 创建一个新的链表C,并初始化其头节点(这里用-1作为占位符,实际使用中可能需要其他方式初始化)  
    List* C = Getnewnode(-1, -1);  
  
    // 初始化两个指向A和B链表中第一个实际节点的指针curA和curB  
    List* curA = A->next;  
    List* curB = B->next;  
  
    // 当curA和curB都不为空时,循环进行以下操作  
    while (curA && curB)  
    {  
        // 如果curA和curB指向的项的指数相同  
        if (curA->power == curB->power)  
        {  
            // 计算两个相同指数项的系数之差  
            int new_coe = curA->coe - curB->coe;  
  
            // 如果系数之差不为0,则将新的项(系数和指数)添加到C链表中  
            if (new_coe != 0)  
                Listpush_back(C, new_coe, curA->power);  
  
            // 移动curA和curB到下一个节点  
            curA = curA->next;  
            curB = curB->next;  
        }  
        // 如果curA指向的项的指数小于curB指向的项的指数  
        else if (curA->power < curB->power)  
        {  
            // 将curA指向的项(系数和指数)添加到C链表中  
            Listpush_back(C, curA->coe, curA->power);  
  
            // 移动curA到下一个节点  
            curA = curA->next;  
        }  
        // 否则(即curA指向的项的指数大于curB指向的项的指数)  
        else  
        {  
            // 将curB指向的项的相反数(系数取反,指数不变)添加到C链表中,实现减法  
            Listpush_back(C, -curB->coe, curB->power);  
  
            // 移动curB到下一个节点  
            curB = curB->next;  
        }  
    }  
  
    // 如果curA还有剩余节点(即A的某些项在B中没有对应项)  
    while (curA)  
    {  
        // 将这些项(系数和指数)添加到C链表中  
        Listpush_back(C, curA->coe, curA->power);  
  
        // 移动curA到下一个节点  
        curA = curA->next;  
    }  
  
    // 如果curB还有剩余节点(即B的某些项在A中没有对应项)  
    while (curB)  
    {  
        // 将这些项的相反数(系数取反,指数不变)添加到C链表中,实现减法  
        Listpush_back(C, -curB->coe, curB->power);  
  
        // 移动curB到下一个节点  
        curB = curB->next;  
    }  
  
    // 返回相减后的多项式链表C  
    return C;  
}

🐇 多项式相乘–PolyMult

相乘的思路是复用多项式相加的函数,先让B链表中的第一个项和A中各个项相乘(系数相乘,幂次相加),然后得到链表C,然后移动B继续和A中的各个相相乘,并执行多项式相加,最终得到结果。

代码实现:

// 定义PolyMult函数,接受两个多项式链表A和B作为参数,返回相乘后的多项式链表C  
List* PolyMult(List* A, List* B)  
{  
    // 断言A和B都不为空,确保传入的多项式链表是有效的  
    assert(A && B);  
  
    // 创建一个新的链表C,并初始化其头节点(这里用-1作为占位符)  
    List* C = Getnewnode(-1, -1);  
  
    // 初始化两个指针curA和curB,分别指向A和B链表中第一个实际节点  
    List* curA = A->next;  
    List* curB = B->next;  
  
    // 遍历curA指向的A链表中的每个项  
    while (curA)  
    {  
        // 计算当前curA指向的项与B链表中第一个项(curB指向的项)的乘积的系数和指数  
        int new_coe = (curA->coe) * (curB->coe);  
        int new_power = curA->power + curB->power;  
  
        // 将新的项(系数和指数)添加到C链表中  
        Listpush_back(C, new_coe, new_power);  
  
        // 移动curA到下一个节点  
        curA = curA->next;  
    }  
  
    // 初始化ans为NULL,用于存储最终的乘法结果  
    List* ans = NULL;  
  
    // 遍历curB指向的B链表中的每个项(从第二个项开始,因为第一个项已经在上面的循环中处理过了)  
    while (curB->next)  
    {  
        // 移动curB到下一个节点  
        curB = curB->next;  
  
        // 创建一个新的链表C1,用于存储当前curB指向的项与A链表中所有项的乘积结果  
        List* C1 = Getnewnode(-1, -1);  
  
        // 初始化curA,重新指向A链表中第一个实际节点  
        List* curA = A->next;  
  
        // 遍历curA指向的A链表中的每个项  
        while (curA)  
        {  
            // 计算当前curA指向的项与当前curB指向的项的乘积的系数和指数  
            int new_coe = (curA->coe) * (curB->coe);  
            int new_power = curA->power + curB->power;  
  
            // 将新的项(系数和指数)添加到C1链表中  
            Listpush_back(C1, new_coe, new_power);  
  
            // 移动curA到下一个节点  
            curA = curA->next;  
        }  
  
        // 将C链表和C1链表相加,得到当前curB指向的项与A链表相乘的结果,并更新ans  
        ans = PolyAdd(C, C1);  
  
        // 销毁C1链表,释放其占用的内存  
        Destroy(C1);  
  
        // 销毁C链表,释放其占用的内存(C现在保存的是上一轮的结果,我们不再需要它)  
        Destroy(C);  
  
        // 将ans赋值给C,准备进行下一轮的乘法运算  
        C = ans;  
    }  
  
    // 返回最终的乘法结果链表C  
    return C;  
}

这里由于我们的C1、和C链表每一次循环都会变成新的链表,我们要及时把旧的链表空间释放,防止内存泄漏的出现。

🐇 销毁单链表–Destroy

这里在多项式相乘函数里,会出现内存泄漏,我们需要及时回收空间,防止出现这种情况。

代码实现:

void Destroy(List* A)//销毁链表
{
	assert(A);

	List* cur = A;
	while (cur)
	{
		List* cur_next = cur->next;//保存下一个节点的地址
		free(cur);//释放当前节点的空间
		cur = cur_next;//指针指向下一个节点
	}
}

♋ 测试

测试函数我们放到了main.c函数里,主要测试函数的各种功能是否和我们的预期一样,当然由于测试的数据有限,如有bug,欢迎指出。

#include"polynomial.h"

void Test()
{
	List* A = CreateDataList();
	List* B = CreateDataList();
	List* AAddB = PolyAdd(A, B);
	List* ASubB = PolySub(A, B);
	List* AMultB = PolyMult(A, B);
	printf("多项式A: ");
	PrintPoly(A);
	printf("多项式B: ");
	PrintPoly(B);
	printf("多项式A+B: ");
	PrintPoly(AAddB);
	printf("多项式A-B: ");
	PrintPoly(ASubB);
	printf("多项式A*B: ");
	PrintPoly(AMultB);
}
int main()
{
	Test();
	return 0;
}

这里我们A输入:3 3 2 2 1 1
B输入: 4 4 3 3 2 2 1 1

运行结果:
在这里插入图片描述

和我们预期的结果一致。

这里我们A输入:1 5 1 3 1 1
B输入: 16 1 4 1 2

运行结果:

在这里插入图片描述
与预期结果一致。

优化

我们给我们的程序增加了一个计数排序,但是由于单链表不能下标访问,所以性能上会差一点,这里还是建议使用归并排序,因为归并排序对下标访问没有要求。

使用计数排序需要先计算单链表的长度。

// 定义一个函数,接受一个链表指针A作为参数,并返回链表的长度  
int List_Length(List* A)
{
	// 断言A不为空,如果A为空则程序会在这里终止,这通常用于调试时确保传入的链表是有效的  
	assert(A);

	// 初始化一个指针cur,指向链表A的第一个实际节点(即头节点之后的节点)  
	List* cur = A->next;

	// 初始化一个变量length,用于记录链表的长度,初始值为0  
	int length = 0;

	// 当cur不为空时,即还有节点未遍历完时,继续循环  
	while (cur)
	{
		// 每次循环都将length加1,表示遍历到了一个节点  
		length++;

		// 将cur移动到下一个节点,继续遍历  
		cur = cur->next;
	}

	// 返回计算得到的链表长度  
	return length;
}

对计数排序不太熟悉的小伙伴,可以看一下博主这篇博客。
这里我们是对有两个数据域的链表进行排序,类似对结构体进行排序,有一点不同:
代码实现:

void SortList(List* A)//按照幂次升序排序单链表,计数排序
{
	CountSort(A,List_Length(A));
}

void CountSort(List* A, int n) // 链表的计数排序  
{
	// 初始化最大和最小值为整型最小值和最大值  
	int max_ = INT_MIN;
	int min_ = INT_MAX;
	List* cur = A->next; // 初始化cur指向链表A的第一个实际节点  

	// 遍历链表A,找到power的最大值和最小值  
	while (cur)
	{
		if (cur->power > max_)
			max_ = cur->power;
		if (cur->power < min_)
			min_ = cur->power;
		cur = cur->next;
	}

	// 计算排序范围,即最大值和最小值之间的差值加1  
	int range = max_ - min_ + 1;

	// 分配一个整数数组,用于存储每个值的计数  
	int* count = (int*)malloc(sizeof(int) * range);
	memset(count, 0, sizeof(int) * range); // 初始化count数组为0  

	// 检查内存分配是否成功  
	if (count == NULL)
	{
		printf("count malloc failed\n");
		exit(-1);
	}

	// 再次遍历链表A,计算每个power的计数  
	cur = A->next;
	while (cur)
	{
		count[cur->power - min_]++;
		cur = cur->next;
	}

	// 创建一个新的链表C,用于存放排序后的结果  
	List* C = Getnewnode(-1, -1);
	int length = n; // 链表A的长度  

	// 初始化链表C的节点,创建一个长度为n的空链表  
	while (length--)
	{
		List* newnode = Getnewnode(-1, -1);
		List* next = C->next;
		newnode->next = next;
		C->next = newnode;
	}

	// 检查链表C的节点创建是否成功  
	if (C == NULL)
	{
		printf("C malloc failed\n");
		exit(-1);
	}

	// 分配一个索引数组,用于记录每个值在排序后的链表中的起始位置  
	int* idx = (int*)malloc(sizeof(int) * (range + 1));
	memset(idx, 0, sizeof(int) * (range + 1));

	// 检查内存分配是否成功  
	if (idx == NULL)
	{
		printf("idx malloc Failed\n");
		exit(-1);
	}

	// 计算每个值的累积计数,即该值在排序后的链表中的起始位置  
	for (int i = 1; i <= range; ++i)
	{
		idx[i] = idx[i - 1] + count[i - 1];
	}

	// 遍历链表A,并根据计数和索引数组将元素插入到链表C中  
	cur = A->next;
	List* cur_ = NULL;
	while (cur)
	{
		cur_ = C->next;
		// 移动cur_到cur的power对应的插入位置  
		while (idx[cur->power - min_]--)
		{
			cur_ = cur_->next;
		}
		// 将cur的值复制到cur_的位置  
		cur_->coe = cur->coe;
		cur_->power = cur->power;
		// 恢复索引数组  
		idx[cur->power - min_]++;
		cur = cur->next;
	}

	// 将排序后的链表C的值复制回原链表A  
	cur = A->next;
	cur_ = C->next;
	while (cur && cur_)
	{
		cur->coe = cur_->coe;
		cur->power = cur_->power;
		cur = cur->next;
		cur_ = cur_->next;
	}

	// 销毁链表C  
	Destroy(C);
}

排序函数写出来后,我们在创建链表的函数后面增加一个排序调用就好了:

List* CreateDataList()
{
	int coe_ = 0, power_ = 0;//初始化两个临时变量,用于输入每个节点的数据
	printf("先输入多项式的系数,后输入幂次:\n");//提示信息
	List* Head = Getnewnode(-1, -1);//设置空的头节点
	while(scanf("%d%d", &coe_, &power_) != EOF)
	{
	  List* newnode = Getnewnode(coe_, power_);
	  newnode->next = Head->next;
	  Head->next = newnode;
	  printf("先输入多项式的系数,后输入幂次:\n");//提示信息,每次输入数据前都打印一次,这里会多打印一次无伤大雅
	} 
	SortList(Head);//按power升序排序链表
	return Head;
}

运行效果:

在这里插入图片描述

下面我们对计数排序排结构体的一些知识点做一下分析:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1545449.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Bert基础(七)--Bert实战之理解Bert模型结构

在篇我们将详细学习如何使用预训练的BERT模型。首先&#xff0c;我们将了解谷歌对外公开的预训练的BERT模型的不同配置。然后&#xff0c;我们将学习如何使用预训练的BERT模型作为特征提取器。此外&#xff0c;我们还将探究Hugging Face的Transformers库&#xff0c;学习如何使…

【机器学习】引领未来的力量:技术革新与应用探索

&#x1f9d1; 作者简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟。提供嵌入式方向的学习指导、简历面…

nodejs中使用@maxmind/geoip2-node 查询地理位置信息

介绍 maxmind/geoip2-node 是一个Node.js模块&#xff0c;用于与MaxMind的GeoIP2数据库进行交互&#xff0c;从而获取IP地址的地理位置信息。MaxMind的GeoIP2数据库包含了全球范围内的IP地址和对应的地理位置信息&#xff0c;如国家、城市、经纬度等。使用maxmind/geoip2-node…

利用sin/cos原理驱动步进电机

利用sin/cos原理控制步进电机转动 前言什么是步进电机驱动器细分控制电机内部结构图片步进电机驱动原理&#xff08;重要&#xff09;步进电机参数&#xff11;、步距角&#xff1a;收到一个脉冲转动的角度&#xff12;、细分数 &#xff1a;&#xff11;&#xff0f;&#xf…

M1 mac安装 Parallels Desktop 18 激活

M1 mac安装 Parallels Desktop 18 激活 下载安装Parallels Desktop 18.1.1 (53328) 激活1. 拷贝prl_disp_service2. 在终端打开Crack所在位置3. 输入命令&#xff0c;激活成功 下载 安装包和激活文件下载地址 链接: https://pan.baidu.com/s/1EjT7xeEDcntIIoOvvhBDfg?pwd9pue …

Kubernetes Pod深度解析:构建可靠微服务的秘密武器(上)

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Kubernetes航线图&#xff1a;从船长到K8s掌舵者》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、Kubernetes概述 2、Pod概述 二、Po…

AI老人跌倒监测报警摄像机

AI老人跌倒监测报警摄像机是一种基于人工智能技术的智能监控设备&#xff0c;专门用于监测老年人的跌倒情况并提供实时报警功能&#xff0c;以及时处理紧急情况&#xff0c;保障老人安全。这种摄像机利用先进的AI算法和深度学习技术&#xff0c;能够实时监测老人的行为&#xf…

时序信号高低频分析——经验模态分解EMD

时序信号高低频分析——经验模态分解EMD 介绍 经验模态分解&#xff08;Empirical Mode Decomposition&#xff0c;EMD&#xff09;是一种用于时序信号分解的自适应方法&#xff0c;旨在将原始信号分解为多个固有模态函数&#xff08;Intrinsic Mode Functions&#xff0c;IM…

【c++】类和对象(二)this指针

&#x1f525;个人主页&#xff1a;Quitecoder &#x1f525;专栏&#xff1a;c笔记仓 朋友们大家好&#xff0c;本节内容来到类和对象第二篇&#xff0c;本篇文章会带领大家了解this指针 目录 1.this指针1.1this指针的引出1.2this指针的特性1.3思考题1.4C语言和C实现Stack的对…

RWTH-PHOENIX Weather数据集模型说明和下载

RWTH-PHOENIX Weather 2014 T数据集说明: 德国公共电视台PHOENIX在三年内(2009 年至 2011 年) 录制了配有手语翻译的每日新闻和天气预报节目,并使用注释符号转录了 386 个版本的天气预报。 此外,我们使用自动语音识别和手动清理来转录原始德语语音。因此,该语料库允许训练…

近线数仓优化改造

近线数仓优化改造 1. 背景2. 优化3. 改造3.1. 重构3.2. 优化 1. 背景 大概就是有那么一个数仓&#xff0c;然后简略结构如下&#xff1a; #mermaid-svg-PVoUzuQhj2BK7Qge {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid…

【C语言】动态内存管理及其常见错误

文章目录 1、前言&#xff1a;为什么要有动态内存分布2、三种动态内存的创建方式及其释放2.1 malloc2.2 calloc2.3 ralloc2.4 free 3、常⻅的动态内存的错误3.1 对NULL指针的解引用操作3.2 对动态开辟空间的越界访问3.3 对非动态开辟内存使用free释放3.4 使⽤free释放⼀块动态开…

C++动态内存管理:new/delete与malloc/free的对比

在C中&#xff0c;动态内存管理是一个至关重要的概念。它允许我们在程序运行时根据需要动态地分配和释放内存&#xff0c;为对象创建和销毁提供了灵活性。在C中&#xff0c;我们通常会用到两对工具&#xff1a;new/delete 和 malloc/free。虽然它们都能够完成类似的任务&#x…

2月线上速溶咖啡行业数据分析:“减肥咖啡”引领电商新潮流

随着生活节奏的加快&#xff0c;速溶咖啡因其便捷性受到广大消费者的青睐。不过&#xff0c;在如今世界咖啡市场激烈竞争的情况下&#xff0c;中国速溶咖啡市场也受到影响&#xff0c;增速有所放缓。 根据鲸参谋电商数据平台显示&#xff0c;2月线上综合电商&#xff08;京东天…

003_vector_conventions_in_MATLA中的向量约定

MATLAB中的向量约定 1. 前言 MATLAB是一种用于数值计算和数据可视化的高级编程语言。以前&#xff0c;都不好意思说它是编程语言&#xff0c;它实际上只是一个脚本工具&#xff0c;配套了一堆工具箱。比如Simulink&#xff0c;可以开展非常复杂的仿真&#xff0c;还能编译到实…

海外媒体发稿:出口贸易媒体发稿7个秘籍揭晓-华媒舍

出口贸易是许多国家经济增长的关键驱动力之一。不仅可以加快国家的发展步伐&#xff0c;还能为企业创造巨大的商机。如何能够在出口贸易中取得成功&#xff0c;如何能够引起媒体的关注&#xff0c;成为企业广告和宣传的焦点&#xff0c;是许多出口企业面临的挑战。本文将揭示出…

【LeetCode热题100】108. 将有序数组转换为二叉搜索树(二叉树)

一.题目要求 给你一个整数数组 nums &#xff0c;其中元素已经按 升序 排列&#xff0c;请你将其转换为一棵 平衡二叉搜索树。 二.题目难度 简单 三.输入样例 示例 1&#xff1a; 输入&#xff1a;nums [-10,-3,0,5,9] 输出&#xff1a;[0,-3,9,-10,null,5] 解释&#x…

【Java程序设计】【C00367】基于(JavaWeb)Springboot的粮仓管理系统(有论文)

TOC 博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;已经做了六年的毕业设计程序开发&#xff0c;开发过上千套毕业设计程序&#xff0c;博客中有上百套程序可供参考&#xff0c;欢迎共同交流学习。 项目简介 项目获取 &#x1f345;文末点击卡片…

JVM——字符串常量池

在Java程序中String类的使用几乎无处不在&#xff0c;String类代表字符串&#xff0c;字符串对象可以说是Java程序中使用最多的对象了。首先&#xff0c;在Java中创建大量对象是非常耗费时间的。其次&#xff0c;在程序中又经常使用相同的字符串对象&#xff0c;如果每次都去重…

企业计算机服务器中了locked勒索病毒怎么处理?Locked勒索病毒解密流程

在网络技术不断发展应用过程中&#xff0c;越来越多的企业利用网络开展各项工作业务&#xff0c;网络为企业的生产运营提供了极大便利&#xff0c;但网络威胁手段也在不断增加&#xff0c;为企业的数据安全带来严重威胁。近日&#xff0c;新一波的网络勒索病毒比较猖獗&#xf…