我正在尝试编写自己的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;}
答案 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);
}
}
您忘了查看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];
}
仅供参考,索引的通常类型是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;
}