Почему все тестовые примеры терпят неудачу, когда я запускаю эту программу в предоставленном тестовом примере Google?

Я пытаюсь запустить эту программу на предоставленных тестовых примерах Google, но все тестовые примеры терпят неудачу.

  • Функция String operator+(const char& str) const добавляет символ в конец строки.
  • Функция String operator+(const String& str) const добавляет строку в конец строки
  • Функция String operator+(char*& str) const добавляет строку в конец строки.

В чем проблема?

#include<iostream>
#include<string>
#include <cstdlib>

using namespace std;

class String
{
private:
    char* s;
    int size;
public:
    String()
    {
        s = NULL;
        size = 0;

    }
    String(const char* str)
    {
        size = strlen(str);
        s = new char[size];
        for (int i = 0; i < size; i++)
            s[i] = str[i];
    }
    String(const String& obj)
    {
        size = obj.size;
        s = new char[size];
        for (int i = 0; i < size; i++)
            s[i] = obj[i];
    }
    String(int x)
    {
        size = x;
        s = new char[size];
    }
    char& operator[](int i)
    {
        return *(s + i);
    }
    const char operator[](int i) const
    {
        return *(s + i);
    }
    String operator+(const char& str) const
    {
        String s1;
        s1.s += str;
        return s1;
    }
    operator int() const
    {
        int m;
        m = size;
        return m;
    }
    String operator+(const String& str) const
    {
        String iSt = "";
        int length = 0;
        length = strlen(s);
        length += strlen(str.s);
        iSt.s = new char[length];

        strcpy(iSt.s, s);
        strcat(iSt.s, str.s);

        return iSt;
    }
    String operator+(char*& str) const
    {
String iSt = "";
    int length = 0;
    length = strlen(s);
    length += strlen(str);

    iSt.s = new char[length];

    strcpy(iSt.s,s);
    strcat(iSt.s,str);

    return iSt;
    }
};
TEST(String, ArithmeticOperatorsplus) {
    String s1("abcd");

    String s2;
    s2 = s1 + 'e';
    ASSERT_EQ('d', s2[3]);
    ASSERT_EQ('e', s2[4]);
    char* c = (char*)"asdfgh";
    s2 = s1 + c;
    ASSERT_EQ('d', s2[3]);
    ASSERT_EQ('a', s2[4]);
    ASSERT_EQ('g', s2[8]);
    ASSERT_EQ(10, (int)s2);
    String s3 = s1 + s2;
    ASSERT_EQ(14, (int)s3);
    ASSERT_EQ('s', s3[9]);

}

Пробовали ли вы запускать свой код построчно в отладчике, отслеживая значения всех переменных, чтобы определить, в какой момент ваша программа перестает вести себя так, как предполагалось? Если вы не пробовали это, вам может быть интересно прочитать это: Что такое отладчик и как он может помочь мне в диагностике проблем? Вы также можете прочитать это: Как отлаживать небольшие программы?

Andreas Wenzel 22.04.2022 23:33

Вопросы, требующие помощи в отладке, обычно должны предоставлять минимальный воспроизводимый пример проблемы, которая включает функцию main.

Andreas Wenzel 22.04.2022 23:37

Рекомендация: добавьте #include<cstring>

user4581301 22.04.2022 23:42

Я использовал #include<cstring>, но проблема все еще в коде

Omega Coding 22.04.2022 23:45

Рассмотрите возможность устранения ошибок и предупреждений, выделенных здесь: godbolt.org/z/KKrzoqM4q.

user4581301 22.04.2022 23:47

Похоже, вы не добавляете нулевой терминатор в конце строк в конструкторах.

JarMan 22.04.2022 23:48

Подсказка: Что такое Правило трех?

user4581301 22.04.2022 23:49

Я видел эти ошибки и предупреждения, но я не могу их преодолеть. Не могли бы вы помочь, чтобы этот код работал идеально?

Omega Coding 22.04.2022 23:50

В operator+ переосмыслите s1.s += str;. Это арифметика указателя, изменяющая адрес s хранилища. Он не добавляется к строке в s. Боюсь, эта функция должна быть намного сложнее. S1 должен быть копией this, но с одним дополнительным пробелом для хранения str.

user4581301 22.04.2022 23:54

Каким может быть возможный способ написать эту функцию?

Omega Coding 22.04.2022 23:55

Получите достаточно большую пустую строку: String s1(size +1);. Скопируйте данные текущей строки в новую строку: memcpy (s1.s, s, size);. Добавить str: s1.s[size] = str;. Вернуть новую строку: return s1;. Это решит первую из МНОГИХ ошибок в коде. Рекомендация: никогда не пишите сразу столько кода. Напишите несколько строк, максимум одну функцию, и ровно столько, чтобы сделать одну легко тестируемую вещь. Протестируйте код, чтобы убедиться, что одна вещь выполняется правильно для каждого ввода, о котором вы только можете подумать. Как только вы поймете, что эти несколько строк работают, напишите еще несколько, протестируйте, повторите. Вы никогда не захотите больше одной ошибки.

user4581301 23.04.2022 00:04

Что касается комментария @JarMan о завершении строк, я не уверен, что вам нужно это делать, но если вы решите не завершать нулем, знайте, что strlen, strcpy и все другие функции манипулирования строками в cstring полностью зависят от этого завершающего нуля и не могут использоваться.

user4581301 23.04.2022 00:08
3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
0
12
39
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Самая большая проблема здесь в том, что вы в основном все еще на C, а не на C++.

Вы используете C-функции, такие как strlen и `strcat, которые даже не компилируются моим компилятором C++.

Затем вы забываете завершающий символ '\0', если копируете из литералов C-строки. И тогда ни strlen, ни strcat не могут работать корректно.

Вы вызываете '+=', но оператор не определен. Так не пойдет.

Вы вообще не определили операторы присваивания. Сгенерированные компилятором присваивания будут копировать указатель, а не выполнять глубокую копию.

Вы делаете много new, но никогда не освобождаете память с delete.

Я получаю 25 предупреждений компилятора с "-wall".

Итак, вам нужно много рефакторинга.

Однажды я создал аналогичный динамический массив (строку), который далек от совершенства, но может дать вам представление о том, как реализовать свой собственный String . . .

#include <iostream>
#include <sstream>
#include <initializer_list>

// -----------------------------------------------------------------------------------------------
// Definition of simple dynamic array class
template <typename T>
class DynamicArray {
    // The Dynamic Array has an initial capacity. 
    // If more elements will be added, there will be a reallocation with double capacity
    static constexpr unsigned int InitialCapacity{ 8 };

    // Internal data ------------------------------------------------------------------------------
    T* data{};                                 // Dynamic Storage for Data
    unsigned int numberOfElements{};           // Number of elements currently in the container
    unsigned int capacity{ InitialCapacity };  // Current maximum capacity of the container
public:
    // Construction and Destruction ---------------------------------------------------------------
    DynamicArray();                            // Default constructor. Allocate new memory
    DynamicArray(const unsigned int size);     // Constructor for a given size. Allocate new memory
    DynamicArray(const DynamicArray& other);   // Copy constructor. Make a deep copy
    DynamicArray(DynamicArray&& other);        // Move constructor

    // Special constructors
    template <class Iterator> DynamicArray(Iterator begin, Iterator end);   // Initialize from range   
    template <int N> DynamicArray(const T(&other)[N]);                      // Initialize from C_Sytle array,e.g. a string literal
    template <int N> DynamicArray(T(&other)[N]);
    DynamicArray(const std::initializer_list<T>& list);                     // Take data from initializer list

    ~DynamicArray();                            // Destructor: Release previously allocated memory

    // Housekeeping ---------------------------------------------------------------
    bool empty() const;                         // Do we have elements in the container? Do not mix up with capacity
    void clear();                               // Clear will not delete anything. Just set element count to 0
    unsigned int size() const;                  // How many elements are in the container

    // Main working functions
    void push_back(const T& d);                 // Add a new element at the end

    // Operators for class------------------------ ---------------------------------------------------------------

    T operator[] (const unsigned int i) const;  // Index operator, get data at given index. No boundary check
    T& operator[] (const unsigned int i);       // Index operator, get data at given index. No boundary check
    DynamicArray& operator=(const DynamicArray& other); // Assignment
    DynamicArray& operator=(DynamicArray&& other);      // Move Assignment


    // Add iterator properties to class ---------------------------------------------------------------
    class iterator {                           // Local class for iterator
        T* iter{};                             // This will be the iterator 
        T* begin{};                            // For boundary check
        T* end{};                              // For boundary check

    public:                                    // Define alias names necessary for the iterator functionality
        using iterator_category = std::random_access_iterator_tag;
        using difference_type = std::ptrdiff_t;
        using value_type = T;
        using pointer = T*;
        using reference = T&;

        // Constructor
        iterator(T* const i, T* const b, T* const e);

        // Dereferencing
        reference operator *() const;
        pointer operator ->() const;

        // Aithmetic operations
        iterator& operator ++();
        iterator& operator --();
        iterator operator ++(int);
        iterator operator --(int);
        iterator operator +(const difference_type& n) const;
        iterator& operator +=(const difference_type& n);
        iterator operator -(const difference_type& n) const;
        iterator& operator -=(const difference_type& n);

        // Comparison
        bool operator != (const iterator& other) const;
        bool operator == (const iterator& other) const;
        bool operator < (const iterator& other) const;
        bool operator > (const iterator& other) const;
        bool operator <= (const iterator& other) const;
        bool operator >= (const iterator& other) const;

        // Reference and difference
        reference operator[] (const difference_type& n);
        difference_type operator-(const iterator& other) const;
    };

    // Begin and end function to initialize an iterator
    iterator begin() const;
    iterator end() const;

    // Working functions dealing with iterators. More may be added
    iterator erase(iterator pos);

};


// Default constructor. Allocate new memory
template <typename T>
inline DynamicArray<T>::DynamicArray() {
    data = new T[capacity];
}
// Constructor for certain size. Allocate new memory
template <typename T>
inline DynamicArray<T>::DynamicArray(const unsigned int size) : data(new T[size]), numberOfElements(0), capacity(size) {
}

// Copy constructor
template <typename T>
DynamicArray<T>::DynamicArray(const DynamicArray& other) {  // Copy constructor. Make a deep copy
    capacity = numberOfElements = other.numberOfElements;
    data = new T[capacity];                // Get memory, same size as other container
    for (size_t k = 0; k < other.numberOfElements; ++k)
        data[k] = other.data[k];           // Copy data
}

// Move constructor
template <typename T>
DynamicArray<T>::DynamicArray(DynamicArray&& other) {
    data = other.data;
    numberOfElements = other.numberOfElements;
    capacity = other.capacity;
    other.capacity = InitialCapacity;
    other.numberOfElements = 0;
    other.data = new T[capacity];;
}

// Range constructor
template <typename T>
template <class Iterator>
DynamicArray<T>::DynamicArray(Iterator begin, Iterator end) {
    data = new T[capacity];
    for (Iterator i = begin; i != end; ++i)
        push_back(*i);
}

// Construct from a const C-Style Array, like for example "Hello"
template <typename T>
template <int N>
DynamicArray<T>::DynamicArray(const T(&other)[N]) {
    capacity = numberOfElements = N;
    data = new T[capacity];                // Get memory, same size as other container
    for (size_t k = 0; k < N; ++k)
        data[k] = other[k];          // Copy data
}
// Construct from a C-Style Array
template <typename T>
template <int N>
DynamicArray<T>::DynamicArray(T(&other)[N]) {
    capacity = numberOfElements = N;
    data = new T[capacity];                // Get memory, same size as other container
    for (size_t k = 0; k < N; ++k)
        data[k] = other[k];          // Copy data
}

// Construct from an initializer list
template <typename T>
DynamicArray<T>::DynamicArray(const std::initializer_list<T>& list) {
    data = new T[capacity];
    for (const T& t : list) push_back(t);
}

// Destructor will release the dynamic allocated memory
template <typename T>
inline DynamicArray<T>::~DynamicArray() {
    delete[] data;
}         // Destructor: Release previously allocated memory

// Some houskeeping functions
template <typename T>
inline bool DynamicArray<T>::empty() const {
    return numberOfElements == 0;
}
template <typename T>
inline void DynamicArray<T>::clear() {
    numberOfElements = 0;
};    // Clear will not delete anything. Just set element count to 0

template <typename T>
inline unsigned int DynamicArray<T>::size() const {
    return numberOfElements;
} // How many elements are in the container

// Main workhorse for a dynamic array. 
// Store element, and alwaysprovide enough memory
template <typename T>
void DynamicArray<T>::push_back(const T& d) {               // Add a new element at the end
    if (numberOfElements >= capacity) {                     // Check, if capacity of this dynamic array is big enough
        capacity *= 2;                                      // Obviously not, we will double the capacity
        T* temp = new T[capacity];                          // Allocate new and more memory
        for (unsigned int k = 0; k < numberOfElements; ++k)
            temp[k] = data[k];                              // Copy data from old memory to new memory
        delete[] data;                                      // Release old memory
        data = temp;                                        // And assign newly allocated memory to old pointer
    }
    data[numberOfElements++] = d;                           // And finally, store the given data at the end of the container
}

// Operators for class ------------------------ ---------------------------------------------------------------
template <typename T>
inline typename T DynamicArray<T>::operator[] (const unsigned int i) const {
    return data[i];
}      // Index operator, get data at given index. No boundary check

template <typename T>
inline typename T& DynamicArray<T>::operator[] (const unsigned int i) {
    return data[i];
}  // Index operator, get data at given index. No boundary check

// Assignement operator. Make a deep copy
template <typename T>
DynamicArray<T>& DynamicArray<T>::operator=(const DynamicArray& other) {
    if (this != &other) {                                    // Prevent self-assignment
        delete[] data;                                       // Release any previosly existing memory
        capacity = numberOfElements = other.numberOfElements;// Take over capacity and number of elements from other container
        data = new T[capacity];                              // Get new memory, depending on size of other 
        for (unsigned int k = 0; k < numberOfElements; ++k)  // Copy other data
            data[k] = other.data[k];
    }
    return *this;
}
template <typename T>
DynamicArray<T>& DynamicArray<T>::operator=(DynamicArray&& other) {      // Move Assignment
    if (this != &other) {                                    // Prevent self-assignment
        data = other.data;
        numberOfElements = other.numberOfElements;
        capacity = other.capacity;
        other.capacity = InitialCapacity;
        other.numberOfElements = 0;
        other.data = new T[capacity];;
    }
    return *this;
}
// Implementation of iterator functions ---------------------------------------------------------------------
// COnstruction 
template <typename T>
inline DynamicArray<T>::iterator::iterator(T* const i, T* const b, T* const e) : iter(i), begin(b), end(e) {
};  // Constructor for the iterator

// Dereferencing
template <typename T>
inline typename DynamicArray<T>::iterator::reference DynamicArray<T>::iterator::operator *() const {
    return *iter;
}

template <typename T>
inline typename DynamicArray<T>::iterator::pointer DynamicArray<T>::iterator::operator ->() const {
    return iter;
}

// Arithmetic operations
template <typename T>
inline typename DynamicArray<T>::iterator& DynamicArray<T>::iterator::operator ++() {
    if (iter < end)
        ++iter;
    return *this;
}

template <typename T>
inline typename DynamicArray<T>::iterator& DynamicArray<T>::iterator::operator --() {
    if (iter > begin)
        --iter;
    return *this;
}

template <typename T>
typename DynamicArray<T>::iterator DynamicArray<T>::iterator::operator ++(int) {
    DynamicArray<T>::iterator tmp = *this;
    if (this->iter < end)
        ++(*this);
    return tmp;
}

template <typename T>
typename DynamicArray<T>::iterator DynamicArray<T>::iterator::operator --(int) {
    DynamicArray<T>::iterator tmp = *this;
    if (this->iter > begin)
        --(*this);
    return tmp;
}

template <typename T>
typename DynamicArray<T>::iterator DynamicArray<T>::iterator::operator +(const DynamicArray<T>::iterator::difference_type& n) const {
    DynamicArray<T>::iterator tmp = *this;
    DynamicArray<T>::iterator::difference_type k{ n };
    if (k > 0)
        while (k--)
            ++tmp;
    else
        while (k++)
            --tmp;
    return tmp;
}
template <typename T>
typename DynamicArray<T>::iterator& DynamicArray<T>::iterator::operator +=(const DynamicArray<T>::iterator::difference_type& n) {
    DynamicArray<T>::iterator::difference_type k{ n };
    if (k > 0)
        while (k--)
            ++* this;
    else
        while (k++)
            --* this;
    return *this;
}

template <typename T>
typename DynamicArray<T>::iterator DynamicArray<T>::iterator::operator- (const DynamicArray<T>::iterator::difference_type& n) const {
    DynamicArray<T>::iterator tmp = *this;
    DynamicArray<T>::iterator::difference_type k{ n };
    if (k > 0)
        while (k--)
            --tmp;
    else
        while (k++)
            ++tmp;
    return tmp;
}

template <typename T>
typename DynamicArray<T>::iterator& DynamicArray<T>::iterator::operator -=(const typename DynamicArray<T>::iterator::difference_type& n) {
    DynamicArray<T>::iterator::difference_type k{ n };
    if (k > 0)
        while (k--)
            --* this;
    else
        while (k++)
            ++* this;
    return *this;
}

// Comparison functions
template <typename T>
inline typename DynamicArray<T>::iterator::reference DynamicArray<T>::iterator::operator[] (const typename DynamicArray<T>::iterator::difference_type& n) {
    return *(iter + n);
};

template <typename T>
inline bool DynamicArray<T>::iterator::operator != (const iterator& other) const {
    return iter != other.iter;
}

template <typename T>
inline bool DynamicArray<T>::iterator::operator == (const iterator& other) const {
    return iter == other.iter;
}

template <typename T>
inline bool DynamicArray<T>::iterator::operator < (const iterator& other) const {
    return iter < other.iter;
}
template <typename T>
inline bool DynamicArray<T>::iterator::operator > (const iterator& other) const {
    return iter > other.iter;
}  // Comparison

template <typename T>
inline bool DynamicArray<T>::iterator::operator <= (const iterator& other) const {
    return iter <= other.iter;
}  // Comparison

template <typename T>
inline bool DynamicArray<T>::iterator::operator >= (const iterator& other) const {
    return iter >= other.iter;
}  // Comparison

// Delta 
template <typename T>
inline typename DynamicArray<T>::iterator::difference_type DynamicArray<T>::iterator::operator-(const typename DynamicArray<T>::iterator& other) const {
    return iter - other.iter;
}

// ------------------------------------------------------------------------
// Get iterators for dynamic array
template <typename T>
inline typename DynamicArray<T>::iterator DynamicArray<T>::begin() const {
    return iterator(data, data, data + numberOfElements);
}

template <typename T>
inline typename DynamicArray<T>::iterator DynamicArray<T>::end() const {
    return iterator(data + numberOfElements, data, data + numberOfElements);
}

// ------------------------------------------------------------------------
// Any other functions for dynamic array
template <typename T>
typename DynamicArray<T>::iterator DynamicArray<T>::erase(typename DynamicArray<T>::iterator pos) {
    iterator result{ pos };
    if (pos != end()) {
        while (pos != end()) {
            *pos = *(pos + 1);
            ++pos;
        }
        ++result;
        --numberOfElements;
    }
    return result;
}


// --------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------

// Using the dynamic array as a String, by using char as the content
using String = DynamicArray<char>;

// Some overloads for operators for easier handling
std::istream& operator >> (std::istream& is, String& s) {
    s.clear();
    char c{};
    is >> std::ws;
    while (is.peek() != EOF and is.get(c) and not isspace(c)) {
        s.push_back(c);
    }
    if (not s.empty()) s.push_back(0);
    return is;
}
std::ostream& operator << (std::ostream& os, const String& s) {
    std::ostringstream oss;
    for (char c : s)  if (c != '\0') oss << c;
    return os << oss.str();
}
bool operator < (const String& s1, const String& s2) {
    unsigned int length{ (s1.size() < s2.size()) ? s1.size() : s2.size() };
    for (unsigned int k{}; k < length; ++k) {
        if (s1[k] == s2[k]) continue;
        if (s1[k] < s2[k]) return true;
        return false;
    }
    return false;
}
bool operator == (const String& s1, const String& s2) {
    if (s1.size() != s2.size()) return false;
    for (unsigned int k{}; k < s1.size(); ++k) {
        if (s1[k] != s2[k]) return false;
    }
    return true;
}
bool operator != (const String& s1, const String& s2) { return not (s1 == s2); }

Другие вопросы по теме