繁体   English   中英

在C ++中接受语法

[英]Accepting a grammar in C++

这是我坚持的实验任务。

我需要接受这种语法(ab)*b ,这基本上意味着任何数量的“ ab”并以b结尾。

我已经写了这段代码,但是不知何故,它只检查前两个字母。

#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();

}

我会为此感到后悔,但是每次我看到这个问题时,我都会发现您的代码有其他问题。 这是一行一行。 我可能很想念。

此标头的正确名称是“ iostream”,而不是“ iostream.h”-不推荐使用“ .h”版本。 同样,在现代C ++中使用“ string”,而不是“ string.h”,并使用现代STL字符串类。

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

如前所述,不要这样做。 您已重新定义标准bool类型,使其具有与标准类型相反的值。 我什至不知道这是合法的。

enum track {true, false};

main函数的返回值是int ,而不是void

void main()    
{
    clrscr();

您知道什么是缓冲区溢出吗? 您已在此处将str定义为指针,没有分配的内存,稍后再写入该未定义的内存。 这是不确定的行为,几乎可以保证会崩溃。 我建议,您应该将str定义为std::string这样可以很好地避免缓冲区溢出,并且它具有许多可以在程序中使用的有用方法。

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

这是缓冲区溢出。 您正在写信给谁知道内存的哪个区域。

    cin>>str;

如果strstd::string您将执行size_t len=str.length() ;

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

将这样的控制台IO功能与iostreams功能混合使用可能不是一个好主意-有些缓冲问题可能会导致困难。

    getch();

在循环的主体中声明i ,因为您不再使用它。 像这样:

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

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

由于您要跟踪i当前字符的索引,因此不必使用poiter算术,只需使用它并将str视为数组即可。 这样一来,你就不必保持str中同步与i通过所有的方式。 顺便说一下,这就是导致您报告错误的原因。

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

您应该将其更改为:

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

(顺便说一下,即使strstd::string ,它也可以工作,与指针算术版本不同)。

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

您确实应该在某个时候退出,如果您发现字符串不匹配,那么在字符串末尾就没有意义了。

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

我不喜欢这样的状态标志-由于这些标志的泛滥,部分原因使您的代码难以理解,因此您无法跟踪正确的行为。 名称track_pos不是助记符,这使得在没有详细研究代码的情况下很难弄清其含义。

我建议您在for循环的主体内重构代码以调用一个函数,该函数的目的仅仅是匹配单个“ ab”组-该函数可以返回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循环,我们已经遍历了整个字符串,因此我们必须经过字符串的末尾(即使忽略缓冲区溢出),因此该测试无法成功。 简而言之,您的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();

}

实现一个简单的状态机。 它具有以下状态:

  • 0 =开始
  • 1 ='收到(ab)的a'
  • 2 ='收到(ab)的b'
  • 3 ='收到的决赛b'
  • -1 =错误,语法无效

然后,您只需要这样的功能:

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;
}

从状态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);
}

您的代码有问题:

#include <iostream.h>

应该:

#include <iostream>

以下是非标准(且非常旧)的标头:

#include <conio.h>

以下是非法的-true和false是保留字。

enum track {true, false};

在C和C ++中,main必须返回一个int:

void main()

非标准功能:

clrscr();

没有内存分配给该指针:

char*str;

然后在此处使用-结果不确定的行为:

cin>>str;

非法致电main:

    main();

我怀疑您正在使用非常老旧的C ++编译器。 您应该用MinGW之类的东西代替它。

不要这样!

enum track {true, false};

在这里,您的true等于0,false等于1! 以后分配track_pos时,可能会得到错误的值! (因为将bool转换为int时,true转换为1,false转换为0。)

不过,这只是一个猜测。 也许这很重要。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM