I'm in the process of learning C++, and I would like to understand how new and delete work for primitive types, and if there is any automatic memory management at all when not using smart pointers.
I have written the following code that tries to trigger a memory leak by repeatedly allocating memory for 10'000 integers in the heap (that is, if I understood how new works).
#include <iostream>
#include <string>
#include <algorithm>
int* MemoryLeak(const int size) {
std::cout << "Allocating space for " << size << " ints..." << std::endl;
return new int[size];
}
int main() {
std::string keepGoing = "y";
while (keepGoing != "n") {
std::cout << "Leak memory? [y/n]" << std::endl;
std::cin >> keepGoing;
std::transform(keepGoing.begin(), keepGoing.end(), keepGoing.begin(), ::tolower);
if (keepGoing == "y") {
MemoryLeak(10000);
} else if (keepGoing != "n") {
keepGoing = "y";
}
}
}
I don't have a corresponding delete call, so I would expect the memory footprint of my program to grow after each "y" I enter. However, memory footprint stays the same (according to my task manager). Why is that? And how would I have to modify my snippet in order to cause a leak?
As noted in comments, your compiler and/or operating system may be optimizing away the problem entirely.
So let's do a few things differently:
Allocate bigger blocks of memory so that the memory leak, if it exists, is easier to "see."
Use the return of MemoryLeak and write to it.
#include <iostream>
#include <string>
#include <algorithm>
int* MemoryLeak(const int size) {
std::cout << "Allocating space for " << size << " ints..." << std::endl;
return new int[size];
}
int main() {
std::string keepGoing = "y";
while (keepGoing != "n") {
std::cout << "Leak memory? [y/n]" << std::endl;
std::cin >> keepGoing;
std::transform(keepGoing.begin(), keepGoing.end(), keepGoing.begin(), ::tolower);
if (keepGoing == "y") {
int *x = MemoryLeak(10000000);
for (std::size_t i = 0; i < 10000000; i++)
x[i] = i;
} else if (keepGoing != "n") {
keepGoing = "y";
}
}
}
If, as mentioned in comments, we use smart pointers, the memory usage of the program remains constant because when the std::unique_ptr<int[]> goes out of scope, it is destroyed and the memory deallocated.
#include <iostream>
#include <string>
#include <algorithm>
#include <memory>
std::unique_ptr<int[]> MemoryLeak(const int size) {
std::cout << "Allocating space for " << size << " ints..." << std::endl;
return std::make_unique<int[]>(size);
}
int main() {
std::string keepGoing = "y";
while (keepGoing != "n") {
std::cout << "Leak memory? [y/n]" << std::endl;
std::cin >> keepGoing;
std::transform(keepGoing.begin(), keepGoing.end(), keepGoing.begin(),
::tolower);
if (keepGoing == "y") {
auto x = MemoryLeak(10000000);
for (std::size_t i = 0; i < 10000000; i++)
x[i] = i;
} else if (keepGoing != "n") {
keepGoing = "y";
}
}
}
Of course, in practice we would likely not create a unique pointer to an array but rather achieve that effect with a std::vector.
Related
I have allocated a string array in CPP with initial size and I need to dynamically resize it based on a counter.
This the initialization statement: string buffer[10];
I need to resize it based on a counter.
Is there a realloc function in cpp?
You should use something like a linked list such as std::vector or std::list to do so, here is an example:
#include <iostream>
#include <stdlib.h>
#include <string>
#include <list>
using namespace std;
int main()
{
list<string> buffer;
int count = 0;
while (true)
{
string s;
cin >> s;
if (s._Equal("exit"))
break;
buffer.push_back(s);
count++;
}
cout << endl << endl << "We have a total of " << count << " string(s):";
for (auto i = buffer.begin(); i != buffer.end(); i++)
cout << endl << "- " << (*i).c_str();
cout << endl << endl;
system("pause");
return 0;
}
link: std::vector
std::vector is a sequence container that encapsulates dynamic size arrays.
I want to increase the size of the array of string after declaring it once, how can it be done. I need to increase the size in the following code..
#include<iostream>
using namespace std;
#include<string>
int main()
{
int n;
string A[] =
{ "vaibhav", "vinayak", "alok", "aman" };
int a = sizeof(A) / sizeof(A[0]);
cout << "The size is " << a << endl;
for (int i = 0; i < a; i++)
{
cout << A[i] << endl;
}
cout << "Enter the number of elements you want to add to the string"
<< endl;
cin >> n;
cout << "ok now enter the strings" << endl;
for (int i = a; i < n + a; i++)
{
cin >> A[i];
}
a = a + n;
A.resize(a); // THIS KIND OF THING
for (int i = 0; i < a; i++)
{
cout << A[i] << endl;
}
return 0;
}
Plain and simple: you cannot.
You can get a larger array, copy all your stuff over and use that instead. But why do all that, when there is a perfectly good class already there, doing it all for you: std::vector.
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::vector<std::string> A = {"vaibhav", "vinayak", "alok", "aman"};
std::cout << "The size is " << A.size() << std::endl;
for(string s : A)
{
std::cout << s << std::endl;
}
// want to enter more?
sd::string more;
std::cin >> more;
A.push_back(more);
std::cout << "The size is " << A.size() << std::endl;
for(string s : A)
{
std::cout << s << std::endl;
}
return 0;
}
Convert your code over to use std::vector and this problem becomes much easier to solve.
#include<iostream>
#include<string>
#include<vector>
int main(){
int n;
std::vector<std::string> A = {"vaibhav", "vinayak", "alok", "aman"};
int a = A.size();
std::cout << "The size is " << a << std::endl;
//Prefer Range-For when just iterating over all elements
for(std::string const& str : A){
std::cout << str << std::endl;
}
std::cout << "Enter the number of elements you want to add to the string" << std::endl;
std::cin >> n;
std::cout << "ok now enter the strings" << std::endl;
for(int i = 0; i < n; i++ ) {
//emplace_back automatically resizes the container when called.
A.emplace_back();
std::cin >> A.back();
//If you're using C++17, you can replace those two lines with just this:
//std::cin >> A.emplace_back();
}
for(std::string const& str : A){
std::cout << str << std::endl;
}
return 0;
}
Also, don't use using namespace std;, since it leads to expensive to fix bugs and makes your code harder to read for other C++ programmers.
I want to increase the size of the array of string after declaring it
once, how can it be done.
It cannot be done. Use std::vector if the element count isn't known at compile time or can change dynamically. It even has a resize member function named exactly like the one in your code.
You cannot increase the size of a Raw Array, you could use an std::vecto<std::string> as this type of array can grow at runtime.
However, you could also create a class that will store an array of string and create your own implementation to resize the raw array. Which would be creating a bigger array and copying all the other values over, then setting the class array to the new array (or just return it)
I've been trying to get this Hangman using functions (from Michael Dawson's book) program to work, but I have this one error that I don't really understand. I realize my code code could have a variety of bad practices, but please go easy on me as I am a newb. I feel like I am almost there but I'm having trouble figuring out this one error. I am using CodeBlocks. The error is:
32|error: no match for call to '(std::__cxx11::string {aka std::__cxx11::basic_string}) (std::__cxx11::basic_string::size_type, char)'|
//Hangman from Michael Dawson's code
//Uses functions to create the program
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <ctime>
#include <cctype>
using namespace std;
//FUNCTION DECLARATION
string pickword();
char playerGuess();
void isitinthere();
char guess = 0;
string soFar = "word";
string used = "";
int wrong = 0;
int main()
{
const int MAX_WRONG = 8;
string WORD = pickword();
soFar = WORD;
soFar(WORD.size(), '-');
used = "";
cout << "Welcome to Hangman! Godspeed!" << endl;
while ((wrong < MAX_WRONG) && (soFar != WORD))
{
cout << "\n\nYou have " << (MAX_WRONG - wrong);
cout << " incorrect guesses left.\n";
cout << "\nYou've used the following letters:\n" << used << endl;
cout << "\nSo far, the word is:\n" << soFar << endl;
}
playerGuess();
while (used.find(guess) != string::npos)
{
cout << "\nYou've already guessed " << guess << endl;
cout << "Enter your guess: ";
cin >> guess;
guess = toupper(guess);
}
used += guess;
isitinthere();
if (wrong == MAX_WRONG)
{
cout << "\nYou've been hanged!";
}
else
{
cout << "\nYou guessed it!";
}
cout << "\nThe word was " << WORD << endl;
return 0;
}
//FUNCTION DEFINITION
string pickword()
{
srand(static_cast<unsigned int>(time(0)));
vector<string> words;
words.push_back("INDUBITABLY");
words.push_back("UNDENIABLY");
words.push_back("CRUSTACEAN");
words.push_back("RESPONSIBILITY");
words.push_back("MISDEMEANOR");
words.push_back("FORENSIC");
words.push_back("BALLISTIC");
words.push_back("PARADIGM");
words.push_back("TROUBARDOR");
words.push_back("SUPERCALIFRAGILISTICEXPIALLADOCIOUS")
random_shuffle(words.begin(), words.end());
theword = words[0];
return theword;
}
char playerGuess()
{
cout << "\n\nEnter your guess: ";
cin >> guess;
guess = toupper(guess);
return guess;
}
void isitinthere()
{
if (WORD.find(guess) != string::npos)
{
cout << "That's right! " << guess << " is in the word.\n";
for (int i = 0; i < WORD.length(); ++i)
{
if (WORD[i] == guess)
{
soFar[i] = guess;
}
}
}
else
{
cout << "Sorry, " << guess << "isn't in the word. \n";
++wrong;
}
}
Thanks in advance for your help!
Here is a simple program that should solve your question.
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <cctype>
// since you must have function here are some
bool removeGuessFromWord(std::string& word, const char guess);
bool isGuessInWord(const std::string& word, const char guess);
bool hasAlreadyGuessed(const std::vector<char>& gussList, const char guess);
// this is a simple program that should solve your question. It is not optimized for speed or efficency.
int main()
{
std::vector<std::string> wordList = {"dog","cat","rat"}; // vector of words to select from and use as the word in hangman
std::vector<char> guessList; // empty vector of gusses
// Note that I assume a MAX_GUESS_COUNT of 0 means no guesses are allowed
const unsigned int MAX_GUESS_COUNT = 4U; // number of guesses your allowed
std::srand(time(0)); // use current time as seed for random generator
std::string word = wordList.at(std::rand()%wordList.size()); // get a random word in the list
std::string letersLeft = word; // keep track of what letters will still need to remove
std::cout << "Welcome to Hangman! Godspeed!" << std::endl;
char guess = 0;
for(unsigned int numBadGusses=0U; numBadGusses<MAX_GUESS_COUNT && letersLeft.size()>0U; guess = 0)
{
std::cin>>guess;
if(std::isprint(guess) == 0)
{
// may want more error checking
std::cout << "You ented a non-printable charecter" << std::endl;
}
else if(isGuessInWord(word, guess))
{
// this was a good guess because the charecter is still in the word
// so remove all the remaining chars of this type from the word
if( removeGuessFromWord(letersLeft,guess) )
{
std::cout << guess << " was a good guess" << std::endl;
}
else
{
std::cout << guess << " was a good guess, but you already guessed it once" << std::endl;
}
}
else if(hasAlreadyGuessed(guessList, guess))
{
std::cout << "You've already guessed " << guess << std::endl;
}
else
{
// this was a new bad guess
guessList.push_back(guess);
numBadGusses++; // Note that this isn't technicly needed and could use size of vector
std::cout << guess << " was a bad guess" << std::endl;
}
}
if(letersLeft.size() == 0U)
{
std::cout<<"You Win"<<std::endl;
}
else
{
std::cout<<"You Lose"<<std::endl;
}
std::cout << "The word was "<< word << std::endl;
return 0;
}
bool removeGuessFromWord(std::string& word, const char guess)
{
return word.erase(std::remove(word.begin(), word.end(), guess), word.end()) != word.end() ? true : false;
}
bool isGuessInWord(const std::string& word, const char guess)
{
return word.find(guess) != std::string::npos ? true: false;
}
bool hasAlreadyGuessed(const std::vector<char>& gussList, const char guess)
{
return std::find(gussList.begin(), gussList.end(), guess) != gussList.end() ? true: false;
}
I am writing a simple bracket checker. Should be pretty easy. I had it working when it was all in one function, but I am required to also make something for stdin. So I thought it was best to make 2 functions. That being said I am getting an error on the checking if the stack is null on line 82. for whatever reason it is not allowing me to check if the top of my stack is null. I tried in a testing program to see if it was some sort of referencing error or if it was going out of scope by going into the other method. Its not. Should work fine because it is a global variable.
Thoughts on what I am doing wrong? All my interneting and knowledge points me to the idea that I am doing it correctly.
Below is all of the code. its compilable. if I need to clarify anything I would be more than happy to.
Thanks
#include <iostream>
#include <sstream>
#include <stack>
#include <deque>
#include <fstream>
#include <cstdlib>
using namespace std;
stack<char> BracketsCheck;
int linecounter = 0;
int FileNumber = 1;
int pos;
string str ="";
string filename;
int validate(string string)
{
int size = str.size();
for (int i = 0; i < str.size(); i++)
{
pos = i;
if ((str[i] == '(' ) || (str[i] == '[') || (str[i] == '{'))
{
BracketsCheck.push(str[i]);
}
else if (str[i] == ')')
{
if (BracketsCheck.top() == '(')
BracketsCheck.pop();
else
{
cout << filename << ":" << linecounter << ":" << pos << "ERROR: missing open parenthesis" << endl;
return EXIT_FAILURE;
}
}
else if (str[i] == ']')
{
if (BracketsCheck.top() == '[')
BracketsCheck.pop();
else
{
cout << filename << ":" << linecounter << ":" << pos << "ERROR: missing open squre bracket" << endl;
return EXIT_FAILURE;
}
}
else if (str[i] == '}')
{
if (BracketsCheck.top() == '{')
BracketsCheck.pop();
else
{
cout << filename << ":" << linecounter << ":" << pos << "ERROR: missing open curly brace" << endl;
return EXIT_FAILURE;
}
}
}
}
int main(int argc, char* argv[])
{
// BracketsCheck.top() = 'h';
if (argc == 1)
{
cin >> str;
cout << "no arguments" << endl;
validate (str);
return 0;
}
else
{
while (argv[FileNumber] != NULL)
{
filename = argv[FileNumber];
ifstream inFile(argv[FileNumber]);
cout << argv[FileNumber]<<endl;
while (getline(inFile, str))
{
validate(str);
linecounter++;
}
if (BracketsCheck.top() != NULL)
{
cout << "got to null checker" << endl;
cout << filename << ":" << linecounter << ":" << pos << "umatched closing brace" << endl;
return EXIT_FAILURE;
}
FileNumber++;
}
return 0;
}
}
Based on your response to my comments. If you are trying to check if the stack is not empty you should use !BracketsCheck.empty() also:
int validate(string string)
is probably not a good idea since you will hiding the string type.
top() will return a reference or const reference not a pointer and if your stack is empty you should not be calling top.
I would also discourage you from using:
using namespace std;
it is considered bad practice I realize typing std:: all the time can be annoying at first but you really do get used to it after a while.
Finally validate needs a return statement since it is supposed to return int and flowing off the end of function without a return in this case will invoke undefined behavior as per 6.6.3 The return statement paragraph 2 from the draft C++ standard.
I am just starting to learn C++ and this is a program I'm writing for an exercise:
#include <iostream>
#include <string>
using namespace std;
int main ()
{
int uppercase=0, lowercase=0, digits=0, other=0, i=0;
int character;
char* string;
cout << "Enter a string!\n";
cin.getline(string, 20);
while(true)
{
character = int(*(string+i));
if (character==0)
{
break;
}
if (character > 64 && character < 91)
{
uppercase++;
}
if (character > 96 && character < 122)
{
lowercase++;
}
if (character > 47 && character <58)
{
digits++;
}
else
{
other++;
}
i++;
}
cout << "Upper case " << uppercase << "\n";
cout << "Lower case " << lowercase << "\n";
cout << "Digits " << digits << "\n";
cout << "Others " << other << "\n";
return 0;
}
The program crashes after it finishes printing the results. Am I missing something really obvious here?
Side question: The variable 'other' is always increased even if it shouldn't be. Am I using the else statement wrong?
You have not allocated memory for string
Try this (allocate on stack):
char string[256];
or (allocate on heap):
char* string = new char[256];
delete[] string;
UPDATE
Using std and predefined isdigit(), isalpha(), etc, the code can be rewritten as follows:
#include <iostream>
#include <string>
int main ()
{
int uppercase=0, lowercase=0, digits=0, other=0;
std::cout << "Enter a string!\n";
std::string myline;
std::getline(std::cin, myline);
for (std::string::iterator i = myline.begin(); i != myline.end(); ++i)
{
if (isdigit(*i))
{
digits++;
}
else if (isalpha(*i))
{
isupper(*i) ? uppercase++
: lowercase++;
}
else
{
other++;
}
}
std::cout << "Upper case " << uppercase << "\n";
std::cout << "Lower case " << lowercase << "\n";
std::cout << "Digits " << digits << "\n";
std::cout << "Others " << other << "\n";
return 0;
}
The else statement is executed if the preceding if statement is false. In your case, other is increased when (character > 47 && character <58) is false. You probably want to be using else-if's instead:
if(){
...
}else if{
...
}else if{
...
}else{
...
}
Try char string[256] instead of char* string;. I guess getline requires a pointer to allocated memory as input.
You have not allocated memory for string and using that name is probably not a good idea:
char* string ;
and alternative declaration that would work and not shadow std::string since you are have using namespace std:
char str[21] ;
In your code if you want to use std::string you have to do this:
std::string someStringVar ;
since using this won't work after you declare char *string:
string someStringVar ;
which seems to defeat the purpose of using namespace std.
You should use char instead of int to represent character. It's because int is usually 4 bytes and char is only 1 byte (so just enough to represent one character).