2016-11-02 7 views
1

main() 함수에서 out[0] = '\0';의 이유는 무엇입니까?K & R - 재귀 적 파서 파서 - strcat

그것 없이는 작동하지 않는 것 같습니다.

코드

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

#define MAXTOKEN 100 
enum { NAME, PARENS, BRACKETS }; 

int tokentype; 
char token[MAXTOKEN]; /*last token string */ 
char name[MAXTOKEN]; /*identifier name */ 
char datatype[MAXTOKEN]; /*data type = char, int, etc. */ 
char out[1000]; 

void dcl(void); 
void dirdcl(void); 
int gettoken(void); 

/* 
Grammar: 

    dcl:   optional * direct-dcl 
    direct-dcl:  name 
        (dcl) 
        direct-dcl() 
        direct-dcl[optional size] 
*/ 

int main() /* convert declaration to words */ 
{ 
    while (gettoken() != EOF) { /* 1st token on line */ 

     /* 1. gettoken() gets the datatype from the token */ 
     strcpy(datatype, token); 

     /* 2. Init out to end of the line? */ 
     /* out[0] = '\0'; */ 

     /* parse rest of line */ 
     dcl(); 

     if (tokentype != '\n') 
      printf("syntax error\n"); 

     printf("%s: %s %s\n", name, out, datatype); 
    } 

    return 0; 
} 

int gettoken(void) /* return next token */ 
{ 
    int c, getch(void); 
    void ungetch(int); 
    char *p = token; 

    /* Skip blank spaces and tabs */ 
    while ((c = getch()) == ' ' || c == '\t') 
     ; 

    if (c == '(') { 

     if ((c = getch()) == ')') { 

      strcpy(token, "()"); 
      return tokentype = PARENS; 

     } else { 
      ungetch(c); 
      return tokentype = '('; 
     } 

    } else if (c == '[') { 

     for (*p++ = c; (*p++ = getch()) != ']';) 
      ; 

     *p = '\0'; 
     return tokentype = BRACKETS; 

    } else if (isalpha(c)) { 

     /* Reads the next character of input */ 
     for (*p++ = c; isalnum(c = getch());) { 
      *p++ = c; 
     } 

     *p = '\0'; 
     ungetch(c); /* Get back the space, tab */ 

     return tokentype = NAME; 

    } else 
     return tokentype = c; 
} 

/* dcl: parse a declarator */ 
void dcl(void) 
{ 
    int ns; 

    for (ns = 0; gettoken() == '*';) /* count *'s */ 
     ns++; 

    dirdcl(); 

    while (ns-- > 0) 
     strcat(out, " pointer to"); 
} 

/* dirdcl: parse a direct declarator */ 
void dirdcl(void) 
{ 
    int type; 

    if (tokentype == '(') { 

     dcl(); 

     if (tokentype != ')') 
      printf("error: missing)\n"); 

    } 
    else if (tokentype == NAME) /* variable name */ { 
     strcpy(name, token); 
     printf("token: %s\n", token); 
    } 
    else 
     printf("error: expected name or (dcl)\n"); 

    while ((type = gettoken()) == PARENS || type == BRACKETS) { 

     if (type == PARENS) 
      strcat(out, " function returning"); 
     else { 
      strcat(out, " array"); 
      strcat(out, token); 
      strcat(out, " of"); 
     } 

    } 
} 
+1

왜냐하면'strcat'은 NUL 종료 문자열을 원하기 때문에 (이 경우 글로벌 변수로) {0}으로 초기화됩니다. –

+0

두 줄의 입력을 시도해보십시오. –

+1

@Keine 정적 저장 기간이 있으므로 자동으로 0으로 초기화됩니다. –

답변

2

당신은 strcat이 작동하기 위해서는 제로가 될 out[0]이 필요합니다. 같은 out[] 정적 배열은, 모두 0으로 초기화되기 때문에

이 줄

out[0] = '\0'; 

이 정적 초기화 규칙의 도입 이전에 필요한 동안

, 그것은 더 이상 필요하지 않습니다. 이 연산 유형이 있는지 initialization rules of C99 따르면

,

  • ...
  • , 그것은 영 (양 또는 부호)으로 초기화된다.
  • 집계 인 경우 모든 구성원은이 규칙에 따라 (재귀 적으로) 초기화됩니다.
+0

나는 왜 처음에'\ 0' 문자를 초기화 하겠는가? 비슷하게 보이지는 않을 것이다.'strcat (out, "abc");'out = { '\ 0', 'a', 'b', 'c'}'? – dud3

+0

@ dud3 아니요, ''\ 0 ''은 null 종결 자 *로 간주되므로 '\ 0'을 첫 문자로 사용하는 문자열은 '\ 0'뒤에 어떤 문자가 있더라도 빈 문자열처럼 동작합니다 . – dasblinkenlight

+0

아 이제 보았습니다. 대신 간단히 out [0] = '''으로 초기화 할 수 없었습니까? – dud3

1

char 배열 (일명 문자열)을 빈 배열로 재설정 중입니다. 그래서 정크 값이 0 인덱스에

을 그러니 그냥 '\ 0'을 추가하지

i += 1; 

: 같은 일을하기 전에

int i = 0; 

: 우리가 사용하는 처럼 (정크 값을 제거) 배열의 다른 인덱스에 정크 값을 쓰는 것보다 배열이 완전히 비어 있고 strcat 함수가 0 인덱스에서 값을 추가하기 시작한다는 것을 알립니다.

배열을 재설정하지 않고 프로그램이 작동하면 IDE 도구가이를 수행하고 있음을 의미하지만 다시 설정하는 것이 좋습니다.

1

간단히 말해서,이 특별한 경우에는 꼭 필요한 것은 아니지만 다른 많은 경우에는 의심스럽게 유사하게 보입니다. 따라서 대부분의 사람들은 그것을 "좋은 스타일"로 간주합니다. 그렇다면 왜 그럴 필요가 있을까요?

"빈 메모리"같은 것은 없습니다. "길이"같은 것이 없습니다. 명시 적으로 추적하지 않거나 자신을 정의하지 않는 한.

메모리는 0부터 255까지의 숫자입니다. 0은 255와 같이 유효한 숫자이기 때문에 바이트가 사용되는지 여부를 알 수있는 방법이 없습니다. 더 큰 숫자가 필요하다면 몇 바이트를 더할 수 있지만 결국 모든 것이 바이트로 만들어집니다. 텍스트는 단순히 숫자에 매핑됩니다. 몇 십 년 전 어느 숫자가 어떤 문자를 나타내는 지 결정되었습니다. 따라서 값이 32 인 바이트를 보면 32가 될 수 있습니다. 또는 컴퓨터의 알파벳 (공백 문자)의 32 번째 문자가 될 수 있습니다.

문자열을 받았는데 처리 할 텍스트의 양을 모르는 경우 대개 큰 바이트 블록을 예약하는 것이 일반적입니다. 위의 내용은 char out[1000];입니다.그러나 텍스트가 끝나는 위치를 어떻게 알 수 있습니까? 이미 사용한 1000 바이트 중 얼마입니까?

예전에는 어떤 사람들은 다른 변수, 예를 들어 int length;을 선언하고 지금까지 사용 된 바이트 수를 추적합니다. C의 디자이너는 다른 경로를갔습니다. 그들은 매우 드문 캐릭터를 골라서 마커로 사용하기로 결정했습니다. 그들은 0이라는 문자로 문자를 선택했습니다 (문자 '0'이 아니며 '0'문자는 실제로 컴퓨터의 알파벳의 48 번째 문자입니다).

문자열의 처음부터 모든 바이트를 볼 수 있으며 문자가 0보다 큰 경우 사용 된 것을 알 수 있습니다. 0 문자에 도달하면 이것이 문자열의 끝임을 알게됩니다. 두 가지 방법 모두 다양한 이점이 있습니다. int은 4 바이트를 사용하며 추가 0 문자 만 1을 사용합니다. 반면에 int를 사용하면 문자열에도 0 문자가 포함될 수 있습니다. 단지 다른 문자 일 뿐이므로 아무도 신경 쓰지 않습니다.

당신이 C에서 "foo" 쓰기 할 때마다

, 무슨 (C) 실제로하는 일은 'f', 'o', 'o' 4 바이트를위한 예비 공간이며, 0의 끝을 나타냅니다. C에서 ""을 쓸 때, 그것은 하나의 바이트를위한 예비 공간 인 0입니다. 문자열이 비어 있음을 알 수 있습니다.

그래서 시작할 때 뭔가를 입력하기 전에 채워지는 메모리는 무엇입니까? 음, 대부분의 경우, 그냥 쓰레기입니다. 마지막으로 메모리를 사용했을 때 그 메모리에 있던 것이 무엇이든간에 (결국 RAM이 제한되어 있으므로 컴퓨터에서 하나의 응용 프로그램을 종료하면 그 다음에 실행되는 다음 응용 프로그램에서 메모리가 다시 사용될 수 있습니다). 이것들은 일반적으로 공통 문자 범위를 벗어나는 난수입니다.

strcatout으로 공백 문자열로 표시하려면 0 값 문자로 시작하는 메모리 블록을 지정해야합니다. 그냥 메모리를 그대로두면 임의의 문자가있을 수 있습니다. 버퍼에 "jbhasugaudq7e1723876123798dbkda 0 skno§§ ^^ % $ # - 9H 0 HWDZmwus 0/usr/local/bin" 또는 이전에 그 메모리에 있던 내용이 포함될 수 있습니다. 이제 일부 텍스트를 추가 한 경우 첫 번째 0 (이 장소에서 무작위로 나타남) 앞의 내용이 유효한 문자열이며 이라는 내용이 추가됩니다. 0을 처음 시작할 때이 문자열이 비어 있어야한다는 것을 알 수 있습니다.

그렇다면 내가 왜 "꼭 필요한 것은 아닙니다"라고 말했습니까? 귀하의 경우에는 out이 전역 변수이므로 전역 변수는 응용 프로그램이 시작될 때 자동으로 0으로 지워지거나 선언 할 때 할당 한 값이 할당되므로 특별합니다.

그러나 이는 전역 변수 (일반 전역 변수 및 static 전역 변수)에만 해당됩니다. 많은 프로그래머는 항상 바이트 블록을 초기화하는 습관을 갖습니다. 그런 식으로 나중에 전역 변수를 로컬 변수로 변경하거나 로컬 변수와 함께 사용할 코드를 다른 곳으로 복사하여 붙여 넣기로 결정하면이 구문을 추가하는 것을 잊어 버릴 염려가 없습니다.

이것은 특히 랜덤 메모리가 종종 0자를 포함하기 때문에 유용합니다. 따라서 이전에 어떤 프로그램을 사용했는지에 따라 초기에 0을 잊어 버린 것을 알지 못할 수도 있습니다. 나중에 사용자 중 한 명이이 응용 프로그램을 실행하면 문자열 시작 부분에 가비지가 생깁니다.

그 점이 다소 명확한가요?

+0

예, 많은 것을 명확히했습니다. – dud3

+0

strcat() 함수는 src 문자열을 dest 문자열에 추가하고 은 dest의 끝에있는 종료 널 바이트 ('\ 0')를 덮어 쓰고, 그런 다음 은 null 바이트를 종료합니다.이 바이트는 이미 처리했습니다. – dud3

+0

"Home \ 0"과 "work \ 0"이라는 두 개의 문자열이있을 때 (앞에서 얘기 한 \ 0이 '0'인 경우) 하나를 다른 것에 추가하면 "Home \ 0work ". C는 문자열이 \ 0으로 끝나기 때문에 \ 0과 같을 것이라고 생각합니다. 그렇다면 strcat이 어떻게 작동 할 수있는가 아닙니다. 대신 첫 번째 \ 0을 삭제 한 다음 나머지 부분을 추가하면 예상 한 "숙제"를 얻을 수 있습니다. 그런 다음 "\ 0"을 추가하여 문자열이 실제로 "작업"후에 끝난다는 것을 알 수 있습니다. 그러나 첫 번째 \ 0은 strcat가 "Home"의 길이를 아는 데 여전히 필요합니다. – uliwitness