CAFE

C 프로그래밍

48/2(9+3) 계산기 소스

작성자별은빛나고|작성시간13.01.20|조회수2,314 목록 댓글 1

C프로그래밍에 도움이 되길 바라며, 잘 못 된 점이나 실행 중 오류가 나면 댓글 달아주시기 바랍니다.

또한 더 간결하고 효율적으로 수정할 수 있다면 제안해 주시기 바랍니다.

연산식만 추가하고 연산자를 단일 문자가 아닌 문자열로 수정하면 math.h에 포함된 각종 연산을 모두 할 수 있습니다.

(sin, cos, tan, asin, acon, atan, sinh, cosh, tanh, exp, pow, pow10, sqrt, hypot, log, log10, abs...)

 

 

소스 파일 : 

첨부파일 LINECALC.C



#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 < 0return 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 *sizechar *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 *sizechar *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 = 0end = 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 + 1end - 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

다음검색
현재 게시글 추가 기능 열기

댓글

댓글 리스트
  • 작성자별은빛나고 작성자 본인 여부 작성자 | 작성시간 13.01.24 for (i = 0; i < strlen(str); i++) {...str[i++]....}의 문장은
    while(*ptr) { ... *ptr++ ...} 형식으로 바꾸어도 됩니다.
    포인터를 충분히 이해하셨다면 포인터로 바꾸는 것이 훨씬 속도도 빠르고 효율적입니다. 만약 포인터에 자신이 없다면 배열로 사용해도 상관없습니다. 문자열은 포인터와 배열이 거의 호환됩니다.
댓글 전체보기
맨위로

카페 검색

카페 검색어 입력폼