2009-08-29 7 views
0

이것은 실험실 과제입니다.C++에서 문법 수락

이 문법은 기본적으로 "ab"이고 b로 끝나는 임의의 수를 의미하는 (ab)*b을 받아 들일 필요가 있습니다.

이 코드를 작성했지만 어쨌든 처음 2 자만 검사합니다.

#include <iostream.h> 
#include <conio.h> 
#include <string.h> 

enum track {true, false}; 

void main() 

{ 
    clrscr(); 
    char*str; 
    enum track track_pos, track_pos_2; 
    cout<<"enter the string: "; 
    cin>>str; 
    int len=strlen(str); 
    cout<<"length of the string is "<<len; 
    getch(); 
    int i; 
    for(i=0;i<len; i++) 
    { 
     ++str; 
     cout<<"loop"<<i; 
     if(*str=='a' && i%2==0) 
     { 
      cout<<"\nchecking a..."; 
      track_pos=true; 
      cout<<"\na.check"; 
      ++str; 
      if (*str=='b') 
       { 
       cout<<"\nchecking b..."; 
       track_pos=true; 
       cout<<"\nb.check"; 
      } 
      else{ 
       track_pos=false; 
       cout<<"\nb.uncheck"; 
      } 
     } 

    } 

    if(*str=='b') 
     track_pos_2=true; 
    else 
     track_pos_2=false; 

    if(track_pos==true && track_pos_2==true) 
     cout<<"\nThe string is accpeted."; 
    else 
     cout<<"\nThe string is rejected."; 

    getch(); 
    cout<<"\n\nDo you want to continue (Y/N)? "; 
    char ch; 
    cin>>ch; 
    if(ch=='y' || ch=='Y') 
     main(); 

} 
+0

가 나는 그것이 가장 쉬운 방법 밖으로이었다 main' :-) –

+0

'재귀를 볼 수있는 처음 ... :) – amit

+1

그것은 ++ 그것은 C에서 불법 난독 C 코드 경쟁 항목 –

답변

12

나는 이것을 후회할 것이다. 그러나이 질문을 볼 때마다 나는 당신의 코드에 뭔가 다른 것을 본다. 다음은 한 줄씩입니다. 나는 아마 많은 것을 놓쳤다.

이 헤더의 올바른 이름은 "iostream.h"가 아니라 "iostream.h"이며 ".h"버전은 더 이상 사용되지 않습니다. 마찬가지로 현대 C++에서는 "string.h"가 아닌 "string"을 사용하고 현대 STL 문자열 클래스를 사용하십시오.

#include <iostream.h> 
#include <conio.h> 
#include <string.h> 

지적한대로이 작업을 수행하지 마십시오. 유형 bool 표준을 다시 정의하여 표준 유형과 반대 값을 갖습니다. 나는 이것이 합법적인지조차 모른다.

enum track {true, false}; 
main

함수의 리턴 값은 int하지 void이다.

void main()  
{ 
    clrscr(); 

버퍼 오버 플로우 란 무엇입니까? 할당 된 메모리가없는 포인터로 str을 여기에 정의했으며, 나중에 그 정의되지 않은 메모리 비트에 기록합니다. 이것은 정의되지 않은 동작이며 충돌 가능성이 거의 없습니다. 추천 할만한 점은 strstd::string으로 정의해야합니다. 버퍼 오버플로를 방지하고 프로그램에서 사용할 수있는 유용한 메소드가 많이 있습니다.

char*str; 
    enum track track_pos, track_pos_2; 
    cout<<"enter the string: "; 

여기가 버퍼 오버 플로우입니다. 당신은 누가 어떤 분야의 기억인지 아는 사람에게 편지를 쓰고 있습니다. strstd::string했다

cin>>str; 

경우 - 당신은 size_t len=str.length() 할 것;

int len=strlen(str); 
    cout<<"length of the string is "<<len; 

그것은 아마 IOSTREAMS 기능과 같은 콘솔 IO 기능을 혼합하는 것은 좋은 생각이 아니다 - 어려움으로 이어질 수있는 몇 가지 버퍼링 문제가 있습니다. 당신이 다시 사용되지 않기 때문에

getch(); 

는 루프의 본문에 i를 선언합니다.과 같이 대신 당신이 i에서 현재의 문자의 인덱스를 추적하기 때문에 그냥 사용하고 배열로 str 치료, poiter 연산을 사용

for (int i=0; i<len; i++) etc... 

    int i; 
    for(i=0;i<len; i++) 
    { 

. 이렇게하면 stri과 동기화 할 필요가 없습니다. 이것은보고하는 버그의 원인입니다. (즉 str는 포인터 연산 버전과는 달리 방법에 의한 std::string 경우에도 작동)

 if (str[i]=='a' && i%2==0) 

:

 ++str; 
     cout<<"loop"<<i; 

당신은이를 변경해야합니다.

 if(*str=='a' && i%2==0) 
     { 

당신은 정말 문자열이 일치하지 않음을 파악하는 경우, 다음 문자열의 끝으로가는 아무 소용이 없다, 어떤 점에서 탈락한다.

   cout<<"\nchecking a..."; 

이 같은 상태 플래그를 선호하지 않는다 - 당신의 코드가 이러한 플래그의 확산, 당신은 적절한 행동을 추적 할 수 없기 때문에 이해하기 위해 부분적으로 단단하다. track_pos이라는 이름은 니모닉이 아니므로 코드에 대한 세부 연구 없이는 의미가 무엇인지 알아내는 것이 어렵습니다.

for 루프의 본문에있는 코드를 리팩토링하여 함수를 호출하는 것이 좋습니다. 그 목적은 단순히 "ab"그룹 하나와 일치시키는 것입니다.이 함수는 true이면 true를 반환하고, 그렇지 않은 경우 false입니다. 우리가 전에 언급 한 버퍼 오버 플로우를 처리하기 때문에, 당신은 정의되지 않은 메모리를 반복하는 것을

   track_pos=true; 
       cout<<"\na.check"; 

참고. 또한 여기에 i을 증가시키지 않았 음을 유의하십시오. 우리가 여기에 도착하면

   ++str; 
       if (*str=='b') 
         { 
         cout<<"\nchecking b..."; 
         track_pos=true; 
         cout<<"\nb.check"; 
       } 
       else{ 
         track_pos=false; 
         cout<<"\nb.uncheck"; 
       } 
     } 

    } 

은에 따라 루프, 우리는 전체 문자열을 반복했다, 그래서 우리는 (심지어 버퍼 오버 플로우를 무시) 문자열의 끝을지나보고해야합니다 그래서 수있는 방법은 없습니다 이 테스트는 성공할 수 있습니다. 즉, for 루프가 너무 멀리 떨어져 있어야합니다.

if(*str=='b') 
     track_pos_2=true; 
    else 
     track_pos_2=false; 

    if(track_pos==true && track_pos_2==true) 

철자 오류를 언급해야합니까?

 cout<<"\nThe string is accpeted."; 
    else 
     cout<<"\nThe string is rejected."; 

    getch(); 
    cout<<"\n\nDo you want to continue (Y/N)? "; 
    char ch; 
    cin>>ch; 

코드를 적절한 서브 루틴으로 리팩토링하면 프로그램의 구조가 스스로 처리됩니다. main을 재귀 적으로 호출하는 것은 엄격히 불법은 아니지만 이상하게 보일 수 있으며 프로그램이 종료되지 않는 경우 스택 오버플로가 발생할 수있는 명백한 취약점이 있습니다.

if(ch=='y' || ch=='Y') 
     main(); 

} 
+5

"최종 스택 오버 플로우로 이어질 수있는"취약점 - 그의 프로그램은 이미 스택 오버 플로우로 이끌었습니다. 닷 컴. –

+0

http://instantrimshot.com/ –

+0

나는이 답변을 게시 한 동료의 끈기에 감탄해야합니다. –

6

간단한 상태 시스템을 구현하십시오.

  • 0 =
  • 1 =
  • 2 = '의 b를 수신 (AB) "
  • 3 ='최종 B를 수신 '(AB)의 완료'시작 : 이들 상태가

    int nextState(int currentState, char inputChar) { 
        if (currentState == 0 && inputChar == 'a') return 1; // handled string is "a" 
        if (currentState == 0 && inputChar == 'b') return 3; // handled string is "b" 
        if (currentState == 1 && inputChar == 'b') return 2; // handled string is "ab", or "abab", or ... 
        if (currentState == 2 && inputChar == 'a') return 1; // handled string is "aba", or "ababa", or ... 
        if (currentState == 2 && inputChar == 'b') return 3; // handled string is "abb", or "ababb", or ... 
        return -1; 
    } 
    
    :
  • -1 = 오류, 잘못된 문법

그런 다음 당신은 이런 기능이 필요합니다

상태 0부터 시작하여 입력 된 문자에 대해이 "상태 시스템"을 반복하고 상태 3에서 끝나면 입력이 유효합니다.

int isValid(char* inputString) { 
    int state = 0; 
    for(int i=0; i<str_len(inputString); i++) { 
    state = nextState(state, inputString[i]); 
    } 

    return (state == 3); 
} 
+3

여러 상태에 대한 열거 형을 사용하면 코드를보다 읽기 쉽고 유지 보수하기 쉽게 만듭니다.코딩을 시작하기 전에 종이에 상태 머신을 디자인하여 모든 다른 상태 전환이 덮여 있는지 확인하십시오. – steve

+0

바로 가기로 최종 b를 먼저 확인해야 할 수도 있습니다. – NomeN

+0

이것을 가능한 입력 값과 결과 상태의 다차원 배열로 바꿔 더 깨끗하게 만들 수 있습니다. 그러면 다음과 같습니다. return output [currentState] [inputChar]; 입력이 많으면 유용하지 않지만 코드를 변경하지 않고도 상태를 쉽게 추가 할 수 있습니다. 1800INFORMATION의 답변이 마음에 들었지만이 솔루션이 가장 좋습니다. –

1

Do not do this!

enum track {true, false}; 

여기에서 true는 0이고 false는 1과 같습니다. 나중에 track_pos를 지정하면 잘못된 값을 얻을 수 있습니다! (왜냐하면 bool을 int로 변환 할 때 true는 1로 변환하고 false는 0으로 변환하기 때문입니다.)

이것은 단지 추측입니다. 어쩌면 그것은 중요한 다른 것일 수 있습니다. 코드 문제

+2

잠깐, 뭐라구? 그걸 할 수 있니? –

+0

완전한 모양새의 C++ 프로그램 이니까, amit이 게시 한 것입니다. 그의 컴퓨터에서 그의 미친 컴파일러로 컴파일됩니다! 그래서 나는 그의 미친 컴파일러가 그걸로 무엇을 할 수 있었는지 짐작하려고합니다. –

4

것들 :

#include <iostream.h> 

은 다음과 같아야합니다

#include <iostream> 

다음은 비표준 (그리고 아주 오래된) 헤더 : 다음

#include <conio.h> 

불법입니다. 참 및 거짓은 예약어입니다.

C 및 C에서
enum track {true, false}; 

++, 주요 int를 반환해야합니다 :

void main() 

비 표준 기능 :

clrscr(); 

이 포인터에 할당 된 메모리가 없습니다 :

char*str; 

그런 다음 여기에서 사용됩니다 - 결과 및 efined 행동 :

cin>>str; 

불법 전화 주에 :

main(); 

나는 당신이 매우 오래되고 쓸모 C++ 컴파일러를 사용하고 생각한다. MinGW와 같은 것으로 교체해야합니다.