⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 运算器.c

📁 加减乘运算器,绝对完整,是初学者必不可少的编程内容
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct DuLNode{//双向循环链表的结点
	int data;
	struct DuLNode *prior,*next;
}DuLNode,*PDuLNode;
typedef struct{//链表的头结点
	PDuLNode head,ge;//head指向链表的第一个结点,ge指向数据的个位数所在结点
	int n1,n2,trag;//n1是数据的整数位,n2是其小数位,trag表示数据的正负,1时为正,-1时为负
}DuLinkList,*PDuLinkList;

PDuLinkList Inicreat(char *fname)
//输入函数,当fname不为空是从文件fname输入,为空是从键盘输入
{
	int t=1,*n;//t为控制变量,控制从文件读入还是从键盘读入,初始值为1,即默认从文件读入,n为输入数据整数位或小数位累加器
	char c;//暂存每次读入字符
	FILE *fp;
	PDuLinkList num;//输入的数据储存在num链表中
	PDuLNode q,p;
	if(strcmp(fname,"\0")!=0) 
		while((fp=fopen(fname,"r"))==NULL){printf("\t输入文件错误,请重新输入:");scanf("%s",fname);} 
	else t=0;//当fname为空时,t=0,此后从键盘读入数据,否则从文件读入
	num=(PDuLinkList)malloc(sizeof(DuLinkList));//以下为num及其头结点申请空间,并且初始化,构造储存结构形成双向循环链表
	q=(PDuLNode)malloc(sizeof(DuLNode));
	num->ge=NULL;num->head=q;num->n1=0;num->n2=0;num->trag=0;n=&num->n1;
	q->data=0;q->next=q;q->prior=q;
	if(t==1) c=fgetc(fp); else c=getchar();//当控制变量t=1时从文件读入,否则从键盘读入,以下雷同
	if(c=='-') {num->trag=-1;if(t==1) c=fgetc(fp); else c=getchar();}//当第一个字符为'-'是,表示此数为负,trag赋值为-1,并继续读下一个符
	else num->trag=1;                                                //否则trag=1
	while(c!='\n'){//当c不为'\n'时循环读入字符并储存
		if(c>47&&c<58){//当c为数字时,转化并储存
			q->data=c-48;
			(*n)++;//整数或小数位加1,初始n指向整数位数,
			p=(PDuLNode)malloc(sizeof(DuLNode));
			p->next=q->next;q->next->prior=p;p->prior=q;q->next=p;
			q=q->next;}
		if(c=='.'){          //当读入小数点时
			num->ge=q->prior;//个位指针指向前一个存入的数据
			n=&num->n2;}     //n变为指向小数位个数
        if(t==1) if(feof(fp)) break;//当文件结尾时,读入数据完成,跳出循环
		if(t==1) c=fgetc(fp); else c=getchar();//读入下一个字符
	}
	if(!num->ge) num->ge=q->prior;//当读入的数据为整数时,个位指针指向最后一个读入的数字
	q=q->prior;q->next=q->next->next;q->next->prior=q;free(p);//删除最后申请的那个空结点,并释放内存空间
	return  num;//返回头结点地址	
}

void print(PDuLinkList p,char *fname)
//输出函数,当fname不为空是输出到文件fname,为空是从输出到屏幕
{
	int t=1;//t的用处同Inicreat函数
	PDuLNode q;
	FILE *fp;
	if(strcmp(fname,"\0")!=0)
		while((fp=fopen(fname,"w"))==NULL){printf("\t输出文件错误,请重新输入:");scanf("%s",fname);}  
	else t=0;//同Inicreat函数
	if (p->trag==-1) if(t==1) fprintf(fp,"-"); else printf("-");//当trag为-1时先输也出“-”
	q=p->head;
	if(t==1) fprintf(fp,"%d",q->data);else  printf("%d",q->data);
	q=q->next;
	while (q!=p->head) 
	{
		if(q->prior==p->ge) if(t==1) fprintf(fp,"."); else printf(".");//当输出的前一个是个位时输出小数点
		if(t==1) fprintf(fp,"%d",q->data);else  printf("%d",q->data);
		q=q->next;
	}
	if(t==1) {fprintf(fp,"\n");fclose(fp);}else printf("\n");
}

int compare(PDuLinkList a,PDuLinkList b,int t)
//此函数用于判断在做加法或减法运算时不同情况下结果的正负号
{
	int trag=0;//trag=1时,a>b;trag=0时,a=b;trag=-1时,a<b。初始值为0,即默认情况下a=b
	PDuLNode p1,p2;
	int ts[3][3][3][3]={//此四维数组中存了不同情况下结果的正负号,四维中的第一维:trag+1;第二维:a->trag+1,即a的正负;第三维:b->trag+1,b的正负;第四维:t+1,加或减运算
	 1,0,-1,0,0,0,-1,0, 1,0,0,0,0,0,0,0,0,0,1,0,-1,0,0,0,-1,0,1,//1表示正,-1表示负,0是不存在的睛况
	 1,0,-1,0,0,0,-1,0, 1,0,0,0,0,0,0,0,0,0,1,0, 1,0,0,0, 1,0,1,
	-1,0,-1,0,0,0,-1,0,-1,0,0,0,0,0,0,0,0,0,1,0, 1,0,0,0, 1,0,1};
	p1=a->head;p2=b->head;//以下判断a与b的大小
	if (a->n1>b->n1) trag=1;
	else if (a->n1<b->n1) trag=-1;
	else
	{
		if(p1->data>p2->data) trag=1;
		else if(p1->data<p2->data) trag=-1;
		else
		{    p1=p1->next;p2=p2->next;
			 while(p1!=a->head&&p2!=b->head)
				 if(p1->data>p2->data){trag=1;break;}
				 else if(p1->data<p2->data) {trag=-1;break;}
				 else {p1=p1->next;p2=p2->next;}
		}
		if(trag==0&&p1!=a->head) trag=1;
		if(trag==0&&p2!=b->head) trag=-1;
	}
	return ts[trag+1][a->trag+1][b->trag+1][t+1];//返回正负号情况
}

void Adjust(PDuLinkList L)
//此函数用于修正结果数据,以去掉数据头部或尾部的零
{
	PDuLNode p,q;
	while (L->head->data==0&&L->head!=L->ge) L->head=L->head->next;//头结点后移支首个不为0的数或个位
	p=L->head->prior;
	while(p->data==0&&p!=L->ge)//删除多余的零
	{q=p->prior;p->prior->next=p->next;p->next->prior=p->prior;free(p);p=q;}
}

PDuLinkList AddSub(PDuLinkList a,PDuLinkList b,int t)
//此函数用于时进加减法运算,当t=1时返回a+b的值,当t=-1时返回a-b的值
//运算时,从个位数开始分别向两头进行,即整数部分从右往左,小数部分从左往右
{
	int sum,t2;//sum存每一位的运算结果;t2同t,它们分别在不同情况下控制两数是做加运算还是减运算
	PDuLinkList res;//res即result,结果链表
	PDuLNode p,ph,p1,p2,q,q1,q2;//p,ph,p1,p2都为原始数据链表指针;q,q1,q2都为结果链表指针
	res=(PDuLinkList)malloc(sizeof(DuLinkList));//以下几行是为结果链表申请空间并初始化
	q1=(PDuLNode)malloc(sizeof(DuLNode));
	res->head=NULL;res->ge=q1;res->n2=0;res->trag=0;
	res->trag=compare(a,b,t);//调用compare函数,判断结果的正负
	q1->data=0;q1->next=q1;q1->prior=q1;
	t=t*a->trag*b->trag;//t控制每位数之间的加或减
	//以下为整数部分的运算,各指针从个位开始前移
	p1=a->ge;p2=b->ge;//以下几行(while语句之前)先做一位运算,以防原始数据中整数位只有一位
	sum=p1->data+p2->data*t;//每次运算时,b中的数据都必须先乘以t,然后再与a中的数据相加,让t达到控制加减的效果
	q1->data+=sum;
	q2=(PDuLNode)malloc(sizeof(DuLNode));q2->data=0;//申请一结点空间并初始化为0
	q2->prior=q1->prior;q1->prior->next=q2;q2->next=q1;q1->prior=q2;//把新申请的结点插入结果双向链表中
	q2->data=q1->data/10;q1->data=q1->data%10;//当sum>10时进位
	if(q1->data<0){q1->data+=10;q2->data--;}//当sum<0时退位
	q1=q2;//结果链表指针前移一位
	while(p1!=a->head&&p2!=b->head)//对a和b整数部分相同的位数进行运算,各语句功能同上
	{
		p1=p1->prior;p2=p2->prior;//a与b的数据指针前移
		sum=p1->data+p2->data*t;
		q1->data+=sum;
		q2=(PDuLNode)malloc(sizeof(DuLNode));q2->data=0;
		q2->prior=q1->prior;q1->prior->next=q2;q2->next=q1;q1->prior=q2;
		q2->data=q1->data/10;q1->data=q1->data%10;
		if(q1->data<0){q1->data+=10;q2->data--;}
		q1=q2;
	}
	p=(PDuLNode)malloc(sizeof(DuLNode));//此两行没有实际用处,只是防止出错
	ph=(PDuLNode)malloc(sizeof(DuLNode));
	p=ph;//当下两个if语句没有运行是,下一个while语句也不用运行
	if(p1!=a->head)  {p=p1;ph=a->head;t2=1;}//当a中还有数据时,复制到res中,t2功能同上面的t,控制复制时是加还是减
	if(p2!=b->head)  {p=p2;ph=b->head;t2=t;}//当b中还有数据时,复制到res中
	while(p!=ph)//具体的复制语句,各句功能与前面的雷同
	{
		p=p->prior;
		q1->data+=p->data*t2;
	   	q2=(PDuLNode)malloc(sizeof(DuLNode));
	   	q2->prior=q1->prior;q1->prior->next=q2;q2->next=q1;q1->prior=q2;
		q2->data=q1->data/10;q1->data=q1->data%10;
		if(q1->data<0){q1->data+=10;q2->data--;}
	    q1=q2;
	}
	res->head=q1;//把q1赋给结果链表的头指针
	//以下开始做小数部分的运算,各指针从个位向后移

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -