Базовый пользовательский строковый класс для C ++ - PullRequest
1 голос
/ 09 апреля 2010

РЕДАКТИРОВАТЬ: я не хочу удалять сообщение, потому что я очень многому научился из него, и это могло бы принести пользу кому-то еще, но больше нет необходимости тратить время на ответ или просмотр этого вопроса. Проблемы были в моих основах программирования, и это не может быть исправлено в быстром ответе. Всем, кто написал, спасибо за помощь, довольно унизительно!

Привет всем, я работаю над созданием собственного строкового класса с очень простой функциональностью. Мне трудно понять, что происходит с базовым классом, который я определил, и считаю, что существует какая-то ошибка, связанная с возникновением области видимости. Когда я пытаюсь просмотреть объекты, которые я создал, все поля описываются как (очевидно, неверный указатель). Кроме того, если я сделаю поля данных общедоступными или создаю метод доступа, происходит сбой программы. По какой-то причине указатель на объект имеет вид 0xccccccccc, который указывает не куда.
Как я могу это исправить? Любая помощь / комментарии очень ценятся.

    //This is a custom string class, so far the only functions are 
    //constructing and appending

#include<iostream>
using namespace std;

class MyString1
{
public:
    MyString1()     
    {   

        //no arg constructor
        char *string;
        string = new char[0];
        string[0] ='\0';
        std::cout << string;
        size = 1;
    }
    //constructor receives pointer to character array
    MyString1(char* chars)
    {
        int index = 0;
        //Determine the length of the array
        while (chars[index] != NULL)
            index++;
        //Allocate dynamic memory on the heap
        char *string;
        string = new char[index+1];
        //Copy the contents of the array pointed by chars into string, the char array of the object
        for (int ii = 0; ii < index; ii++)
            string[ii] = chars[ii];
        string[index+1] = '\0';
        size = index+1;
    }
    MyString1 append(MyString1 s)
    { 
        //determine new size of the appended array and allocate memory
        int newsize = s.size + size;
        MyString1 MyString2;
        char *newstring;
        newstring = new char[newsize+1];

        int index = 0;
        //load the first string into the array
        for (int ii = 0; ii < size; ii++)
        {
            newstring[ii] = string[ii];
            index++;
        }

        for(int jj = 0; jj < s.size; jj++, ii++)
        {
            newstring[ii] = s.string[jj++];
            index++;
        }
        //null terminate
        newstring[newsize+1] = '\0';

        delete string;
        //generate the object for return
        MyString2.string=newstring;
        MyString2.size=newsize;

        return MyString2;
    }
private:
    char *string;
    int size;
};



int main()
{
    MyString1 string1;
    MyString1 string2("Hello There");
    MyString1 string3("Buddy");
    string2.append(string3);
    return 0;
}

EDIT: Спасибо всем, кто откликнулся и имеет дело с моим огромным непониманием этой темы. Я начну работать со всеми ответами, но еще раз спасибо за хорошие ответы, извините, мой вопрос расплывчат, но на самом деле нет конкретной ошибки, а скорее из-за отсутствия понимания массивов и классов.

Ответы [ 3 ]

3 голосов
/ 09 апреля 2010

Вот только ошибки первого конструктора.

    MyString1()     
    {   

//no arg constructor
        char *string;         //defines local variable that hides the member by that name
        string = new char[0]; //sort of meaningless
        string[0] ='\0';      //not enough room for that (out-of-bounds)
        std::cout << string;
        size = 1;             //I don't think you should count null as part of the string
    }

Подобные ошибки в других местах.

Также вы должны передавать параметры более осторожно.

MyString1(const char* source); //note const

MyString1 append(const MyString1& what); //note const and reference

Если последнее верно, это также зависит от того, что он должен делать. На основании std::string ожидаемый результат будет:

MyString1 a("Hello "), b("world");
a.append(b);
assert(a == "Hello world");
2 голосов
/ 09 апреля 2010

Некоторые комментарии к вашему коду:

    MyString1()     
    {   

//no arg constructor

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

        char *string;
        string = new char[0];
        string[0] ='\0';

Это вызывает неопределенное поведение.Разрешается вызов new с нулевыми элементами, но вы не можете разыменовать то, что он возвращает (он может возвращать нулевой указатель или может возвращать ненулевой указатель, который не ссылается на какое-либо хранилище).В большинстве случаев лучше установить указатель в NULL.

        std::cout << string;

Какой смысл писать пустую строку?

        size = 1;

Строка пуста, так чтоНормальная фигура, размер равен нулю.

//constructor receives pointer to character array

По-прежнему бесполезен.

    MyString1(char* chars)

Поскольку вы не планируете (или не должны в любом случае) изменять входные данные, этопараметр должен быть char const *.

    {
        int index = 0;
//Determine the length of the array
        while (chars[index] != NULL)
            index++;

. Хотя это работает, «NULL» действительно должен быть зарезервирован для использования в качестве указателя, по крайней мере, IMO.Я написал бы что-то вроде:

while (chars[index] != '\0')
    ++index;

Если вы не используете предыдущее значение, предпочитайте предварительное увеличение вместо пост-увеличения.

//Allocate dynamic memory on the heap

В отличие от выделения статической памятив куче?

    MyString1 MyString2;

Использование одного и того же соглашения об именах для типов и переменных сбивает с толку.

    while (string[index] != NULL)

Тот же комментарий о NULL, что и здесь, применяется ранее.

MyString1 append(MyString1 s)

IMO, сама идея этой функции просто неверна - если у вас есть строка, и вы просите ее добавить что-то к вашей строке, она уничтожает вашу исходную строку и (что еще хуже) оставляет еев непригодном для использования состоянии - когда вы дойдете до добавления деструктора, который освобождает память, принадлежащую строке, это приведет к двойному удалению хранилища строки, которая была объектом (жертвой?) вызова append

Я бы подумал написать частную функцию «копирования» и использовать ее в реализациях некоторых (большинства?) того, что вы здесь показали.

Как немногоиз более общего совета, яЯ бы рассмотрел еще пару возможностей: во-первых, вместо того, чтобы всегда выделять ровно количество места, необходимого для строки, я бы рассмотрел округление выделения до (скажем) степени два.Во-вторых, если вы хотите, чтобы ваш строковый класс работал хорошо, вы можете рассмотреть возможность реализации «оптимизации коротких строк».Это состоит из выделения места для короткой строки (например, 20 символов) в теле самого строкового объекта.Поскольку многие строки имеют тенденцию быть относительно короткими, это может значительно повысить скорость (и уменьшить фрагментацию кучи и т. Д.), Избегая распределения кучи, если строка короткая.

1 голос
/ 09 апреля 2010

index не начинается с 0 во втором цикле while в вашей функции добавления. Вы, вероятно, должны использовать петли for. О, и вы используете неправильную форму delete. Вы должны использовать delete[] string, потому что string - это массив.

Существует множество других проблем со стилем и прямые ошибки, но первое, что я упомянул, - это основная ошибка, с которой вы столкнулись.

Я бы написал функцию добавления следующим образом:

void append(MyString1 s)
{ 
           //determine new size of the appended array and allocate memory
    int newsize = s.size + size;
    char *newstring = new char[newsize+1];

    int destindex = 0;
    for (int index = 0; index < size; ++index) {
       newstring[destindex++] = string[index];
    }
    for (int index = 0; index < s.size; ++index) {
       newstring[destindex++] = s.string[index];
    }
    newstring[destindex] = '\0';

    delete[] string;
    string = newstring;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...