2015-01-12 5 views
0

- + 2 * 3 4/12 6과 같은 런타임 제공 입력을 저장할 수있는 배열을 만들려고합니다. 여기에 총 9 개의 요소가 있습니다. 입력 인스턴스 중 배열에 50 개 이상의 인덱스가 필요하지 않다고 가정합니다. 나는이 목적을 위해 정수 배열을 생각하고 있는데, 나는 어떤 특정 형식의 인덱스가 있는지 프로그램에서 후자를 구별 할 수 있도록 (return/Enter 키를 눌렀을 때 종료 된) 입력을 가져 오기 위해 scanf()에서 사용할 수있는 형식 지정자를 얻지 못하고있다. char 또는 int와 그 값은 무엇입니까?배열에서 문자와 정수의 조합 저장 및 검색

내가 %c 또는 getchar() 기능을 사용하는 경우 하나 이상의 숫자가 정수를 처리하는 데 어려움을 겪고 있습니다. * + - /와 같은 문자를 사용하는 경우 %d이 저장되지 않습니다. 등등.

가능하면 가능하면 친절하게 제안하십시오.

+1

당신은 하나에 2 개 개의 다른 질문을하고 있습니다 : 입력 문자열 및 숫자와 분리 문자 (텍스트의 첫 번째 질문)에서 구문 분석하는 방법과 배열에 저장하는 방법 (제목의 두 번째 질문). 그리고 첫 번째 질문에 올바르게 대답하기에 충분한 문맥을 제공하지 않습니다. 입력에 대한 ** 정확히 ** 귀하의 사양은 무엇입니까? 단 4 개의 연산자와 10 진수 정수? 다중 다중 함수 (1/x 또는 sqrt에 대한 'inv')? 모든 괄호 ('('')')? 소수 자리수 부동 (1.25)? 아니면 정말로 역 연산 4 정수 계산기입니까? 그리고 여러 개의 공백, 탭을 허용합니까? –

+0

실제로 접두사 식 계산기와 같은 것을 구현하고 싶습니다. 난 괄호를 사용하고 싶지 않다. 단지 배열 인덱스를 사용하는 피연산자를 구분하기를 원할 뿐이다. 내 예제 12처럼 두 번째 마지막 인덱스에 저장해야하며 배열의 마지막 인덱스에 6 저장해야합니다. 지금은 그냥 정수를 고려하고 있지만 그것은 부동 소수점에 대한 방법을 제안 할 수 있으면 좋을 것이다. 예 저는 5 명의 연산자 만 사용하고 있습니다. + - * /와 % –

답변

1

내가 배운 프로그래밍 (오래 전에 ...) 선생님이 무엇을 선명해질 때까지 코드로 시작하지 "라고 당신은 올바른 분석으로 달성하기를 원한다 "고 말했다. 내가 제대로 이해하면 다섯 사업자와 함께, 계산기를 구축 - 문법 다음 다음과 (+/* %) :

expr : number 
    | operator expr expr 

with the following lexical tokens : 

operator: single character among +-*/% 
number: consecutive sequence of decimal digits ([0-9]*) 
not printing characters (space, tab, \r, \n) are used as delimiters or otherwise ignored 

any other character causes an error. 

확인 : 나중에 진수를 사용하려는 경우 즉, 현재 사양의 당신 하나의 선택적 소수점을 허용하도록 숫자 정의를 변경해야합니다.

그런 식으로 작성하면 lex와 yacc를 사용하기가 쉽지만 간단한 문법의 경우에는 분명히 과장입니다. +12은 동일 (12)

그래서 당신이 사용하여 간단한 렉서를 구축해야하기 때문에 : 그것은 자동으로 + 표지판을 먹는 것 때문에 우리가 구분 기호로 공백을 정의하더라도

, 토큰을 얻을 수 scanf을 사용할 수 없습니다 토큰을 반환하는 getc 및 재귀 적으로 표현식을 계산하는 파서. 배열에 아무것도 저장하기위한 필요 : 사업자 및 정수, 어쩌면 부동 소수점 숫자 나 (변수 나 함수의) 이름 :

typedef struct _token { 
    enum {OPERATOR, INT, END, ERROR } type; 
    union { 
     int ival; 
     char op; 
    } value; 
} TOKEN; 

TOKEN getToken(FILE *fdin) { 
    static const char valid_op[] = "+-*/%"; 
    static const char spaces[] = " \t\r\n"; 
    int c; 
    TOKEN tok; 
    int val = 0; 
    int isval = 0; 
    while ((c = getc(fdin)) != EOF) { 
     if ((c >= '0') && (c <= '9')) { 
      val = 10 * val + (c - '0'); 
      isval = 1; 
     } 
     else if (isval != 0) { 
      tok.type = INT; 
      tok.value.ival = val; 
      ungetc(c, fdin); 
      return tok; 
     } 
     else if (strchr(valid_op, c)) { 
      tok.type = OPERATOR; 
      tok.value.op = c; 
      return tok; 
     } 
     else if (! strchr(spaces, c)) { 
      tok.type = ERROR; 
      return tok; 
     } 
    } 
    tok.type = END; 
    return tok; 
} 

int parse(FILE *fdin, int *typ) { 
    int i, j; 
    *typ = INT; 
    for(;;) { 
     TOKEN tok = getToken(fdin); 
     if (tok.type == INT) { 
      return tok.value.ival; 
     } 
     else if (tok.type == OPERATOR) { 
      i = parse(fdin, typ); 
      if (*typ != INT) { 
       *typ = ERROR; 
       return 0; 
      } 
      j = parse(fdin, typ); 
      if (*typ != INT) { 
       *typ = ERROR; 
       return 0; 
      } 
      switch(tok.value.op) { 
       case '+': return i+j; 
       case '-': return i-j; 
       case '*': return i*j; 
       case '/': return i/j; 
       case '%': return i * j/100; 
      } 
     } 
     else { 
      *typ = tok.type; 
      return 0; 
     } 
    } 
} 
0

사용

  1. fgets() 라인의 끝까지 읽을 수 있습니다.
  2. 줄을 구문 분석하고 줄을 구분 기호로 사용하여 strtok()을 사용하여 토큰으로 나눕니다.
  3. 각 토큰이 char 또는 digit인지 확인하십시오. 토큰이 숫자인지 여부를 확인하는 방법은 여러 가지가 있습니다. 이것은 당신이 0character 사이의 차이를 확인하는 데 도움이 될 것입니다 정수로 토큰을 변환하는 strtol()를 사용
+0

당신은 코드의 일부를 사용하여 그것을 시연 해 주시겠습니까? stdin과 fgets의 문맥에서 fgets()를 사용하는 방법은 char 배열에 대한 포인터를 입력 인수로 사용하여 그것을 처리하는 법을 가르쳐줍니다. –

+0

@DeepankarSingh pasring 후 입력의 각 toekn으로 무엇을하고 싶은지 말해 줄 수 있습니까? – Gopi

+0

나는 문자 (연산자)와 정수 (피연산자)를 기반으로 산술 계산을 수행하고자합니다. –

1

당신은 다양한 유형의 데이터를 저장할 수있는 데이터 유형을 필요가 없습니다.

C의 일반적인 접근 방식은 union을 사용하는 것으로 동일한 공간에서 여러 유형을 유지할 수 있습니다. 한 번에 하나의 유형 만 사용할 수 있으므로 enum을 사용하여 활성화 된 유형을 나타내는 방법이 필요합니다. 그런 다음 enumunionstruct에 포장하여 서로 가깝게 정리하십시오.

다음은 데이터 유형의 구현 예입니다.그것은 어떤 연산도하지 않으며, 단지 문자열을 파싱하고 토큰을 인쇄합니다.

예에서와 같이 모든 토큰은 공백으로 구분해야 strtok을 찾을 수 있습니다. 5/2을 세 개의 토큰으로 인식하려면 Serge Ballesta가 매우 체계적인 대답으로 제안한 것처럼 렉서를 작성할 수 있습니다. 아래 구현은 -1과 같은 음수를 인식하지 못합니다. 오류 처리도 매우 기본입니다.

이 코드는 여전히 해결책을 출발점으로 서비스를 제공 할 수 :

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

enum Type {      /* enumeration of possible types */ 
    Operator,  
    Integer, 
    Float, 
    Name, 
    Illegal 
}; 

struct Token { 
    enum Type type;    /* token type */ 
    union {      /* mutually exclusive data fields */ 
     long long int l;  /* ... for Integer */ 
     double x;    /* ... for Float */ 
     char name[20];   /* ... for Name and Operator */ 
    } data; 
}; 

struct Token illegal(const char *str) 
{ 
    struct Token tk = {Illegal}; 

    snprintf(tk.data.name, 20, "%s", str); 
    return tk; 
} 

struct Token parse(const char *str) 
{ 
    struct Token tk = {Illegal}; 

    if (strchr("+-*/%", *str)) { 
     if (str[1]) return illegal("Overlong operator"); 
     tk.type = Operator; 
     strcpy(tk.data.name, str); 
     return tk; 
    } 

    if (isdigit(*str)) { 
     double x; 
     long long l; 
     char *end; 

     l = strtoll(str, &end, 0); 
     if (end != str && *end == '\0') { 
      tk.type = Integer; 
      tk.data.l = l;  
      return tk; 
     } 

     x = strtod(str, &end); 
     if (end != str && *end == '\0') { 
      tk.type = Float; 
      tk.data.x = x;  
      return tk; 
     } 

     return illegal("Illegal number"); 
    } 

    if (isalpha(*str)) { 
     const char *p = str; 

     while (*p) { 
      if (!isalnum(*p++)) return illegal("Illegal name"); 
     } 
     tk.type = Name; 
     snprintf(tk.data.name, 20, "%s", str);   
     return tk; 
    } 

    return illegal("Illegal character"); 
} 

int split(struct Token tk[], int max, char *str) 
{ 
    int n = 0; 
    char *p; 

    p = strtok(str, " \t\n"); 
    while (p) { 
     struct Token curr = parse(p); 

     if (curr.type == Illegal) { 
      fprintf(stderr, "Parse error: %s.\n", curr.data.name); 
      return -1; 
     } 

     if (n < max) tk[n] = curr; 
     n++; 

     p = strtok(NULL, " \t\n"); 
    } 

    return n; 
} 

void print(struct Token tk) 
{ 
    switch (tk.type) { 
    case Operator: printf("operator %c\n", tk.data.name[0]); 
        break; 
    case Integer: printf("integer %lld\n", tk.data.l); 
        break; 
    case Float:  printf("float %g\n", tk.data.x); 
        break; 
    case Name:  printf("name \"%s\"\n", tk.data.name); 
        break; 
    default:  printf("illegal token\n"); 
    } 
} 

int main() 
{ 
    char line[] = "- + 2 * alpha beta/12.0 6"; 
    struct Token tk[20]; 
    int i, n; 

    n = split(tk, 20, line); 
    for (i = 0; i < n; i++) { 
     print(tk[i]); 
    } 

    return 0; 
}