-4

I ran into a problem, from an exercise in Bjarne Stroustrup's book Programming: Principles and Practice Using C++ (2nd edition), at the very end of chapter 17 for the Exercises section, exercise 7:

The program works normally if you do not use delete linearray1;. Accordingly, the problem is when deleting the allocated dynamic memory.

I have no error messages or warnings in the console. However, VS Code shows me that problem in this line (delete linearray1). Highlights the entire line in yellow.

Tell me how to solve the problem in this case. How can I correctly clear the allocated memory?

#include <iostream> 

void fillarray(std::string& array)
{ 
    char* linearray1 {new char};
    char* line = linearray1;
    std::cin >> line;
    
    while (*line)
    {   
        if (*line == '!')
            break;
        array += *line;
        line++;
    }
    delete linearray1;
}

int main()
{

    std::string linearray1;
    fillarray(linearray1);
    std::cout << "\n" << linearray1;
    return 0;
}
21
  • 6
    char* linearray1 {new char}; creates a pointer to a single char. Why are you trying to mix std::string and manual memory management of c-style arrays? Commented Dec 14, 2024 at 13:52
  • 3
    I have not needed to use new in a real C++ program in 13 years. Use smart pointers. The smart pointer for strings that manages the memory backing store for you is called std::string.
    – Eljay
    Commented Dec 14, 2024 at 14:05
  • 6
    The problem is not on the line with delete. The problem is that you allocated only space for one char (basically, only enough to hold the NUL terminator), but tries to read a string from cin to it, which is UB and anything can happen. That removing the delete line makes the program appears to work proves nothing. It still has UB without the delete line. Commented Dec 14, 2024 at 14:13
  • 3
    @marcusreed I want to emphasize that when deleting a line: *line0 = '\0'; delete operation works correctly! -- No it doesn't. There is this piece of important information you are missing -- when you use manual memory management, if you write beyond or outside the bounds of the allocated memory, there is no guarantee that your "works". You are invoking undefined behavior. I took your code, commented out the line you mentioned, and ran it under a sanitizer -- you see that you are corrupting memory. Commented Dec 14, 2024 at 15:36
  • 3
    And speaking of undefined behavior, C++ (and C) are the rare languages where this occurs. If you expected that automatically some sort of error popup or exception is thrown when you make these types of mistakes, you are mistaken. This is why C++ is a complex language, unlike probably most others. With Java, python, C#, etc. you make a mistake, you know right away by having an exception thrown or similar -- not so with C++. Commented Dec 14, 2024 at 15:40

1 Answer 1

2

To summarize the comments...

In fillarray(), you are allocating dynamic memory for only 1 char, and then passing that buffer to the operator>> overload that reads a word into a char[] buffer. That overload will try to read and output more than 1 char (including a '\0' terminator) until it encounters a whitespace character that ends the input. So, you end up invoking undefined behavior by writing out of bounds of your dynamic memory, thus corrupting surrounding memory. And in this case, delete seems to be just an unwitting victim of that behavior.

If you really want to read the input 1 char at a time, then use the operator>> overload that reads a single char, or use the istream::get(char&) method instead, eg:

void fillarray(std::string& array)
{ 
    char* pch {new char};
    
    while ((std::cin >> *pch) && (*pch != '!'))
    // or: while (std::cin.get(*pch) && (*pch != '!'))
    {   
        array += *pch;
    }

    delete pch;
}

But, there is no need to dynamically allocate 1 char by itself, just use a local char variable instead, eg:

void fillarray(std::string& array)
{ 
    char ch;
    
    while ((std::cin >> ch) && (ch != '!'))
    // or: while (std::cin.get(ch) && (ch != '!'))
    {   
        array += ch;
    }
}

However, in this particular example, you can just read directly into your target std::string by using std::getline() instead, eg:

void fillarray(std::string& array)
{ 
    std::getline(std::cin, array, '!');
}
1
  • Remy!Remy! Thank you very much for your time! The problem was actually a little different, all because of my carelessness! By the way, I figured it all out and am going to write a full answer to my own question later Your answer turned out to be very interesting in terms of choosing an alternative for solving this problem. I will take it into account when writing subsequent works. Thanks again! Commented Dec 15, 2024 at 6:11

Not the answer you're looking for? Browse other questions tagged or ask your own question.