C프로그래밍에 도움이 되길 바라며, 잘 못 된 점이나 실행 중 오류가 나면 댓글 달아주시기 바랍니다.
또한 더 간결하고 효율적으로 수정할 수 있다면 제안해 주시기 바랍니다.
연산식만 추가하고 연산자를 단일 문자가 아닌 문자열로 수정하면 math.h에 포함된 각종 연산을 모두 할 수 있습니다.
(sin, cos, tan, asin, acon, atan, sinh, cosh, tanh, exp, pow, pow10, sqrt, hypot, log, log10, abs...)
소스 파일 :
#include <stdio.h> #include <ctype.h> #include <conio.h> #include <string.h> #include <stdlib.h> #include <math.h> #define TRUE 1 #define FALSE 0 #define ON 1 #define OFF 0 int trace; // 계산과정 보이기 int precision = 7+1; // 소수점 이하 7자리 /*-----------------------------------------------------------------------* | | 사용방법을 안내합니다 | | *------------------------------------------------------------------------*/ void introduce(void) // 안내문 { printf("*(x), /, +, -의 사칙연산\n"); printf("p(원주율), r(제곱근), ^(거듭제곱), %(나머지)\n"); printf("연산자가 없이 괄호에 연결된 숫자는\n"); printf("곱하기로 간주되며 최고우선순위를 갖습니다.\n"); printf("수식을 한 줄로 입력합니다.(예 : 48/2(9+3)-2p+r3+2^3\n\n"); } /*-----------------------------------------------------------------------* | | 각종 오류를 검사합니다 | | *------------------------------------------------------------------------*/ int character_check(char *str) // 불가산 문자 확인 { int i; char *ptr = str; for (i = 0; i < strlen(str); i++) { if (isdigit(*ptr) || *ptr == '*' || *ptr == 'x' || *ptr == 'X' || *ptr == '/' || *ptr == '%' || *ptr == '+' || *ptr == '-' || *ptr == 'r' || *ptr == '^' ||*ptr == 'p' || *ptr == ' ' || *ptr == '(' || *ptr == ')' || *ptr == '.') ptr++; else return (int)*ptr; } return -1; } int bracket_check(char *str) // 괄호 오류 검사 { int match = 0; char *ptr = str; while (*ptr++) { if (*ptr == '(') match++; else if (*ptr == ')') match--; if (match < 0) return match; // 우측 괄호가 먼저 나오면계산 불가 } return match; } int operator_check(char *str) // 연산식 검사 { char *ptr1 = str, *ptr2; if (*ptr1 == '*' || *ptr1 == 'x' || *ptr1 == 'X' || *ptr1 == '/' || *ptr1 == '%' || *ptr1 == '^' || *ptr1 == '+') return (int)*ptr1; // 첫 글자가 - 부호가 아닌 연산식은 오류 ptr1++; ptr2 = ptr1 - 1; while (*ptr1) { // 연산식이 연속되면 오 if ((*ptr1 == '*' || *ptr1 == 'x' || *ptr1 == 'X' || *ptr1 == '/' || *ptr1 == '+' || *ptr1 == '-') &&(*ptr2 == '*' || *ptr2 == 'x' || *ptr2 == 'X' || *ptr2 == '/' || *ptr2 == '+' || *ptr2 == '-')) return (int)*ptr1; else if (*ptr1 == ')' && *ptr2 == '(') return (int)*ptr1; else if ((*ptr1 == 'r' || *ptr1 == '^') && (*ptr2 == 'r' || *ptr2 == '^')) return (int)*ptr1; ptr1++; ptr2 = ptr1 - 1; } return 0; } /*--------------------------- 각종 오류 검사 ----------------------*/ int err_check(char *str) { int ret_val; ret_val = character_check(str); if (ret_val > -1) { printf("불가산 문자 '%c' 발견\n", ret_val); return FALSE; } ret_val = bracket_check(str); if (ret_val != 0) { printf("괄호 여닫음 불일치\n"); return FALSE; } ret_val = operator_check(str); if (ret_val != 0) { printf("수식 오류 : %c\n", ret_val); return FALSE; } return TRUE; } /*-----------------------------------------------------------------------* | | 사전 준비작업을 합니다 | | *------------------------------------------------------------------------*/ int remove_space(char *str) // 공백 제거 { int r_qty = 0; char buf[256] = "\0"; char *ptr1 = str, *ptr2 = buf; while (*ptr1) { if (*ptr1 == 'x') *ptr1 = '*'; if (*ptr1 == ' ') r_qty++; else *ptr2++ = *ptr1; ptr1++; } strcpy(str, buf); return r_qty; } void str2lower(char *str) // 연산자를 소문자로 통일 { char *ptr = str; while(*ptr++) { *ptr = tolower(*ptr); } } void insert_X(char *str) // 괄호에 우선 순위 부여 { int i; char buf[256] = "\0"; char *ptr2 = buf; for (i = 0; i < strlen(str); i++) { if (str[i] == '(') { if (isdigit(str[i-1])) { *ptr2++ = 'X'; *ptr2++ = '('; } else *ptr2++ = str[i]; } else if (str[i] == ')') { if (isdigit(str[i+1])) { *ptr2++ = ')'; *ptr2++ = 'X'; } else *ptr2++ = str[i]; } else if (i> 0 && str[i] == 'p') { if (isdigit(str[i-1]) || str[i-1] == 'p') { *ptr2++ = 'X'; *ptr2++ = str[i]; } } else if (i > 0 && str[i] == 'r') { if (isdigit(str[i-1]) || str[i-1] == 'p') { *ptr2++ = 'X'; *ptr2++ = str[i]; } } else *ptr2++ = str[i]; } strcpy(str, buf); } void add_bracket(char *str) { char buf[255] = "\0"; sprintf(buf, "(%s)", str); strcpy(str, buf); } /*-----------------------------------------------------------------------* | | 연산을 수행합니다 | | *------------------------------------------------------------------------*/ double get_left_value(int operat_pos, int *size, char *str) // 좌측 피연산자를 구합니다 { int i; char buf[128] = "\0"; char *ptr2 = buf; for (i = operat_pos - 1; i > 0; i--) { if (isdigit(str[i]) || str[i] == '.') continue; else if (str[i] == '-') break; else { i++; break; } } *size = operat_pos - i; for (; i < operat_pos + 1; i++) { if (isdigit(str[i]) || str[i] == '.' || str[i] == '-') { *ptr2++ = str[i]; } } return atof(buf); } double get_right_value(int operat_pos, int *size, char *str) // 우측 피연산자를 구합니다 { int i; char buf[128] = "\0"; char *ptr2 = buf; for (i = operat_pos +1; i < strlen(str); i++) { if (isdigit(str[i]) || str[i] == '.') continue; else break; } *size = i - operat_pos - 1; for (i = operat_pos + 1; i < operat_pos + *size +1; i++) { if (isdigit(str[i]) || str[i] == '.' ||str[i] == '-') *ptr2++ = str[i]; } return atof(buf); } // 맨 앞의 -는 숫자에 붙여 음수 취급 void operation(char *str) // 한 괄호내의 수식을 연산합니다 { int i, j, r_size, l_size; double lval, rval, result; char operat[][3] = { 'p', ' ', ' ', 'r', '^', ' ', 'X', ' ', ' ', '*', '/', '%', '+', '-', ' ' }; char buf[256] = "\0"; char str_cut[256] = "\0"; for (i = 0; i < sizeof(operat)/3; i++) { for (j = 0; j < strlen(str); j++) { if (str[j] == operat[i][0] ||str[j] == operat[i][1] || str[j] == operat[i][2]) { if (str[j] == 'p') { result = acos(-1.0); // 원주율 l_size = 0; r_size = 0; } else { rval = get_right_value(j, &r_size, str); if (str[j] == 'r') { result = sqrt(rval); // 제곱근 l_size = 0; } else { lval = get_left_value(j, &l_size, str); if (str[j] == '^') result = pow(lval, rval); //x의 y승 else if (str[j] == 'X' || str[j] == '*') result = lval * rval; // * else if (str[j] == '/') { if (rval == 0) printf("0으로 나눌 수 없습니다.\n"); else result = lval / rval; // / } else if (str[j] == '%') result = (int)lval % (int)rval; // % else if (str[j] == '+') result = lval + rval; // + else if (str[j] == '-') { if (j > 0) result = lval - rval; // - else continue; } } } sprintf(str_cut, "%.*g\0", precision, result); strset(buf, '\0'); strncpy(buf, str, j - l_size); strcat(buf, str_cut); strcat(buf, str + j + r_size+1); strset(str, '\0'); strcpy(str, buf); if (trace == ON) printf("%s\n", str); j = 0; } } } } void discover_bracket(char *str) // 괄호를 하나씩 제거합니다 { int i, start = 0, end = 0; double result; char buf[256] = "\0"; char str_cut[256] = "\0"; for (i = 0; i < strlen(str); i++) { if (str[i] == '(') start = i; else if (str[i] == ')') { end = i; strset(str_cut, '\0'); strncpy(str_cut, str + start + 1, end - start - 1); operation(str_cut); strset(buf, '\0'); strncpy(buf, str, start); strcat(buf, str_cut); strcat(buf, str+end+1); strset(str, '\0'); strcpy(str, buf); i = -1; if (trace == ON) { printf("%s\n", str); printf("계속하려면 아무키나 누르시오.\n"); getch(); } } } } int main(void) { char str_samp[255] = "-34(78(9/34 + 37%3) - 25 * 34 /57PR2 /48 /2( 9+3)-2p)+ r3+2^3"; char str[255] = "\0"; introduce(); printf("견본을 보시겠습니까? (y/N) "); if (toupper(getch()) == 'Y') { printf("\n"); strcpy(str, str_samp); printf("%s\n", str); } else { printf("\n수식입력 : "); gets(str); } printf("계산과정을 보시겠습니까? (y/N) "); if (toupper(getch()) == 'Y') trace = ON; // 계산과정 보이기 else trace = OFF; printf("\n입력된 수식 : %s\n", str); remove_space(str); // 공백문자 제거 if (trace == ON) printf("공백 제거 : %s\n", str); str2lower(str); // 연산문자를 소문자로 if (trace == ON) printf("소문자로 : %s\n", str); if (err_check(str) == FALSE) { // 수식의 오류 점검 return 0; } insert_X(str); // 괄호에 우선순위 부여 if (trace == ON) printf("우선순위 : %s\n", str); printf("준비된 수식 : %s\n", str); add_bracket(str); // 전체식을 괄호로 묶음 discover_bracket(str); // 괄호를 제거하면서 계산 수행 printf("계산 결과 : %s\n", str); // 계산 결과 화면 출력 } | cs |
첨부파일첨부된 파일이 6개 있습니다.
다음검색