如何让线路工作?

时间:2012-03-08 04:01:55

标签: c++ string getline

我正在尝试编写自己的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 个答案:

答案 0 :(得分:1)

嗯...

if(size+1<=capacity)

假设您的容量为11,而您的容量为11。

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

您想要if( size >= capacity )

此外,您的循环中有data[size] = c; size++;次。所以你要为每个角色制作2份副本。

答案 1 :(得分:0)

看起来应该是这样的:

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

现在你只需要正确实现一个名为append的方法,它附加一个单独的字符。如果您遇到问题,请再问一个问题。你可能认为我在这里很滑稽,但我不是。您需要限制重新分配的位置,并在代码中停止重复自己。 getline函数不是那种活动的地方(重新分配,我的意思)。

答案 2 :(得分:0)

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; BTW,你忘了返回任何内容),而不是另一个副本。另请注意,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);
    }


}

您忘了查看sizecapacity。因此,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];
}

仅供参考,索引的通常类型是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。 indiv指出了额外字符和坏检查的问题。 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);
}

这只是浪费时间,因为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;
}