0

这是我坚持的实验室任务。

我需要接受这个语法(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();

}
4

4 回答 4

12

我会为此感到遗憾,但每次我看到这个问题时,我都会发现您的代码有其他问题。这是一行一行的。我大概错过了很多。

此标头的正确名称是“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为指针,没有分配内存,稍后您写入未定义的内存位。这是未定义的行为,您几乎肯定会崩溃。我建议,您应该定义strstd::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,只需使用它并将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();

}
于 2009-08-29T10:05:03.843 回答
6

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

  • 0 = 开始
  • 1 = '收到 (ab)'
  • 2 = '收到 b of (ab)'
  • 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);
}
于 2009-08-29T09:35:57.240 回答
4

您的代码有问题:

#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 的东西来代替它。

于 2009-08-29T09:56:33.127 回答
1

不要这样做!

enum track {true, false};

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

不过,这只是一个猜测。也许还有其他重要的事情。

于 2009-08-29T09:37:34.960 回答