Как работает линия? - PullRequest
       2

Как работает линия?

1 голос
/ 08 марта 2012

Я пытаюсь написать свою собственную функцию getline, и она продолжает segfaulting.Как это исправить и как официально работает линия, если моя не работает?Я пишу это, чтобы научиться кодировать лучше.

#include"MyString.h"





MyString::MyString( )  //constructor
{
    size=0;
    capacity=1;
    data=new char[capacity];

}
MyString::MyString(char * n)  //copy constructor
{
    size=strlen(n);
    capacity=strlen(n)+1;
    data=new char[capacity];
    strcpy(data,n);
}
MyString::MyString(const MyString &right)  //
{
    size=strlen(right.data);
    capacity=strlen(right.data)+1;
    data=new char [capacity];
    strcpy(data,right.data);

}
MyString::~MyString( )
{
    delete [] data;
}
MyString  MyString::operator = (const MyString& s)
{

    if(this!=&s)
    {
        MyString temp=data;
        delete [] data;
        size=strlen(s.data);
        capacity=size+1;
        data= new char [capacity];
        strcpy(data,s.data);
    }
}
MyString&  MyString::append(const MyString& s)
{
    if(this!=&s)
    {
        strcat(data,s.data);
    }


}
MyString&  MyString::erase()
{

}
MyString  MyString::operator + (const MyString& s)const
{
    return strcat(data,s.data);
}
bool  MyString::operator == (const MyString& s)
{
    return strcmp(data,s.data)==0;
}
bool  MyString::operator <  (const MyString& s)
{
    return strcmp(data,s.data)<0;
}
bool  MyString::operator >  (const MyString& s)
{
    return strcmp(data,s.data)>0;
}
bool  MyString::operator <= (const MyString& s)
{
    return strcmp(data,s.data)<=0;
}
bool  MyString::operator >= (const MyString& s)
{
    return strcmp(data,s.data)>=0;
}
bool  MyString::operator != (const MyString& s)
{
    return strcmp(data,s.data)!=0;
}
void  MyString::operator += (const MyString& s)
{
    append(s.data);
}
char&  MyString::operator [ ] (int n)
{
    return data[n];
}
void  MyString::getline(istream& in)
{
    char c;
    erase();
    ifstream input;
    while(in.get(c)&&c!='\n')
    {
        data[size]=c;
        size++;

        if(size+1<=capacity)
        {
          capacity*=2;
          char*p=new char[capacity];
          strcpy(p,data);
          delete [] data;
          data=p;
        }
        data[size]=c;
        size++;
        data[size]='\0';
    }

}
int  MyString::length( ) const
{
    return strlen(data);
}
void MyString::grow()
{
 capacity=strlen(data)+1;
MyString temp;
temp=data;
delete [] data;
capacity*=2;
data= new char[capacity];
}

ostream& operator<<(ostream& out, MyString& s)
{

    out<<s.data;
    return out;


}



// int  MyString::getCapacity(){return capacity;}

Ответы [ 3 ]

1 голос
/ 08 марта 2012

Ну ...

if(size+1<=capacity)

Допустим, ваша емкость равна 11, а ваш размер равен 11.

if( 12 <= 11 )
{
   // Resize capacity.  This code won't run.
}

Вы хотите if( size >= capacity ).

Также, у вас есть data[size] = c; size++; дважды в вашем цикле.Итак, вы делаете 2 копии каждого персонажа.

0 голосов
/ 08 марта 2012
MyString::MyString(char * n)  //copy constructor
{
    size=strlen(n);
    capacity=strlen(n)+1;
    data=new char[capacity];
    strcpy(data,n);
}

Нет смысла звонить strlen дважды.Оптимизаторы недостаточно умны, чтобы устранить избыточность.Кроме того, поскольку вы не изменяете данные в переданной строке, это должно быть const.В противном случае вы не могли бы передать это строковые константы.Исправляя, мы получаем:

MyString::MyString(const char * n)  //copy constructor
{
    size = strlen(n);
    capacity = size + 1;
    data = new char[capacity];
    strcpy(data, n);
}

MyString::MyString(const MyString &right)  //
{
    size=strlen(right.data);
    capacity=strlen(right.data)+1;
    data=new char [capacity];
    strcpy(data,right.data);

}

right имеет size член, который устраняет необходимость в strlen.Это плюс приведенные выше исправления дают:

MyString::MyString(const MyString &right)  //
{
    size = right.size;
    capacity = size + 1;
    data = new char[capacity];
    strcpy(data, right.data);
}

MyString  MyString::operator = (const MyString& s)
{

    if(this!=&s)
    {
        MyString temp=data;
        delete [] data;
        size=strlen(s.data);
        capacity=size+1;
        data= new char [capacity];
        strcpy(data,s.data);
    }
}

operator = должен возвращать ссылку (т. Е. *this; кстати, вы забыли что-либо вернуть), а не другую копию.Также обратите внимание, что temp не используется, и у вас есть избыточный strlen вызов:

MyString& MyString::operator = (const MyString& s)
{
    if(this!=&s)
    {
        delete[] data;
        size = s.size;
        capacity = size + 1;
        data = new char[capacity];
        strcpy(data, s.data);
    }
    return *this;
}

MyString&  MyString::append(const MyString& s)
{
    if(this!=&s)
    {
        strcat(data,s.data);
    }


}

Вы забыли проверить свои size и capacity.Так что strcat будет запускаться прямо в конец вашего char массива.Кроме того, объединение к себе должно быть сделано для работы.И вам не нужно strcat:

MyString& MyString::append(const MyString& s)
{
    size_t rSize = s.size;
    if(capacity < size + rSize + 1)
    {
        capacity = size + rSize + 1;
        char* newData = new char[capacity];
        memcpy(newData, data, size);
        delete[] data;
        data = newData;
    }
    memcpy(data + size, s.data, rSize);
    size += rSize;
    data[size] = '\0';
    return *this;
}

erase, просто нужно, чтобы строка ушла.Нет необходимости перепутывать память с:

MyString& MyString::erase()
{
    size = 0;
    data[0] = '\0';
}

MyString  MyString::operator + (const MyString& s)const
{
    return strcat(data,s.data);
}

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

MyString MyString::operator + (const MyString& s) const
{
    return MyString(*this).append(s);
}

void  MyString::operator += (const MyString& s)
{
    append(s.data);
}

Это коварный способ!Видите ли, поскольку append принимает const MyString&, а вы присваиваете ему char*, компилятор создает временный MyString, вызывает для него конструктор MyString(const char*), передает временное значение в append, затем сбрасываетЭто.Таким образом, вы получите правильный результат, но вы создали дополнительный объект.Правильный путь:

void MyString::operator += (const MyString& s)
{
    append(s);
}

char&  MyString::operator [ ] (int n)
{
    return data[n];
}

Нет проверки границ?Храбрый.Если вы хотите, это не сложно добавить.Предполагая, что вы не хотите генерировать исключение:

char& MyString::operator [] (int n)
{
    if(n < 0)
        n = 0;
    if(n >= size)
        n = size - 1;
    return data[n];
}

FYI, обычный тип индекса - size_t, который определен в <stddef.h> и является целочисленным типом без знака, возвращаемым sizeof(), так что он гарантированно будет работать как индекс массива с обычным массивом (здесь вы можете избавиться от отрицательной проверки индекса).

Кроме того, вы можете захотеть версию, которая может работать на const MyString,Он просто возвращает символ вместо ссылки:

char MyString::operator [] (int n) const
{
    if(n < 0)
        n = 0;
    if(n >= size)
        n = size - 1;
    return data[n];
}

void  MyString::getline(istream& in)
{
    char c;
    erase();
    ifstream input;
    while(in.get(c)&&c!='\n')
    {
        data[size]=c;
        size++;

        if(size+1<=capacity)
        {
          capacity*=2;
          char*p=new char[capacity];
          strcpy(p,data);
          delete [] data;
          data=p;
        }
        data[size]=c;
        size++;
        data[size]='\0';
    }

}

Сначала ifstream ничего не делает;избавиться от этого.Вы должны работать только с istream.Индивид указал на проблемы с дополнительными символами и плохой проверкой.strcpy потерпит неудачу, потому что вы не поместили \0 обратно в конец строки, поэтому вам нужно использовать memcpy вместо:

void  MyString::getline(istream& in)
{
    char c;
    erase();
    while(in.get(c) && c != '\n')
    {
        data[size++] = c;
        if(size >= capacity)
        {
          capacity *= 2;
          char *newData = new char[capacity];
          memcpy(newData, data, size);
          delete[] data;
          data = newData;
        }
    }
    data[size] = '\0';
}

int  MyString::length( ) const
{
    return strlen(data);
}

Thisпросто тратить время, потому что size уже имеет длину строки.Он действительно должен быть определен в определении класса, поэтому он может быть встроен:

int MyString::length() const
{
    return size;
}

void MyString::grow()
{
 capacity=strlen(data)+1;
MyString temp;
temp=data;
delete [] data;
capacity*=2;
data= new char[capacity];
}

Первая строка просто неверна;capacity уже настроен правильно.Вам не нужно temp.И вы забыли скопировать строковые данные поверх:

void MyString::grow()
{
    capacity *= 2;
    char* newData = new char[capacity];
    memcpy(newData, data, size + 1);
    delete[] data;
    data = newData;
}

ostream& operator<<(ostream& out, MyString& s)
{

    out<<s.data;
    return out;


}

Вы не меняете s, поэтому должно быть const:

ostream& operator<<(ostream& out, const MyString& s)
{
    return out << s.data;
}
0 голосов
/ 08 марта 2012

Это должно выглядеть примерно так:

void MyString::getline(istream& in)
{
    erase();
    for (char c; in.get(c) && c != '\n'; )
        append(c);
}

Теперь вам просто нужно правильно реализовать метод append, который добавляет один символ.Если у вас возникли проблемы с этим, задайте другой вопрос.Вы можете думать, что я здесь шутливый, но это не так.Вам нужно ограничить места, которые вы перераспределяете, и перестать повторять себя в своем коде.Функция getline не место для такого рода деятельности (я имею в виду перераспределение).

...