购物清单程序:在 VIM "Segmentation fault (core dumped)" 中,但 Codeblocks 有效

Shopping List program: In VIM "Segmentation fault (core dumped)", but Codeblocks works

祝你一切顺利。

在编程方面我有点菜鸟,所以请多多包涵。我有两个问题。我正在尝试创建一个包含 5 个文件的程序:items.h、items.cpp、list.h、list.cpp 和 main。有一个项目 class 和一个列表 class。该程序的目的是创建一个购物清单,允许用户输入商品名称、商品单位、单位成本,然后将其添加到清单中。该程序还允许您通过名称删除项目。 我们不能使用向量

问题 1:到目前为止,我在 Codeblocks 中的 运行,但是当我在 VIM 中 运行 时,我得到错误 "Segmentation fault (core dumped)."

问题2:当我尝试添加另一个变量在main中使用时,我也遇到了一个错误,例如amountToBuy(包含用户想要购买的项目的int数)——添加后,Codeblocks中的程序不会 运行,说明 "std::bad_alloc"。我已经注释掉了一些内容,所以程序会 运行。

我完全不知所措,不知道是哪几行导致了问题,也不知道我将如何解决问题。任何投入将不胜感激。非常感谢!

list.h

#ifndef LIST_H_INCLUDED
#define LIST_H_INCLUDED
#include "items.h"
#include <string>

class List
{
    private:
        int arrayPosition;
        int arraySize;
        Item* itemsOnList = new Item[arraySize];
    public:
        List();
        void addItem(Item);
        void removeItem(std::string ri);
        void displayList();
    }; 
#endif // LIST_H_INCLUDED

list.cpp

#include "list.h"
#include "items.h"
#include <string>
#include <iostream>

/*******************************************************************

List::List()
Constructor initializes List size to 4 as default

*******************************************************************/
List::List()
{
    arraySize = 4;
    arrayPosition = 0;
}


/*******************************************************************

void List::addItem(Item)
This function adds the specified Item to the List

*******************************************************************/
void List::addItem(Item i)
{
    //x2 arraySize when arrayPosition gets too close to arraySize
    if (arrayPosition == arraySize)
    {
        //doubling arraySize since we need more space
        arraySize *= 2;

        //tempList to hold the old List's items
        Item* tempList = new Item[arraySize];

        //transferring information to tempList
        for (int a = 0; a < arrayPosition; a++)
        {
            tempList[a] = itemsOnList[a];
        }

        delete[] itemsOnList;

        //transferring data from temp List back to Old list
        itemsOnList = tempList;

        delete[] tempList;

        //adding next item to list
        itemsOnList[arrayPosition++] = i;
    }
    else
    {
        //adding next item to list
        itemsOnList[arrayPosition++] = i;
    }
}


/*******************************************************************

void List::removeItem(std::string)
This function removes the specified Item to the List

*******************************************************************/
void List::removeItem(std::string ri)
{
    for (int a = 0; a < arrayPosition; a++)
    {
        if (itemsOnList[a].getItemName() == ri)
        {
            //moving the rest of the items down one position
            //to take the removed item's spot
            for (int b = a; b < arrayPosition; b++)
            {
                itemsOnList[b] = itemsOnList[b+1];
            }
            //decreasing arrayPosition by one because Item was removed
            --arrayPosition;
        }
    }
}

/*******************************************************************

void List::displayList()
This function displays the List

*******************************************************************/
void List::displayList()
{
    std::cout << "The following Items are on your Grocery List\n\n";

    for (int i = 0; i < arrayPosition; i++)
    {
        std::cout << "Item name: " << itemsOnList[i].getItemName() << std::endl;
        //std::cout << "Number to buy: " << itemsOnList[i].getNumberToBuy() << std::endl;
    }
    std::cout << std::endl;
}

items.h

#ifndef ITEMS_H_INCLUDED
#define ITEMS_H_INCLUDED

#include <string>

class Item
{
    private:
        std::string itemName;
        //int numberToBuy;
    public:
        Item();
        Item(std::string);
        //setters
        void setItemName(std::string);
        //void setNumberToBuy(int);
        //getters
        std::string getItemName();
};

#endif // ITEMS_H_INCLUDED

items.cpp

#include "items.h"

Item::Item()
{
    itemName = "empty";
    //numberToBuy = 0;
}

//this constructor accepts a string and an int
Item::Item(std::string in)
{
    itemName = in;
    //numberToBuy = ntb;
}

//setters
void Item::setItemName(std::string in)
{
    itemName = in;
}

/*
void Item::setNumberToBuy(int ntb)
{
    numberToBuy = ntb;
}
*/

//getters
std::string Item::getItemName()
{
    return itemName;
}

main.cpp

#include "list.h"
#include "items.h"
#include <iostream>

int main()
{
    int menuChoice, subMenuChoice;
    std::string itemName, removeItem;
    bool exit = false;
    List newList;

    //introduction
    std::cout << "Welcome to your Grocery List!\n\n";

    do
    {
        //menu
        std::cout << "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * \n\n";
        std::cout << "To select a menu item, please select its corresponding number.\n\n";

        //menu prompts and storing the choice
        std::cout << "1. Add items to Grocery List\n";
        std::cout << "2. Remove items from Grocery List\n";
        std::cout << "3. Display Grocery List\n";
        std::cout << "4. Exit\n\n";

        std::cout << "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * \n\n";
        std::cout << "Menu choice: ";
        std::cin >> menuChoice;
        std::cout << std::endl;

        //menu choice break-away section
        if (menuChoice == 1)
        {
            do
            {
                std::cout << "Please enter the name of the item: ";
                std::cin >> itemName;

                //std::cout << "Please enter the unit (cans, lbs, oz): ";
                //std::cin >> itemUnit;

                //std::cout << "Please enter number to buy: ";
                //std::cin >> amountToBuy;

                Item theItem(itemName);

                newList.addItem(theItem);

                std::cout << "Would you like to add another item? For YES type 1 | For NO type 0: ";
                std::cin >> subMenuChoice;
                std::cout << std::endl;
            }
            while(subMenuChoice == 1);
        }
        else if (menuChoice == 2)
        {
            std::cout << "Please enter the name of the item you want to remove: ";
            std::cin >> removeItem;
            std::cout << std::endl;

            newList.removeItem(removeItem);
        }
        else if (menuChoice == 3)
        {
            newList.displayList();
        }
        else if (menuChoice == 4)
        {
            exit = true;
            std::cout << "Goodbye!" << std::endl;
        }
    }
    while (exit == false);

    return 0;
}

class List
{
private:
    int arrayPosition;
    int arraySize;
    Item* itemsOnList = new Item[arraySize];
public:
    List();
    void addItem(Item);
    void removeItem(std::string ri);
    void displayList();
}; 

Item* itemsOnList = new Item[arraySize]; 将在构造函数主体之前执行,所以到

List::List()
{
    arraySize = 4;
    arrayPosition = 0;
}

运行并且arraySize设置为4,itemsOnList已经分配了一个未知大小的数组或者程序已经崩溃。

一个简单的解决方法是

class List
{
private:
    int arrayPosition;
    int arraySize;
    Item* itemsOnList;
public:
    List();
    void addItem(Item);
    void removeItem(std::string ri);
    void displayList();
}; 

List::List()
{
    arraySize = 4;
    arrayPosition = 0;
    itemsOnList = new Item[arraySize]
}

List::List():
    arrayPosition(0),
    arraySize(4),
    itemsOnList(new Item[arraySize])
{
}

第二个使用不幸的是Member Initializer List。这通常是最好的方法,因为它确保在进入构造函数的主体之前完全构造对象。对于复杂对象,这避免了必须重做默认构造函数执行的任何工作,这些默认构造函数用于在使用前确保对象有效。

编辑:关于上面的成员初始值设定项列表 link 的注释。前三分之一看起来好像是用火星语写的。跳到解释部分并开始阅读,然后在需要时返回到具体细节。

addItem下面也会出现问题:

    Item* tempList = new Item[arraySize]; //created new array

    //transferring information to tempList
    for (int a = 0; a < arrayPosition; a++)
    {
        tempList[a] = itemsOnList[a]; //copying old to new
    }

    delete[] itemsOnList; //free old list storage

    //transferring data from temp List back to Old list
    itemsOnList = tempList; // assign new list to old list


    delete[] tempList; // whoops. Freed new list storage

在短时间内 tempListitemsOnList 指向相同的存储空间,因此 delete 任何一个指针都将释放两者的存储空间。解决方案:不要 delete[] tempList;

RemoveItem中:

for (int b = a; b < arrayPosition; b++)
{
    itemsOnList[b] = itemsOnList[b+1];
}

b 的取值范围最大为 arrayPosition - 1,因此 itemsOnList[b+1] 可以写成 itemsOnList[arrayPosition-1+1]itemsOnList[arrayPosition]。如果列表已满,arrayPosition 可能是列表末尾后面的一个。

您的代码存在三个突出问题。

没有初始化'arraySize'和'arrayPosition'。

您没有为 'arraySize' 指定初始值,但您指定了

    Item* itemsOnList = new Item[arraySize];

由于您指定的方式,充其量它总是会生成一个零长度 (nullptr) itemsOnList,在最坏的情况下它会使用一些未初始化的随机值来创建一个随机大小的数组,而 arrayPosition 将也随机小于或大于 arraySize 值。

尺寸*=2

if (arrayPosition == arraySize)
{
    //doubling arraySize since we need more space
    arraySize *= 2;

在最好的情况下,您的 arraySize 从零开始。因此,当你将它加倍时,你会得到:零。

全部删除。

在 addItem 中,您执行以下操作:

    delete[] itemsOnList;

    //transferring data from temp List back to Old list
    itemsOnList = tempList;

此时itemsOnList和tempList都指向同一个数组。所以下一条语句:

    delete[] tempList;

删除您的第二个副本 - 现在旧数组和新数组都被删除。