所以我试图完成这个非常基本的字符串类(MyString)。一切似乎都有效,但当我将其上传到任务网站时,它显示出一个段错误。上传站点使用电围栏,但它没有提供有关故障发生位置的深入见解。它基本上贯穿每个函数并为它返回通过/失败/错误。在getline
函数的情况下,它返回了一个错误。
此外,上传网站使用valgrind报告没有错误。
编辑:我差点忘了,当我在驱动程序中调用该函数时,它从文件messages.txt
读取,其中包含一行文本:Testing this program... PLEASE WORK
以下是getline
函数(因为它存在于实现文件中),它似乎是错误的来源:
// reads line from istream ... line end at newline char of choice) -- '\n' in this case
void MyString::getline(istream &inFile, char delimit)
{
int index = 0;
do
{
data[index] = inFile.get();
index ++;
if (index + 1 > capacity)
{
MyString tempStr;
delete [] tempStr.data;
tempStr.data = new char [capacity];
for (int i = 0; i <= index; i++)
{
tempStr.data[i] = data[i];
}
capacity += 5;
size = index;
delete [] data;
data = new char [capacity];
for (int i = 0; i <= size; i++)
{
data[i] = tempStr.data[i];
}
delete [] tempStr.data;
tempStr.data = NULL;
}
}
while (!inFile.eof() && data[index-1] != delimit);
if (data[index - 1] == delimit)
{
index -= 1;
if (static_cast<double>(index)/capacity < .25 && capacity > 5)
{
capacity -= 5;
char *temp = new char [capacity];
for (int i = 0; i < index; i++)
{
temp[i] = data[i];
}
delete [] data;
data = temp;
}
}
data[index] = '\0';
size = index + 1;
}
我觉得这是我忽略的一件非常简单的事情,或者是我接触这个特定功能的方式的根本缺陷。任何帮助表示赞赏。我很喜欢编程(几个星期),我只是想维持下去 - 同时注册了CompSci 1 + 2。
此外,下面是更多的实现文件 - 特别是构造函数(减去副本)和一些重载的运算符。虽然我可以在我的头上编译它并成功连接类对象,但上传站点在测试“连接”时返回了一个失败。对于哪个运营商失败没有任何反馈。我很好奇在我的代码中会导致什么。再次感谢。
#include <iostream>
#include <fstream>
#include "MyString.h"
using namespace std;
//default constructor - works
MyString::MyString()
{
capacity = 5;
size = 0;
data = new char [capacity];
}
// constructor with character string
MyString::MyString(const char *cString)
{
int index = 0;
capacity = 5;
while ( cString[index] != '\0')
{
index++;
}
size = index + 1;
while (size > capacity)
{
capacity += 5;
}
data = new char[capacity];
for (int i = 0; i < size; i++)
{
data[i] = cString[i];
}
}
// copy constructor
MyString::MyString(const MyString &aMyString)
{
capacity = aMyString.capacity;
size = aMyString.size;
data = new char [capacity];
for (int i = 0; i < size; i++)
{
data[i] = aMyString.data[i];
}
}
// overloaded += operator
void MyString::operator+=(const MyString &aMyString)
{
int tSize1 = size;
int holder = 0;
size += aMyString.size - 1;
while (size > capacity)
{
capacity += 5;
}
char *tempArr = new char [capacity];
for (int i = 0; i < (tSize1 - 1); i ++)
{
tempArr[i] = data[i];
}
for (int i = (tSize1 - 1); i < size; i++)
{
tempArr[i] = aMyString.data[holder];
holder ++;
}
delete [] data;
data = tempArr;
}
// overloaded + operator
MyString MyString::operator+(const MyString &aMyString) const
{
int holder = 0;
MyString tempS;
int tSize1 = size + aMyString.size - 1;
int tCap1 = capacity + aMyString.capacity;
if (static_cast<double>(tSize1)/tCap1 < .25 && tCap1 > 5)
{
tCap1 -= 5;
}
tempS.size = tSize1;
tempS.capacity = tCap1;
delete [] tempS.data;
tempS.data = new char [tempS.capacity];
for (int i = 0; i < (size - 1); i ++)
{
tempS.data[i] = data[i];
}
for (int i = (size - 1); i < tSize1; i++)
{
tempS.data[i] = aMyString.data[holder];
holder ++;
}
return tempS;
}
答案 0 :(得分:0)
我不知道这些是否都是你的错误,但我看到两个从代码中脱颖而出:
for (int i = 0; i <= index; i++)
{
tempStr.data[i] = data[i];
}
[snip]
for (int i = 0; i <= size; i++)
{
data[i] = tempStr.data[i];
}
for
语句都访问了多个字符而不是它们应该访问的字符。如果您想要处理5次,例如在基于零的索引编制中,则检查i < 5
而不是i <= 5
。如果我没有弄错的话,你在这两个for循环中都犯了这个错误。我相信他们应该是:
for (int i = 0; i < index; i++)
和
for (int i = 0; i < size; i++)
将内存写入数组边缘可能会导致像segfaults这样的问题。
答案 1 :(得分:0)
立即问题出在operator +=
上。它应该返回对象的引用,而不是void
。
其次,operator +
应以operator +=
开头。相反,你从头开始编写整个operator +
&#34;&#34;,在operator + =
以下是如何实施operator +:
// overloaded + operator
MyString MyString::operator+(const MyString &aMyString)
{
MyString result = *this; // copy the object
result += aMyString; // call the operator += (where the real work is done).
return result; // just return the result
}
您的运营商+ =,需要定义为:
MyString& MyString::operator+(const MyString &aMyString)
{
// code to do work
return *this;
}
第三,您未能实现赋值运算符。您实现了复制构造函数,但没有实现赋值运算符。除非您没有发布,否则如果您想将一个字符串分配给另一个字符串,则必须实现它。
最后,您的operator+=
有一个缺陷。它会更改size
的值:
size += aMyString.size - 1;
然后尝试分配内存。如果内存分配失败(new
抛出异常)该怎么办?你如何&#34;回滚&#34; size
的值是否为原始值?你不能,至少不是你的实施。
总结一下,仅仅因为你的实施工作&#34;工作&#34;并不意味着它确实运作正常。我上面指出的事情(没有赋值运算符,运算符+ =没有返回引用,*this
)只是两个问题。
像这样的作业的问题在于它可以给你错误的成就感,当你如实地编码你所编写的错误时,你从未意识到错误,但更糟糕的是,可以很容易地创造出来。例如:
int main()
{
MyString s("abc");
MyString t("123");
s = t;
}
如果没有赋值运算符,该代码将因内存泄漏和双删除错误而失败。
真正需要一个中级到高级程序员来创建是,这听起来像一个简单的&#34; String&#34;正确地,至少有一个可以传递所有可以使String类在实际程序中可用的测试。