c语言实现带加减乘除以及单元函数的计算器

整体思路是逆波兰+计算后缀表达式
其中比较特殊的地方是实现了单元与多元函数的计算
首先是新引入了一个栈来存储函数名,然后在右括号的结算后把函数名push进目标栈
多元函数的逗号’,‘处理类似右括号’)’,只是不将右括号’)'从临时栈中出栈

运行截图
c语言实现带加减乘除以及单元函数的计算器_第1张图片

#include 
#include 
#include "simpio.h"
#include "strlib.h"
#include "stack.h"


#define MaxLineLength 1000
#define MaxOperatorLength 50
#define MaxArrayLength 1000
#define ReverseNotationOutput 1   //whether output the Reverse Polish Notation or not

string AimArray[MaxArrayLength];  //the Reverse Polish Notation array 
int AimSize; 

int priority(string x)//return the priority rank of x
{
	if (StringEqual(x, "+") || StringEqual(x, "-")) return 1;
	if (StringEqual(x, "*") || StringEqual(x, "/")) return 2;
	return 0;
}

int IsSymbol(char ch)//tell whether ch is symbol(+-*/) or not
{
    return (ch == '+' || ch == '-' || ch == '*' || ch == '/');
}

int IsNum(char ch)//tell whether ch is number or not
{
    return (ch <= '9' && ch >= '0' || ch == '.');
}

int IsDouble(string str)//tell whether str could be converted to double or not
{
	double result;
	char dummy;
	return (sscanf(str, " %lg %c", &result, &dummy) == 1);
}
 
int IsChar(char ch)//tell whether ch is character or not
{
	return ((ch>='a' && ch<='z') || (ch>='A' && ch<='Z'));
}
 
int IsSeparator(char ch)//tell whether ch is separator or not
{
	return (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
}
 
void push_string(stackADT stack, const string content)//push content of string
{
	string s = (string)malloc(MaxOperatorLength*sizeof(char));
	s = CopyString(content);
	PushStack(stack, (void*)s);
}
 
void push_double(stackADT stack, const double content)//push content of double
{
	double *x = (double*)malloc(sizeof(double));
	*x = content;
	PushStack(stack, (void*)x);
}
 
void push_aim(const string content)//push content to AimArray 
{
	string s = (string)malloc(MaxOperatorLength*sizeof(char));
	s = ConvertToUpperCase(CopyString(content));
	AimArray[AimSize++] = s;
}

void error(const char *x)//output error message and exit -1
{
	printf("%s",x);
	exit(-1);
}

void GetReverseNotation(string Line)//Get the reverse polish notation from a mathematical expression
{
	stackADT TempStack = NewStack();//stack to storage the symbol(+ - / * ( ) )
	stackADT FuncStack = NewStack();//stack to storage the function name(SIN COS TAN LOG POW)
    int len = StringLength(Line);
    int i, flag;
    
    for (i = 0, flag = 0; i < len; i++) //Convert Infix Expression to Reverse Polish Notation
    {
    	flag++;
    	char ch = IthChar(Line, i);
    	if (IsSeparator(ch)) continue;
        if (IsNum(ch))
		{
			int t = i;
            while(i+1<len && IsNum(IthChar(Line, i+1))) i++;
            push_aim(SubString(Line, t, i));
            continue;
        }   
        if (ch == '(')
		{
            push_string(TempStack, "(");
            flag = 0;
            continue;
        }  
		if (IsSymbol(ch))
		{
			if (flag == 1 && ch == '-') push_aim("0");
			while (!IsemptyStack(TempStack) && priority(CharToString(ch)) <= priority((char *)TopStack(TempStack)))
				push_aim((char *)PopStack(TempStack));
            push_string(TempStack, CharToString(ch));
            continue;
        }  
        if (ch == ')')
        {
        	while (TRUE)
			{
				if (IsemptyStack(TempStack)) error("There is no corresponding '(' before ')'");
				if (StringEqual((char *)TopStack(TempStack), "("))
				{
					PopStack(TempStack);
					break;
				}
				push_aim((char *)PopStack(TempStack));
			}
			if (!IsemptyStack(FuncStack)) push_aim((string)PopStack(FuncStack));
			continue;
		}
		if (ch == ',')
		{
        	while (TRUE)
			{
				if (IsemptyStack(TempStack)) error("There is no corresponding '(' before ','");
				if (StringEqual((char *)TopStack(TempStack), "("))
				{
					break;
				}
				push_aim((char *)PopStack(TempStack));
			}
			continue;	
		}
		if (IsChar(ch))
		{
			int t = i;
            while(i+1<len && IsChar(IthChar(Line, i+1))) i++;
            push_string(FuncStack,SubString(Line, t, i));
            continue;
        }
        error("Illegal character detected");
    }
    if (!IsemptyStack(FuncStack)) push_aim((string)PopStack(FuncStack));
    while (!IsemptyStack(TempStack))
    {
		if (StringEqual((char *)TopStack(TempStack), "(")) error("There is a redundant '('");
    	push_aim((char *)PopStack(TempStack));
    }
    if (ReverseNotationOutput)
    {
	    printf("The Reverse Polish Notation(n = %d): ",AimSize);
	    for (i=0;i<AimSize;i++)
	    {
	    	string x = AimArray[i];
	    	printf("%s ",x);
	    }
 	    printf("\n");
 	}
    FreeStack(TempStack);
    FreeStack(FuncStack);
}

double CalcAnswer()//calculate the answer of the reverse polish notation
{
	stackADT CalcStack = NewStack();
	int i;
		
	for (i = 0; i < AimSize; i++)//calculate the reverse polish notation
	{
		string str = AimArray[i];
		string sError = (string)malloc(MaxOperatorLength + 18);
		sprintf(sError, "There's redundant '%s'", str);
		if(StringLength(str) == 1 && IsSymbol(str[0])) //binary operator
		{
			if (IsemptyStack(CalcStack)) error(sError);
			double y = *(double*)PopStack(CalcStack);
			if (IsemptyStack(CalcStack)) error(sError);
			double x = *(double*)PopStack(CalcStack);
			switch(str[0])
			{
				case '+' :
					push_double(CalcStack, x + y);
	                break;
				case '-' :
					push_double(CalcStack, x - y);
					break;
				case '*' :
					push_double(CalcStack, x * y);
					break;
				case '/':
					push_double(CalcStack, x / y);
					break;
			}
		} else if (StringEqual(str,"SIN")) //unary operator
		{
			if (IsemptyStack(CalcStack)) error(sError);
			double x = *(double*)PopStack(CalcStack);
			push_double(CalcStack, sin(x));
		} else if (StringEqual(str,"COS"))
		{
			if (IsemptyStack(CalcStack)) error(sError);
			double x = *(double*)PopStack(CalcStack);
			push_double(CalcStack, cos(x));
		} else if (StringEqual(str,"TAN"))
		{
			if (IsemptyStack(CalcStack)) error(sError);
			double x = *(double*)PopStack(CalcStack);
			push_double(CalcStack, tan(x));
		} else if (StringEqual(str,"LOG"))
		{
			if (IsemptyStack(CalcStack)) error(sError);
			double x = *(double*)PopStack(CalcStack);
			push_double(CalcStack, log(x));
		} else if (StringEqual(str,"POW") || StringEqual(str,"POWER"))
		{
			if (IsemptyStack(CalcStack)) error(sError);
			double y = *(double*)PopStack(CalcStack);
			double x = *(double*)PopStack(CalcStack);
			push_double(CalcStack, pow(x, y));
		} else  //number 
		{
			if (!IsDouble(str))
			{
				sprintf(sError, "Undefined function '%s'", str);
				error(sError);
			}
            push_double(CalcStack, StringToReal(str));
		}
		FreeBlock(sError);
	}
	double ans = *(double*)PopStack(CalcStack);
	FreeStack(CalcStack);
	return (ans);
}
	
//Main program
main()
{
	string Line = (string)malloc(MaxLineLength*sizeof(char));
    while (TRUE)
    {
    	AimSize = 0; //Initialization
 		printf("Type the mathematical expression(enter or 'exit' to exit):\n");
		Line = GetLine();
		if (StringEqual(Line, "") || StringEqual(ConvertToUpperCase(Line), "EXIT")) break;
		GetReverseNotation(Line);
		double ans = CalcAnswer();
		printf("%s = %.4f\n\n", Line, ans); 
	}
    return 0; 
}



include的是The Art and Science of C的教材库
simpio.c

/*
 * File: simpio.c
 * Version: 3.0
 * Last modified on Tue Oct  4 11:24:40 1994 by eroberts
 * -----------------------------------------------------
 * This file implements the simpio.h interface.
 */

#include 
#include 

#include "genlib.h"
#include "strlib.h"
#include "simpio.h"

/*
 * Constants:
 * ----------
 * InitialBufferSize -- Initial buffer size for ReadLine
 */

#define InitialBufferSize 120

/* Exported entries */

/*
 * Functions: GetInteger, GetLong, GetReal
 * ---------------------------------------
 * These functions first read a line and then call sscanf to
 * translate the number.  Reading an entire line is essential to
 * good error recovery, because the characters after the point of
 * error would otherwise remain in the input buffer and confuse
 * subsequent input operations.  The sscanf line allows white space
 * before and after the number but no other extraneous characters.
 */

int GetInteger(void)
{
    string line;
    int value;
    char termch;

    while (TRUE) {
        line = GetLine();
        if (line == NULL) Error("GetInteger: unexpected end of file");
        switch (sscanf(line, " %d %c", &value, &termch)) {
          case 1:
            FreeBlock(line);
            return (value);
          case 2:
            printf("Unexpected character: '%c'\n", termch);
            break;
          default:
            printf("Please enter an integer\n");
            break;
        }
        FreeBlock(line);
        printf("Retry: ");
    }
}

long GetLong(void)
{
    string line;
    long value;
    char termch;

    while (TRUE) {
        line = GetLine();
        if (line == NULL) Error("GetLong: unexpected end of file");
        switch (sscanf(line, " %ld %c", &value, &termch)) {
          case 1:
            FreeBlock(line);
            return (value);
          case 2:
            printf("Unexpected character: '%c'\n", termch);
            break;
          default:
            printf("Please enter an integer\n");
            break;
        }
        FreeBlock(line);
        printf("Retry: ");
    }
}

double GetReal(void)
{
    string line;
    double value;
    char termch;

    while (TRUE) {
        line = GetLine();
        if (line == NULL) Error("GetReal: unexpected end of file");
        switch (sscanf(line, " %lf %c", &value, &termch)) {
          case 1:
            FreeBlock(line);
            return (value);
          case 2:
            printf("Unexpected character: '%c'\n", termch);
            break;
          default:
            printf("Please enter a real number\n");
            break;
        }
        FreeBlock(line);
        printf("Retry: ");
    }
}

/*
 * Function: GetLine
 * -----------------
 * This function is a simple wrapper; all the work is done by
 * ReadLine.
 */

string GetLine(void)
{
    return (ReadLine(stdin));
}

/*
 * Function: ReadLine
 * ------------------
 * This function operates by reading characters from the file
 * into a dynamically allocated buffer.  If the buffer becomes
 * full before the end of the line is reached, a new buffer
 * twice the size of the previous one is allocated.
 */

string ReadLine(FILE *infile)
{
    string line, nline;
    int n, ch, size;

    n = 0;
    size = InitialBufferSize;
    line = GetBlock(size + 1);
    while ((ch = getc(infile)) != '\n' && ch != EOF) {
        if (n == size) {
            size *= 2;
            nline = (string) GetBlock(size + 1);
            strncpy(nline, line, n);
            FreeBlock(line);
            line = nline;
        }
        line[n++] = ch;
    }
    if (n == 0 && ch == EOF) {
        FreeBlock(line);
        return (NULL);
    }
    line[n] = '\0';
    nline = (string) GetBlock(n + 1);
    strcpy(nline, line);
    FreeBlock(line);
    return (nline);
}

strlib.c

/*
 * File: strlib.c
 * Version: 1.0
 * Last modified on Fri Jul 15 14:10:41 1994 by eroberts
 * -----------------------------------------------------
 * This file implements the strlib.h interface.
 */

/*
 * General implementation notes:
 * -----------------------------
 * This module implements the strlib library by mapping all
 * functions into the appropriate calls to the ANSI 
 * interface.  The implementations of the individual functions
 * are all quite simple and do not require individual comments.
 * For descriptions of the behavior of each function, see the
 * interface.
 */

#include 
#include 
#include 

#include "genlib.h"
#include "strlib.h"

/*
 * Constant: MaxDigits
 * -------------------
 * This constant must be larger than the maximum
 * number of digits that can appear in a number.
 */

#define MaxDigits 30

/* Private function prototypes */

static string CreateString(int len);

/* Section 1 -- Basic string operations */

string Concat(string s1, string s2)
{
    string s;
    int len1, len2;

    if (s1 == NULL || s2 == NULL) {
        Error("NULL string passed to Concat");
    }
    len1 = strlen(s1);
    len2 = strlen(s2);
    s = CreateString(len1 + len2);
    strcpy(s, s1);
    strcpy(s + len1, s2);
    return (s);
}

char IthChar(string s, int i)
{
    int len;

    if (s == NULL) Error("NULL string passed to IthChar");
    len = strlen(s);
    if (i < 0 || i > len) {
        Error("Index outside of string range in IthChar");
    }
    return (s[i]);
}

string SubString(string s, int p1, int p2)
{
    int len;
    string result;

    if (s == NULL) Error("NULL string passed to SubString");
    len = strlen(s);
    if (p1 < 0) p1 = 0;
    if (p2 >= len) p2 = len - 1;
    len = p2 - p1 + 1;
    if (len < 0) len = 0;
    result = CreateString(len);
    strncpy(result, s + p1, len);
    result[len] = '\0';
    return (result);
}

string CharToString(char ch)
{
    string result;

    result = CreateString(1);
    result[0] = ch;
    result[1] = '\0';
    return (result);
}

int StringLength(string s)
{
    if (s == NULL) Error("NULL string passed to StringLength");
    return (strlen(s));
}

string CopyString(string s)
{
    string newstr;

    if (s == NULL) Error("NULL string passed to CopyString");
    newstr = CreateString(strlen(s));
    strcpy(newstr, s);
    return (newstr);
}

/* Section 2 -- String comparison functions */

bool StringEqual(string s1, string s2)
{
    if (s1 == NULL || s2 == NULL) {
        Error("NULL string passed to StringEqual");
    }
    return (strcmp(s1, s2) == 0);
}

int StringCompare(string s1, string s2)
{
    if (s1 == NULL || s2 == NULL) {
        Error("NULL string passed to StringCompare");
    }
    return (strcmp(s1, s2));
}

/* Section 3 -- Search functions */

int FindChar(char ch, string text, int start)
{
    char *cptr;

    if (text == NULL) Error("NULL string passed to FindChar");
    if (start < 0) start = 0;
    if (start > strlen(text)) return (-1);
    cptr = strchr(text + start, ch);
    if (cptr == NULL) return (-1);
    return ((int) (cptr - text));
}

int FindString(string str, string text, int start)
{
    char *cptr;

    if (str == NULL) Error("NULL pattern string in FindString");
    if (text == NULL) Error("NULL text string in FindString");
    if (start < 0) start = 0;
    if (start > strlen(text)) return (-1);
    cptr = strstr(text + start, str);
    if (cptr == NULL) return (-1);
    return ((int) (cptr - text));
}

/* Section 4 -- Case-conversion functions */

string ConvertToLowerCase(string s)
{
    string result;
    int i;

    if (s == NULL) {
        Error("NULL string passed to ConvertToLowerCase");
    }
    result = CreateString(strlen(s));
    for (i = 0; s[i] != '\0'; i++) result[i] = tolower(s[i]);
    result[i] = '\0';
    return (result);
}

string ConvertToUpperCase(string s)
{
    string result;
    int i;

    if (s == NULL) {
        Error("NULL string passed to ConvertToUpperCase");
    }
    result = CreateString(strlen(s));
    for (i = 0; s[i] != '\0'; i++) result[i] = toupper(s[i]);
    result[i] = '\0';
    return (result);
}

/* Section 5 -- Functions for converting numbers to strings */

string IntegerToString(int n)
{
    char buffer[MaxDigits];

    sprintf(buffer, "%d", n);
    return (CopyString(buffer));
}

int StringToInteger(string s)
{
    int result;
    char dummy;

    if (s == NULL) {
        Error("NULL string passed to StringToInteger");
    }
    if (sscanf(s, " %d %c", &result, &dummy) != 1) {
        Error("StringToInteger called on illegal number %s", s);
    }
    return (result);
}

string RealToString(double d)
{
    char buffer[MaxDigits];

    sprintf(buffer, "%G", d);
    return (CopyString(buffer));
}

double StringToReal(string s)
{
    double result;
    char dummy;

    if (s == NULL) Error("NULL string passed to StringToReal");
    if (sscanf(s, " %lg %c", &result, &dummy) != 1) {
        Error("StringToReal called on illegal number %s", s);
    }
    return (result);
}

/* Private functions */

/*
 * Function: CreateString
 * Usage: s = CreateString(len);
 * -----------------------------
 * This function dynamically allocates space for a string of
 * len characters, leaving room for the null character at the
 * end.
 */

static string CreateString(int len)
{
    return ((string) GetBlock(len + 1));
}

stack.c

/*
 * File: stack.c
 * -------------
 * This file implements the stack.h abstraction using an array.
 */

#include 

#include "genlib.h"
#include "stack.h"

/*
 * Constants:
 * ----------
 * MaxStackSize -- Maximum number of elements in the queue
 */

#define MaxStackSize 1000

/*
 * Type: stackCDT
 * --------------
 * This type provides the concrete counterpart to the stackADT.
 * The representation used here consists of an array coupled with 
 * with an integer indicating the top element of the stack. 
 */
//stackCDTÀïÃæÓиöarray 
struct stackCDT {
    void *array[MaxStackSize]; /*stack space -- pointer array*/ 
    int top; /*top position of the stack*/
};

/* Exported entries */

/*
 * Function: NewStack
 * ------------------
 * This function allocates and initializes the storage for a
 * new stack.
 */

stackADT NewStack(void)
{
    stackADT stack;

    stack = New(stackADT);
    stack->top = -1;
    return (stack);
}

/*
 * Function: FreeStack
 * -------------------
 * This function frees the stack storage.
 */

void FreeStack(stackADT stack)
{
    FreeBlock(stack);
}

/*
 * Function: PushStack
 * -----------------
 * This function adds a new element to the top of the stack.
 */

void PushStack(stackADT stack, void *obj)
{
    if (stack->top == MaxStackSize-1) {
        Error("Pushstack called on a full stack");
    }
    stack->array[++stack->top] = obj;
}

/*
 * Function: PopStack
 * -----------------
 * This function removes and returns the data value at the
 * top of the stack.
 */

void *PopStack(stackADT stack)
{
    void *result;

    if (stack->top == -1) {
        Error("Popstack of empty stack");
    }
    result = stack->array[stack->top--];
    return (result);
}

/*
 * Function: IsemptyStack
 * ---------------------
 * This function checks if the stack is empty.
 */

bool IsemptyStack(stackADT stack)
{
    return (stack->top == -1);
}

/*
 * Function: TopStack
 * -----------------
 * This function returns the top element of the stack.Topstack an empty stack is
 * an NULL pointer.
 */

void *TopStack(stackADT stack)
{
    void *result;

    if (stack->top == -1) return (NULL);
    result = stack->array[stack->top];
    return (result);
}

以上

你可能感兴趣的:(堆栈)