【问题标题】:Basic Custom String Class for C++C++ 的基本自定义字符串类
【发布时间】:2011-02-06 05:51:16
【问题描述】:

编辑:我不想删除帖子,因为我很快从中学到了很多东西,它可能对其他人有好处,但其他人没有必要花时间回答或查看这个问题。问题出在我的编程基础上,而这是无法通过快速响应解决的。感谢所有发帖的人,感谢您的帮助,非常谦虚!

大家好,我正在构建自己的具有非常基本功能的字符串类。我很难理解我定义的基本类发生了什么,并且相信在处理发生的范围时存在某种错误。当我尝试查看我创建的对象时,所有字段都被描述为(显然是错误的指针)。此外,如果我公开数据字段或构建访问器方法,程序会崩溃。由于某种原因,该对象的指针是 0xccccccccc,它不指向任何位置。
我该如何解决这个问题?非常感谢任何帮助/cmets。

    //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;
}

编辑: 感谢到目前为止所有回复并处理我对这个主题的严重缺乏理解的人。我将开始处理所有答案,但再次感谢您的良好回复,抱歉我的问题含糊不清,但实际上并没有具体的错误,但更多的是缺乏对数组和类的理解。

【问题讨论】:

  • 为什么不使用std::basic_string
  • 由于我还在学习 C++,因此我正在尝试将课程构建为练习。
  • 仅供参考,0xcccccccc 地址是 Microsoft 编译器在调试模式下编译时填充未初始化内存的特殊值。当您看到该值时,您可以合理确定地知道您要么忘记初始化变量,要么取消引用已删除或其他野指针。
  • 要添加到 Tyler 的评论中,请参阅 stackoverflow.com/questions/370195/…

标签: c++ string class object


【解决方案1】:

这只是第一个构造函数的错误。

    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");

【讨论】:

  • 是的,仔细观察,整个事情充满了错误。我只是专注于 OP 询问的具体错误。 叹息
  • 我有一个在本地教 C++ 的学生,实际上我跳过了引用并通过 const 引用传递,直到稍后。 C++ 中有很多复杂的东西与通过引用或值传递时发生的确切情况有关,而 const 正确性在一开始并不是一个容易理解的概念。 OTOH,OPs 类有一个重要的默认构造函数,并且需要一个复制构造函数,所以也许 OP 应该立即跳入该领域。
  • 为了回应仔细的参数评论,我正在使用一个给出头文件的书籍示例,所以我只是使用了书中列出的内容。 append 也是如此,对我来说也没有多大意义,因为字符串库中的 append 也是一个 void。
  • 如果不引入const char*不想修改字符串的话,这是一本很可疑的书。事实上,构造函数几乎不能接受“字符串文字”(因为将它们转换为char* 已被弃用——而且很危险)。 - 另外,正如 Omnifarious 所提到的,没有 const 引用就不可能实现一个重要的类,因为你肯定需要一个复制构造函数/赋值运算符/析构函数。 - 如果你还没有达到那个水平,也许你应该忘记这个类,而只是通过简单地重新实现 &lt;cstring&gt; 函数来练习处理 C 字符串?
  • 这听起来是个好主意,退后一步会给我带来很多好处。文中介绍了 const char*,但对于本示例,它要求构造函数为 char * chars。想一想,问题可能是要先定义一个字符数组,然后把这个数组的指针传给构造函数。感谢您的帮助,希望我的下一个问题不会因基本错误而复杂。
【解决方案2】:

您的代码中有一些 cmets:

    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,这个函数的整个想法是完全错误的——如果你有一个字符串,并要求它在你的字符串上附加一些东西,它破坏你的原始字符串,并且(更糟)让它处于不可用状态——当你开始添加一个析构函数来释放字符串所拥有的内存时,它会导致字符串的存储被双重删除,该字符串是拥有@987654334 的主题(受害者?) @ 调用它。

我会考虑编写一个私有的“复制”函数,并在你在这里展示的一些(大部分?)的实现中使用它。

作为一个更一般的建议,我会考虑更多的可能性:首先,我不会总是准确地分配字符串所需的空间量,而是考虑将分配四舍五入到(比如说)a两个的幂。其次,如果您希望您的字符串类运行良好,您可以考虑实施“短字符串优化”。这包括在字符串对象本身的主体中为短字符串(例如 20 个字符)分配空间。由于许多字符串往往相对较短,因此可以通过避免在字符串较短时进行堆分配来显着提高速度(并减少堆碎片等)。

【讨论】:

  • 这些是我的指令缺少的cmets。在我的课程中,只要代码功能正确,就会收到完整的积分,所以很少有事情被忽略(从长远来看这是不好的)。感谢您的帮助!
【解决方案3】:

index 在 append 函数的第二个 while 循环中不是从 0 开始。您可能应该使用for 循环。哦,你使用了错误的delete 形式。您应该使用delete[] string,因为string 是一个数组。

还有许多其他的样式问题和彻底的错误,但我首先提到的是您遇到的基本错误。

我会这样写append函数:

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;
}

【讨论】:

  • 好的,我知道 for 循环在风格上是一个更好的选择,但我不想构建一个新的 char 数组,所以第二个元素中第一个字符的索引将是第一个元素+1?编辑,好吧,我需要的是新字符数组的索引从 (size+1) 开始,但另一个仍然为 0,真是个愚蠢的错误。
  • @wdow88,我给了你附加函数的示例代码。它不返回任何内容,因为 append 的语义意味着原始内容是通过附加一些内容来修改的。不过,您有很多错误。我认为您应该通过这整个事情进行几次,并请一些知识渊博的人帮助指出它们。你有很多东西要学(这不是坏事)。
猜你喜欢
  • 2011-02-20
  • 2019-06-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-03
相关资源
最近更新 更多