C++ 购物清单计划:在VIM中;分段故障(堆芯倾倒)“;,但代码块是有效的

C++ 购物清单计划:在VIM中;分段故障(堆芯倾倒)“;,但代码块是有效的,c++,vim,codeblocks,C++,Vim,Codeblocks,希望你的一天过得很好 说到编程,我有点无所事事,所以请容忍我。我有两个问题。我正在尝试创建一个由5个文件组成的程序:items.h、items.cpp、list.h、list.cpp和main。有一个Item类和一个List类。该程序的目标是创建一个购物列表,允许用户输入项目名称、项目单位、单位成本,然后将其添加到列表中。该程序还允许您按项目名称删除项目我们不能使用向量 问题1:到目前为止,我所拥有的将在代码块中运行,但当我在VIM中运行它时,我得到错误“分段错误(内核转储)” 问题2:当我尝试

希望你的一天过得很好

说到编程,我有点无所事事,所以请容忍我。我有两个问题。我正在尝试创建一个由5个文件组成的程序:items.h、items.cpp、list.h、list.cpp和main。有一个Item类和一个List类。该程序的目标是创建一个购物列表,允许用户输入项目名称、项目单位、单位成本,然后将其添加到列表中。该程序还允许您按项目名称删除项目我们不能使用向量

问题1:到目前为止,我所拥有的将在代码块中运行,但当我在VIM中运行它时,我得到错误“分段错误(内核转储)”

问题2:当我尝试在main中添加另一个要使用的变量时,我也遇到了一个错误,例如amountToBuy(包含用户想要购买的项目的整数)——添加时,代码块中的程序将不会运行,并声明“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
#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
main.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;
}
#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;
}
#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;
}
#包括“list.h”
#包括“项目.h”
#包括
int main()
{
int菜单选择,子菜单选择;
std::string itemName,removietem;
bool exit=false;
列表新建列表;
//导言
std::coutIn

Item*itemsOnList=newitem[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();
}; 

第二种方法使用了令人遗憾的欠教方法。这通常是最好的方法,因为它可以确保在进入构造函数主体之前完全构造对象。对于复杂对象,这可以防止在使用之前必须重做默认构造函数执行的任何工作,默认构造函数用于确保对象有效

编辑:上面的成员初始值设定项列表链接上的注释。前三分之一看起来像是用火星语写的。跳到解释部分并开始阅读,然后返回到细节,如果需要的话

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

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从零开始。因此,当您将其加倍时,您将得到:零

删除所有内容。

此外,您还可以执行以下操作:

    delete[] itemsOnList;

    //transferring data from temp List back to Old list
    itemsOnList = tempList;
此时,itemsOnList和tempList都指向同一数组。因此下一条语句:

    delete[] tempList;

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

重要的一点是,最好及早了解:许多编程错误有时会导致它们看起来像是工作的。这意味着它可能会在一个编译器或一台计算机上“工作”一致,而不会在另一台计算机上工作,或者可能会在部分时间“工作”,然后停止“工作”突然之间,没有明显的原因。事实上,它从来没有“起作用”。无论如何,当你在构建系统1下找到“起作用”而不是构建系统2下的东西时,这几乎从来都不是构建系统的错。当你测试它时,它可能“起作用”,但当老师这样做时就不起作用了。有趣吧?在列表类定义中
Item*itemsOnList=newitem[arraySize]
不应该工作。
数组大小还没有设置,所以没有人知道会发生什么。你可以构建一个大小为0、40亿、-42或任何其他有效的
int
的数组。大多数数组会立即爆炸。@user4581301你不能实际声明一个大小为负的数组,但你已经一针见血了。同意。我同意t会立刻爆炸的。非常感谢你的帮助和解释。信息非常丰富,我学到了一些新东西!祝你有一个美好的一天!:)
    Item* itemsOnList = new Item[arraySize];
if (arrayPosition == arraySize)
{
    //doubling arraySize since we need more space
    arraySize *= 2;
    delete[] itemsOnList;

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