【问题标题】:Why is there an error in my String class append() method?为什么我的 String 类 append() 方法中有错误?
【发布时间】:2020-07-20 05:52:52
【问题描述】:

我正在尝试实现一个String 类,但我发现我的append() 方法有一个错误。你能告诉我我做错了什么吗?我不允许使用任何标准库功能。我刚刚在打印输出中添加了<iostream>,以便查看答案。

这里是append()

void append(const String& s){
    char* temp;
    temp = new char[len+s.len];
    for(int i = 0; i < len; i++){
        temp[i] = str[i];
    }
    for(int i = 0; i < s.len; i++){
        temp[len + 1] = s.str[i];
    }
    str = temp;
}

这是我的完整代码:

#include <iostream>

using namespace std;

class String{
    public:
        char* str = nullptr;
        unsigned int len = 0;

        String() = default;

        String(const char* chars){
            if(chars){
                unsigned int i = 0;
                while(chars[i]){
                    i++;
                }
                len = i;
                str = new char[len];
                for(int j = 0; j < len; j++){
                    str[j] = chars[j];
                }
            }
        };

        String(const String& s){
            if(!s.isEmpty()){
                len = s.len;
                str = new char[len];
                for(int i = 0; i < len; i++){
                    str[i] = s.str[i];
                }
            }
        };

        ~String() noexcept{
            delete[] str;
        };

        String& operator=(const String &s) {
            if (&s != this) {
                String tmp(s);
                char *tmpstr = tmp.str;
                unsigned int tmplen = tmp.len;
                tmp.str = str;
                tmp.len = len;
                str = tmpstr;
                len = tmplen;
            }
            return *this;
        }

        void append(const String& s){
            char* temp;
            temp = new char[len+s.len];
            for(int i = 0; i < len; i++){
                temp[i] = str[i];
            }
            for(int i = 0; i < s.len; i++){
                temp[len + 1] = s.str[i];
            }
            str = temp;
        }

        bool isEmpty() const noexcept{
            return(len == 0);
        }

        unsigned int length() const noexcept{
            return len;
        }

        bool contains(const String& substring) const noexcept{
            if(find(substring)){
                return true;
            }
            return false;
        }

        int find(const String& substring) const noexcept{
            for(int i = 0; i < len - substring.len + 1; i++){
                if(str[i] == substring.str[0]){
                    for(int j = 1; j < substring.len;){
                        if(str[i + j] == substring.str[j]){
                            j++;
                            if(j == substring.len){
                                return i;
                            }
                        }
                        else{
                            break;
                        }
                    }
                }
            }
            return -1;
        }

        const char* toChars() const noexcept{
            char* temp = new char[len + 1];
            for(unsigned int c = 0; c < len; ++c) {
                temp[c] = str[c];
            }
            temp[len] = '\0';
            return temp;
        }
};

int main()
{
    const char* chars = "Boo is snoring1";
    const char* morechars = " and running";

    String s(chars);
    String more(morechars);
    s.append(more);

    cout << s.str << endl;

    return 0;
}

【问题讨论】:

  • 究竟是什么错误?

标签: c++ string class


【解决方案1】:

您的第二个循环未正确访问temp。您正在使用temp[len + 1],但您需要改用temp[len + i]。这就是为什么您应该为变量使用更有意义的名称。 1i不可互换,但在视觉上非常接近,容易混淆。

另外,在用新数据替换之前,您不会释放以前的 str。并且您在替换 str 后不会更新 len

试试这个:

void append(const String& s){
    char* temp = new char[len + s.len];
    for(int idx = 0; idx < len; ++idx){
        temp[idx] = str[idx];
    }
    for(int idx = 0; idx < s.len; ++idx){
        temp[len + idx] = s.str[idx];
    }
    delete[] str;
    str = temp;
    len += s.len;
}

除此之外,您已经更改了您的main(),因为您的last question 直接打印出str,但str 不是以空值终止的。所以你需要像这样打印出来:

int main()
{
    String s("Boo is snoring1");
    s.append(" and running");

    cout.write(s.str, s.len);
    cout << endl;

    return 0;
}

否则,就像我之前向您展示的那样,返回打印 toChars() 的结果:

const char *chars = s.toChars();
cout << chars << endl; 
delete[] chars;

否则,您应该定义自己的operator&lt;&lt; 以打印出String 对象:

std::ostream& operator<<(std::ostream &os, const String &s)
{
    return os.write(s.str, s.len);
}

...

cout << s << endl; 

【讨论】:

    【解决方案2】:

    你的第二个循环应该temp[len + i] 而不是temp[len + 1]

    【讨论】:

      【解决方案3】:

      对于初学者来说,函数 append 存在内存泄漏,因为前一个指针没有被删除。并且数据成员len的新值没有设置。

      void append(const String& s){
                  char* temp;
                  temp = new char[len+s.len];
                  for(int i = 0; i < len; i++){
                      temp[i] = str[i];
                  }
                  for(int i = 0; i < s.len; i++){
                      temp[len + 1] = s.str[i];
                  }
                  str = temp;
              }
      

      在第二个循环中

              for(int i = 0; i < s.len; i++){
                  temp[len + 1] = s.str[i];
              }
      

      有一个错字。你的意思是

      temp[len + i] = s.str[i];
                ^^^
      

      第三,你正在像 C 字符串一样输出字符串

      cout << s.str << endl
      

      这意味着指向的字符串应具有终止零字符。

      数据成员strlen 应为私有数据成员。并且数据成员len 的类型应该是size_t

          char* str = nullptr;
          unsigned int len = 0;
      

      此外,在循环中,您使用的是int 类型的索引,而不是unsigned int 类型。

      所以实际上整个类的定义是错误的。

      至于函数 append 那么它至少应该定义如下。我假设指向的数组包含字符串。

      String & append( const String &s )
      {
          char* temp = new char[len + s.len + 1];
      
          size_t i = 0;
      
          for ( ; i < len; i++ ) temp[i] = str[i];
          while ( ( temp[i] = s.str[i-len] ) != '\0' ) i++;
      
          delete [] str;
      
          str = temp;
          len = len + s.len;
      
          return *this; 
      }
      

      注意默认构造函数分配一个大小为1的内存,并将分配的字节设置为'\0'。在这种情况下,数据成员len 应设置为0

      所以检查所有其他成员函数。例如,当传递的字符串的数据成员 len 等于 0 时,成员函数 find 将具有未定义的行为。

      【讨论】:

        猜你喜欢
        • 2021-12-12
        • 2014-02-10
        • 2011-06-20
        • 1970-01-01
        • 2021-09-15
        • 2014-12-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多