Home > other >  Why does assigning a value to a string in a struct crash the program?
Why does assigning a value to a string in a struct crash the program?

Time:07-07

I have commented out the problematic string, attempted to pass the input to a string that is not a member of the struct, then passing it to the correct string, to no avail. To achieve the intended function, the string must go through this struct. Where is it going wrong? Structure code:

#include <iostream>
#include <string>
#include <fstream>
#include <iomanip>

using namespace std;

class passingdata
{
    public:
    passingdata()
    {
        //constructor
    };
    ~passingdata()
    {
        //destructor
    };
    int convertedResponse;
    const string headers[4] = {"Labor/Materials", "Cost (per unit)", "Total Units", "Total Cost"}; //this is all to be written to a file later.
    struct dynInputs
    {
        string name;
        int perCost;
        int unitTotal;
        int totalCost = perCost * unitTotal;
    };
    void acceptInputs()
    {
        string name = "";
        string response = "";
        const string positiveResponse = "yes";
        cout << "Would you like to insert a label?" << endl;
        getline(cin, response);
        if (response == positiveResponse)
        {
            populateSaveData();
        }
        else
        {
            //nothing yet
        }
    }

    void populateSaveData()
    {
        if (convertedResponse = 1)
        {
            cout << "How many labels would you like to create?" << endl;

            int labelCount;
            cin >> labelCount;
            cin.clear();
            int labelsNeeded = labelCount;
            dynInputs* dynamicInputs;
            dynamicInputs = new dynInputs[labelsNeeded];
            while (labelsNeeded > 0)
            {
                cout << "please type the name for this row" << endl;
                cin.ignore();
                //string tempName = "";
                //getline(cin, tempName); this works!
                getline(cin, dynamicInputs[labelsNeeded].name); //this breaks, goes to trash memory when done this way
                system("pause");
                cin.clear();
                //tempName = dynamicInputs[labelsNeeded].name; breaks as well
                cout << dynamicInputs[labelsNeeded].name << endl;
                //cout << tempName << endl;
                system("pause");
                cout << "please type the cost of the unit, and the number of units" << endl;
                cin >> dynamicInputs[labelsNeeded].perCost;
                cin.clear();
                cin >> dynamicInputs[labelsNeeded].unitTotal;
                cin.clear();
                labelsNeeded--;
            }
            cout << dynamicInputs[0].unitTotal << endl;

The dynamicInputs[labelsNeeded] array points to junk memory, yet I'm unsure of why it only crashes assigning value to the string.

CodePudding user response:

In labelsNeeded you store the size of the array.

Then in the first iteration you use labelsNeeded to index into your array. Since C indexes an array starting from 0, the largest possible valid index is (the size of the array) - 1.

Eg.: For an array of size 4, your valid index range is [0, 1, 2, 3].

Now what you are doing is setting labelsNeeded to equal labelCount and then allocate an array of the size equalig labelsNeeded. And then in the first iteration you use the value of labelsNeeded as an index with this original value for accessing an element in your array. Which goes past the valid range of your array. Hence the program crashes.

I see that at the and of the iteration you decrement labelsNeeded but that is too late considering that you already tried to use the original value earlier in the code.

Your labelsNeeded > 0 condition for your while loop is also incorrect if you are using this "decrement the index at the end of the iteration" solution since it will fail to write the first (at index 0) element of your array.

Try moving the labelsNeeded-- line to the beginning of the iteration.

Note:

As to "why it only crashes assigning value to the string".

C (or rather the runtime) does not care whether your pointer points to a valid address or not. Simply because a pointer is just a memory address. By it self it is just a number stored in memory. A pointer that references invalid memory will only crash your program (or do other weird stuff) if you want to dereference it or in other words -> If you want to actually use the pointer to access that place in memory. It is not the "invalid" memory address in the pointer that crashes but the act of trying to access the memory at that address. The distinction may look subtle but is very important nonetheless. You can have any number of "null pointers" in the program as long as you don't try to dereference null.

Note 2:

Yours is an especially interesting mode of failure since it can fail in one of two places:

  1. Since you are indexing an element that is one past the end of the array, that may as well coincide with the end of the heap that was assigned to the program. So it may crash there. But... Most likely your array is not allocated in such a place and there will still be accessible heap past the end of your array so dereferencing one element past your array may as well give you "something" and by something I mean some memory content cast to the type that you have. But of course from your point of view that is some random data.

  2. If execution survived the previous section and now you have a struct with random data, you also have your string in your struct that is also filled with random garbage. Which means its pointer to the actual string content is also random (most likely pointing somewhere before or past your addressable space) as well as its size and other state information also being garbage. So if you reassign that string then its original content pointer will likely be accessed (eg.: deallocation) which will result in a crash.

  • Related