C++中的字符串串联有什么问题?

What's wrong with my String concatenation in C++?

本文关键字:什么 问题 字符串 C++      更新时间:2023-10-16

我正在通过为嵌入式项目创建一个字符串类来学习C++,但我的字符串类的连接有问题。

这是我的主要方法和输出

#include <iostream>
#include "string.hpp"
using namespace std;
int main() {
    String s1("hello "), s2("world");
    String s3 = s1 + s2;
    cout << "s1=" << s1 << endl;
    cout << "s2=" << s2 << endl;
    cout << "s3=" << s3 << endl;
    return 0;
}
s1=hello 
s2=world
s3=hello 

它不是打印出"hello world",而是打印"hello ">

这是我的string.hpp类:

#pragma once
#include <cstring>
#include <iostream>
class String {
public:
    String() : c_str(NULL), len(0)
    {
    }
    String(const String& str) : c_str(new char[str.len]), len(str.len)
    {
        strncpy(c_str, str.c_str, len);
        c_str[len] = '';
    }
    String(const char* str) : String(str, strlen(str))
    {
        strncpy(c_str, str, len);
        c_str[len] = '';
    }
    String(const char* str, const int n) : len(n), c_str(new char[n+1])
    {
        strncpy(c_str, str, len);
    }
    ~String()
    {
        delete[] c_str;
    }
    const char* get_c_str()
    {
        return c_str;
    }
    bool contains(const String &cmd, const size_t pos)
    {
        return strncmp(c_str+pos, cmd.c_str, cmd.len) == 0;
    }
    size_t length()
    {
        return len;
    }
    friend std::ostream& operator<<(std::ostream& os, const String obj)
    {
        os << obj.c_str;
        return os;
    }
    friend void swap(String& s1, String& s2)
    {
        using std::swap;
        swap(s1.c_str, s2.c_str);
        swap(s1.len, s2.len);
    }
    bool operator==(const String& str)
    {
        return strncmp(c_str, str.c_str, len) == 0;
    }
    char operator[](const size_t i)
    {
        return c_str[i];
    }
    String& operator=(const String& src)
    {
        String tmp(src);
        swap(*this, tmp);
        return *this;
    }
    String operator+(const String& rhs)
    {
        const size_t new_len = len + rhs.len;
        char* new_c_arr = new char[new_len+1];
        strcpy(new_c_arr, c_str);
        strcat(new_c_arr, rhs.c_str);
        printf("new_c_arr=%sn", new_c_arr);
        return String(new_c_arr, len);
    }
    String operator+(const char* rhs)
    {
        const size_t new_len = len + strlen(rhs) + 1;
        char* new_c_arr = new char[new_len];
        strcpy(new_c_arr, c_str);
        strcat(new_c_arr, rhs);
        return String(new_c_arr, new_len);
    }
private:
    char* c_str;
    int len;
};

我在寻找类似问题时在 SO 上阅读了"三巨头",但不确定是否正因为如此。

此代码以多种方式中断。

#pragma once

实际包括防护装置比#pragma once更便携。

    String() : c_str(NULL), len(0)
    {
    }

默认构造函数使c_str为 null;其他函数从不检查这种情况。请记住,即使是空的 C 字符串也只有一个字符。

    String(const String& str) : c_str(new char[str.len]), len(str.len)
    {
        strncpy(c_str, str.c_str, len);
        c_str[len] = '';
    }

您只为c_str分配了str.len个字符,但您正在访问c_str[len]

    String(const char* str) : String(str, strlen(str))
    {
        strncpy(c_str, str, len);
        c_str[len] = '';
    }

委派给的构造函数已执行复制。你怎么又把strncpy叫到这里来了?

    String(const char* str, const int n) : len(n), c_str(new char[n+1])
    {
        strncpy(c_str, str, len);
    }

在这里,您没有确保字符串以 null 结尾。

    const char* get_c_str()
    {
        return c_str;
    }

应标记为const

    bool contains(const String &cmd, const size_t pos)
    {
        return strncmp(c_str+pos, cmd.c_str, cmd.len) == 0;
    }

同上。而且您没有检查pos是否在范围内。

    size_t length()
    {
        return len;
    }

const .

    friend std::ostream& operator<<(std::ostream& os, const String obj)
    {
        os << obj.c_str;
        return os;
    }

obj应通过 const 引用传递,而不是通过值传递。

    bool operator==(const String& str)
    {
        return strncmp(c_str, str.c_str, len) == 0;
    }

const,逻辑甚至不正确。按照这个逻辑,"something" == "something else"因为你只是比较前len个字符。

    char operator[](const size_t i)
    {
        return c_str[i];
    }

如果您要返回副本,则应将其const。如果要允许用户修改字符串中存储的字符,则应返回char & 。(更好的是,有两个单独的重载,一个const和一个非const

    String operator+(const String& rhs)
    {
        const size_t new_len = len + rhs.len;
        char* new_c_arr = new char[new_len+1];
        strcpy(new_c_arr, c_str);
        strcat(new_c_arr, rhs.c_str);
        printf("new_c_arr=%sn", new_c_arr);
        return String(new_c_arr, len);
    }

您正在构造长度错误的新字符串,并且还泄漏了new_c_arr.并且这个函数应该是const的(并且真的应该在operator+=方面实现,而你没有(。

    String operator+(const char* rhs)
    {
        const size_t new_len = len + strlen(rhs) + 1;
        char* new_c_arr = new char[new_len];
        strcpy(new_c_arr, c_str);
        strcat(new_c_arr, rhs);
        return String(new_c_arr, new_len);
    }

再次泄漏new_c_arr;此外,此处new_len包括空终止符,而其他operator+中的版本不包含。采用长度的构造函数似乎不包括 null 终止符作为长度的一部分。

这是

方法String operator+(const String& rhs)中的问题行:

return String(new_c_arr, len);

您需要更改为以下内容:

return String(new_c_arr, new_len+1);

您正在初始化返回的字符串,其长度仅等于第一部分。不是整个串联的字符串。

看到另一个运算符是否正常。

顺便说一下,你在operator+constructor中创造了很多新的char[]

对于operator+,您在每次调用中创建一个新char[]并传递给字符串的构造函数(之后不删除(,并且在构造函数中创建一个新char[]来存储destructor中删除的字符串,在operators中创建的新char[]被泄漏。