C語言實現簡易計算器(可作加減乘除)


C語言實現簡易計算器(加減乘除)

計算器作為課設項目,已完成答辯,先將代碼和思路(注釋中)上傳一篇博客

已增添、修改、整理至無錯且可正常運行

雖使用了棧,但初學者可在初步了解棧和結構語法后理解代碼

#include <stdlib.h>

#include <stdio.h>
#include <string.h>

#define IsDouble 0
#define IsChar 1
//_______________________________________________________________________________________________________________________________________________________
//1.支持浮點數和字符的棧 
typedef struct {
    char * buffer;
    int typesize;
    int top;
    int max;
} stack;

stack * CreateStack(int max, int typesize);//創建一個棧 
void DestroyStack(stack *);//釋放棧的空間 
void ClearStack(stack *);//清空棧 
int Push(stack *, void *);//入棧 
int Pop(stack *, void *);//出棧 
int GetSize(stack *s);//得到棧的大小 
int GetTop(stack *, void *);//找到棧頂 
int IsEmpty(stack *);//判斷是否為空棧,空則下溢 
int IsFull(stack *);//判斷棧是否已滿 ,滿則溢出 

stack * CreateStack(int max, int typesize){
    stack * s = (stack*)malloc(sizeof(stack));//為棧s malloc內存 
    if (!s) return 0;
	//為結構中buffer元素malloc內存 
    s->buffer = (char *)malloc(sizeof(char) * max * typesize);
    if (!s->buffer) return 0;
	//初始化結構中的棧頂,最大值,類型大小 
    s->top = -1;
    s->max = max;
    s->typesize = typesize;

    return s;
}

void DestroyStack(stack* s){
    free(s->buffer);//先釋放buffer的空間 
    free(s);//在釋放s的空間 
}

void ClearStack(stack * s){
    s->top = -1;//清空棧(棧頭位置歸零) 
}

int Push(stack * s, void * data){
    if (IsFull(s)) return 0;//如果棧已滿則return 0,防止溢出 
	//棧未滿則將棧頭移動打動下一位置,並將data中的元素拷入棧中buffer的第top位置 
    s->top++; 
    memcpy(s->buffer + s->top*s->typesize, data, s->typesize);
	//入棧成功return 1 
    return 1;
}

int Pop(stack * s, void * data){
    if (IsEmpty(s)) return 0;//出棧判斷棧是否為空,若為空則return 0 
	//棧未空則將buffer中top位置的字符拷入data記錄,並讓棧頭向前移動一個位置 
    memcpy(data, s->buffer + s->top*s->typesize, s->typesize);
    s->top--;
	//成功則return 1 
    return 1;
}



int GetSize(stack *s){
	return s -> top+1;//棧頭位置+1得到大小 
}


int GetTop(stack *s, void * data){
    if (IsEmpty(s)) return 0;//如果棧空return 0 
    //棧不為空則將top位置的字符拷回data記錄,得到棧頭 
    memcpy(data, s->buffer + s->top*s->typesize, s->typesize);
    //成功則return 1; 
    return 1;
}

int IsEmpty(stack * s){
    return s->top == -1;//如果top為-1則棧空 
}

int IsFull(stack * s){
    return s->top == s->max-1;//如果top為max-1則棧滿 
}
//___________________________________________________________________________________________________________________________________________________








//2.定義一個cal類型,其中data存數時sign為IsDouble,存字符時,sign為Ischar 
typedef struct {
        double data;
        char sign;
} cal;



//3.查找對應符號(找到則返回該符號下標)(找不到則說明該部分為數字返回-1) 
int SearchCode(char ch){
        char * code = "+-*/()@";//@為終止符,算式輸入結束 
        int index = 0;//
        while (code[index]){
			if (code[index] == ch) return index;
			index++;
        }
		return -1;
}




//4.得到兩個符號間的優先級
//與SearchCode相對應, 
char GetPriority(char ch, char next){
		//創建一個perferen表,第i行(列)對應SearchCode函數中code中的第i個字符 
        char perferen[7][7] = {
                ">><<<>>",
                ">><<<>>",
                ">>>><>>",
                ">>>><>>",
                "<<<<<=E",
                ">>>>E>>",
                "<<<<<E="
        };
		//找到兩個形參對應的字符 
        int c = SearchCode(ch);
        int n = SearchCode(next);
		//如果找不到對應運算符(字符不是運算符而是為數字)return E 
        if (c==-1 || n==-1) return 'E';
		//如果找到兩個對應運算符則按照優先級表返回兩個運算符的優先級 
        return perferen[c][n];
}




//5.四則運算 
double add(double a, double b) { return a+b; }
double sub(double a, double b) { return a-b; }
double mul(double a, double b) { return a*b; }
double ddiv(double a, double b) { return a/b; }




//整合四種運算 
double calcu(double a, char ch, double b){
        double (*calculation[4])(double,double) = {add,sub,mul,ddiv};
        return calculation[SearchCode(ch)](a,b);
}









//6.檢測字符串 
int CheckStr(char * buffer){
		int n;
		//遍歷字符串確保算式中無非法字符若檢測到非法字符return 0,若都合法則return 1 
		for (n = 0;buffer[n];n++){
			if ((SearchCode(buffer[n]) != -1 || buffer[n] == '.' || (buffer[n] >= '0' && buffer[n] <= '9')) && buffer[n] != '@') continue;
			else return 0;
		}
		buffer[n] = '@';//加上終止符,表示算式結束 
		buffer[n+1] = '\0';
		return 1;
}






//7.得到數據轉化為double類型存入rs 
int GetDigit(char * buffer, int * n, double * rs){
        char str[30];
        int i,j = 0;
        for (i = 0;SearchCode(buffer[*n]) == -1;i++){
                str[i] = buffer[*n];//從*n位置開始,將這一串數字字符存入str 
                (*n)++;
        }
        str[i] = '\0';
        for (i = 0;str[i];i++){
            if (str[i] == '.') j++;
        }
        //如果一段小數有多個小數點或小數點在數字首尾,return 0 
        if (j>1 || str[i-1] == '.' || str[0] == '.') return 0;
        //rs接收轉化為double的數據 
        *rs = atof(str);
        //操作成功return 1 
        return 1;
}







//8.將用戶輸入的buffer字符串轉化為可供程序運算的calstr數組 
int resolu(char * buffer, cal * calstr){
        int i = 0, j = 0;
        cal c;
		
        while (buffer[i]){
            if (SearchCode(buffer[i]) == -1){
        		//如果得到數據不成功則return 0 
                if (GetDigit(buffer,&i, &c.data) == 0) return 0;
                //如果成功得到數據則在c.sign標記為浮點數 
                c.sign = IsDouble;
				//將c存入數組calstr中 
                calstr[j++] = c;
            }
            else{
				//若符號為運算符 
        		//判斷正負號 
                if (buffer[i] == '-' && (buffer[i-1] == '('||buffer[i-1] == '+'||buffer[i-1] == '-'||buffer[i-1] == '*'||buffer[i-1] == '/') || (i==0 && buffer[0] == '-')){
            		i++;
                    if (GetDigit(buffer,&i, &c.data) == 0) return 0;//在符號的下一位開始查找,若找不到數字return 0 
                    //否則,給數字取相反數,c.sign標記為浮點數,存入calstr中 
                    c.data = 0 - c.data;
                    c.sign = IsDouble;
                    calstr[j++] = c;
                } else
				//如果是正號,與符號處理方式同理 
                if (buffer[i] == '+' && (buffer[i-1] == '('||buffer[i-1] == '+'||buffer[i-1] == '-'||buffer[i-1] == '*'||buffer[i-1] == '/') || (i==0 && buffer[0] == '+')){
            		i++;
                    if (GetDigit(buffer, &i, &c.data) == 0) return 0;
                    c.sign = IsDouble;
                    calstr[j++] = c;
                }
                else{
                	//如果不是正負號,則為運算符,先強制轉換為double類型存在c.data里,然后c.sign標記為char類型,存入calstr 
                    c.data = (double)buffer[i++];
                    c.sign = IsChar;
                    calstr[j++] = c;
                }
                    
            }
        }
        //操作蔡成功則return 1 
        return 1; 
}








//9.計算出結果 
int result(cal * calstr, double * rs){
        stack * pst = CreateStack(100,sizeof(char));//運算符棧 
        stack * pnd = CreateStack(100,sizeof(double));//數據棧 
		
        double num1,num2;
        int n = 0;
        char ch = '@';
        Push(pst, &ch);
        //在轉換得到的calstr中遍歷直到終止符'@" 
        while(ch != '@' || !(calstr[n].sign == IsChar && (char)calstr[n].data == '@')){
        	//如果calstr的n位上是浮點數,則將這個data壓棧進入數據棧pnd中 
            if (calstr[n].sign == IsDouble){
                Push(pnd, &(calstr[n].data));
                n++;
            }
            //反之,如果是運算符,則要檢測優先級 
            else{ 
                    switch( GetPriority(ch, (char)calstr[n].data)){
                    	//如果運算符優先級較小,則讓ch等於優先級大的符號並壓入符號棧pst中 
                        case '<':
                                ch = (char)calstr[n].data;
                                Push(pst, &ch);
                                n++;
                                break;
                        //如果結果為等號,讓符號出棧暫存到ch中 
                        case '=':
                                if (!Pop(pst, &ch)) return 0;
                                n++;
                                break;
                        //如果ch優先級較高,則將前兩個數字及運算符出棧,分別儲存至num2,ch,num1中,進行運算,得到的結果再次壓棧進入pnd中 
                        case '>':
                                if (!(Pop(pnd,&num2) && Pop(pst,&ch) && Pop(pnd,&num1))) return 0;
                                num1 = calcu(num1,ch,num2);
                                Push(pnd, &num1);
                                break;
                        //如果符號順序出錯,return 0 
                        case 'E':
                                return 0;
                    }
            }
            //檢測是否可以得到棧頂符號,棧空則return 0 
            if (!GetTop(pst, &ch)) return 0;
        }
		//如果棧中得到了最終結果,並且取出pnd中的最終結果到rs,return 1 
        if (GetSize(pnd) == 1 && GetTop(pnd,rs)){
                DestroyStack(pst);
                DestroyStack(pnd);
                return 1;
        }
        //否則 return 0 
        else{
                return 0;
        }
}




//10.用戶交互函數 
void treatment()
{
        char buffer[100];//用戶輸入的字符串(算式) 
        cal calstr[50];//計算用的數組 
        double rs = 0;//計算結果 
        printf("Enter your equation:");
        gets(buffer);//讓用戶輸入算式buffer 
		//用戶不輸入"exit"就不退出 
        while (!(buffer[0]=='e' && buffer[1]=='x' && buffer[2]=='i' && buffer[3]=='t')){
        		//檢查buffer中字符君合法,成功將buffer轉化為用於計算的calstr數組,成功計算出結果存入rs 
            	if (CheckStr(buffer) && resolu(buffer,calstr) && result(calstr,&rs)){
                    printf("\n%lf\n",rs);
            	}else{
                    printf("\nError!\n");
            	}
			printf("Enter \"exit\"to quit");
            printf("\nEnter your equation:");
            gets(buffer);//再次讓用戶輸入算式 
        }
        printf("\nbye\n");
}




//11.主函數 
int main(){
        treatment();
}

參考文獻鏈接如下

[參考文獻](c語言強化訓練——簡易計算器 - 石瑩 - 博客園 (cnblogs.com))


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM