i want to take a simple array of string from the user in a dynamic array. If i made the size of the array 1000 for example. how to delete the unused space in the array so that it fits just for the size the user entered without deleting the whole array?
Memory allocators do not typically allow for deallocating parts of allocated memory, and the allocation facilities specified in C++ certainly do not provide any interface to such functionality.
There is a standard function 'realloc' which may allow an allocated block of memory to be, apparently, expanded. However the way this typically works is that the underlying allocator checks to see if previously allocated block of memory is already large enough. That is, when you allocate, say, 1000 bytes, the allocator may provide a chunk of memory that is larger than 1000 bytes.
That hidden 'extra' memory is valid to access just as if you had asked for it, but since you didn't ask for it and don't know how much, if any, extra memory is there, you are limited to only accessing the bytes you actually requested.
realloc will provide to you allocated memory of the new size, with the same contents as the memory pointed to by the parameter you pass to it. It may do this by discovering that the existing block of memory is large enough for the requested new size, in which case it simply returns the same pointer you pass to it. In this case you know there was extra memory and now you can access up to the size you requested.
If there's not enough 'extra' memory, or if the realloc implementation is simple, then realloc will allocate a new block, copy the data into the new block, free the old block, and return the new pointer.
Reducing the amount of memory for an array will pretty much always mean allocating a new, smaller array, copying the content into the new array, and then freeing the old, larger array. For example vector::shrink_to_fit and the old 'swap with empty' trick do this.
If you want to avoid having too much memory allocated, then you should simply avoid allocating too much in the first place. You should just allocate the correct amount to start with.
One side benefit if this approach is that it means you won't engage in the bad practice of, for example, allocating an array of some fixed size which you think is larger than you will ever need:
#include <iostream>
#include <string>
int main() {
std::string user_input[10000]; // should be enough for anyone
int count = 0;
for (std::string s; std::cin >> s;) {
user_input[count] = s;
++count;
}
magic_array_size_reducing_function(user_input, count);
}
The above code is wrong, because the user might exceed the fixed limit and cause the program to break. In fact, any time you see such fixed limits you should be suspicious, and the code probably needs to be fixed. You should also be suspicious of any beginning programming book or course that asks you to do this.
The right way to write this is to not have fixed limits, and instead dynamically increase resource usage as necessary.
#include <iostream>
#include <string>
#include <vector>
int main() {
std::vector<std::string user_input;
for (std::string s; std::cin >> s;) {
user_input.push_back(s);
}
//...
}
Doing this by hand simply means doing the allocation/copy/deallocation dance as necessary. Below is an example where I implement just the bare minimum.
#include <iostream>
#include <string>
struct dynamic_string_array {
int capacity, size;
std::string *user_input;
dynamic_string_array() {
capacity = 0;
size = 0;
user_input = nullptr;
}
~dynamic_string_array() {
delete [] user_input;
}
void push_back(std::string const &s) {
if (size == capacity) {
int new_capacity = capacity ? 16 : capacity * 1.5;
std::string *new_user_input = new std::string[new_capacity];
for (int i = 0; i < size; ++i) {
new_user_input[i] = user_input[i];
}
// ---
delete [] user_input;
user_input = new_user_input;
capacity = new_capacity;
}
user_input[size] = s;
++size;
}
};
int main() {
dynamic_string_array user_input;
for (std::string s; std::cin >> s;) {
user_input.push_back(s);
}
//...
}
Related
I made a program for school's little contest, I have:
#include <iostream>
#include <vector>
int main(){
int n;
std::cin >> n;
int c[n];
std::vector<int> r(n);
std::cout << "I made it through";
//rest of program
}
When i type in 1000000 and press enter program crashes without a word, exit code (0xC00000FD). I presumed it happens when i initialize vector, but i though it can handle a lot more. Am i doing something wrong? I know i can use pointer but i'd prefer not to touch things that are already working.
The stack is a very restricted resource.
Even though your compiler seems to implement C-style VLA's in C++ (int c[n];), it does not magically gain more memory.
Test 1) Success of reading n, and 2) n not being out-of-bounds for your use before executing the statement allocating that stack-array.
Default stack-size for Windows: 1MB sizeof(int): 4 Thus, about 250000 fit.
Default stack size for Linux: 8MB sizeof(int): 4 Thus, about 2000000 fit.
Workaround: Use dynamic allocation for the ints, like with a std::vector:
std::vector<int> c(n);
Alternatively, at least use a smart-pointer:
std::unique_ptr<int[]> c(new int[n]);
The problem isn't vector (which uses the heap for its underlying expanding storage in most STL implementations), but int c[n], which will allocate 1,000,000 4-byte integers in the stack, which is almost 4MB. On Win32 the stack is by default around 1MB, hence the overflow.
If you really need to use an array then change your c array to be allocated on the heap by using new, but don't forget to delete[], otherwise use of vector is preferred for most expanding storage scenarios. If you need a fixed-length array then consider array<class T, size_t N> (new in C++11) which adds bounds-checking.
You probably just need to allocate the array dynamically. In C++
#include <iostream>
#include <vector>
int main()
{
int n;
std::cin >> n;
int *c = new int[n];
if(nullptr == c) {
std::cerr << "Runtime error" << std::endl;
return 1;
}
std::vector<int> r(begin(n), end(n));
std::cout << "I made it through";
delete[] c;
return 0;
}
Also to make the vector after you have allocated c dynamically you can use begin, end
I am writing a big code and I prepared a memory class in order to create and grow different types of arrays safely. In this class I keep track of the size of memory that allocated using sizeof when allocating a new pointer. However, I do not know how to keep track of the memory allocating.
Let me put my question in another way. For example suppose we allocate a new array at some point in the code:
double* array=new double[size];
and some place else we want to deallocate the memory without knowing the size, normally we use
delete [] array;
delete operator automatically frees the memory of array, is there any way to determine how many bytes does it free (supposing that we don't keep track of size)?
In general, the answer is no, because memory managers hide that kind of implementation-dependent information from you. Also, C++ doesn't provide any standard way of tracking how much memory is actually used/freed. There might be functions specific to a certain platform/operating system, but nothing that is 100% portable.
use a std::vector instead and when you delete it you can call this beforehand to find out how much was cleared: vec.capacity() * sizeof(OBJECT) will give you the amount of bytes stored in the vector.
To keep track of allocated memory you need to implement manuelly some kind of counting mechanism, for example with a static (private) member which counts the allocated bytes.
If you want to have full control over memory allocation and deallocations you should use amemory pool.
Home grown memory pools are fast, safe and relatively easy to implement - unless you want fancy stuff. Implementing such a mechanism will provide you will all kinds of information such as memory leaks too. Calculating the memory freed is also a breeze because the linked list holds the total memory allocated.
Click the big friendly button to dive in.
I realize another answer was already accepted, but here is how you write your own allocators if you wanted to very simply track memory arrays:
#include <map>
#include <iostream>
using namespace std;
map<void*,size_t> memmap; //put this as a global variable in an implementation file, and extern it in the header file.
class MyManagedClass{
public:
MyManagedClass(){}
void* operator new[](size_t sz){
void* out = operator new(sz*sizeof(MyManagedClass));
for(size_t i=0; i<sz; ++i)
*((MyManagedClass*)out+sz)=MyManagedClass::MyManagedClass();
memmap[out] = sz;
return out;
}
void operator delete[](void* t){
cout << "Freed units: " << memmap[t] << endl;
memmap.erase(t);
delete[] t;
}
};
int main(){
MyManagedClass* ip = new MyManagedClass[10];
delete[] ip;
system("pause");
}
I should mention that this is a scrappy way to do it, and you could probably make it nicer/generic with templates and a more thought out memory design lol.
#include <cstdlib>
#include <cstring>
#include <string>
using std::string;
string *arr_ptr;
int capacity;
void add() {
int old_capacity = capacity;
capacity <<= 1;
// double the capacity
string *tmp_ptr = new string[capacity];
// apply new space
memmove(tmp_ptr, arr_ptr, sizeof(string) * old_capacity);
// copy
delete[] arr_ptr;
// free the original space
arr_ptr = tmp_ptr;
arr_ptr[capacity - 1] = "occupied";
// without this statement, everything "seems" to be fine.
}
int main() {
arr_ptr = new string[1];
capacity = 1;
for (int i = 0; i < 3; i++) add();
}
Run the code. As you can see, the program crashes when string's desctrutor is invoked. Try to comment the line of delete and check again.
I suspect that std::string keeps some address information of itself. It won't be informed when its location in memory has changed.
Furthermore, since memmove doesn't always work as expected, what's the appropriate expression of copying an array of class instance in C++?
memmove is a lowlevel function for copying bytes. This means that the value of an array of bytes is copied to another array. This is fine for POD data, but not for anything else. The reason is that classes can have a copy constructor, which isn't called by memmove and classes can have extra data like a vpointer for calling virtual member-functions.
The easiest solution for you is to replace memmove with std::copy for (#include <algorithm>) which copies entries instead of bytes:
std::copy(arr_ptr, arr_ptr + old_capacity, tmp_ptr);
I believe what you are looking for is string::reserve.
In your code, you are also trying to make an array of string (and not a string as an array of character).
What you are doing here is copying the object 'string', and not its content (since you are not calling its constructor / destructor).
Therefore, when you 'delete' your "arr_ptr", the destructor free the data associated.
When you try to access it with tmp_ptr, the program segfault.
1st you don't initialize the value of your capacity as in:
int capacity;
should be:
int capacity = 0;
and when you try this operation:
arr_ptr[capacity - 1] = "occupied";
there is a referencing error that may occur.
The behaviour of this program is ::std::string implementation dependent.
If the implementation of string uses heap memory to store the characters, memmoveing an instance of string means there are two pointers pointing to the same heap memory. Calling the destructor of one of the string instance causes the heap memory to be freed, resulting in the other instance of string to have a dangling pointer.
So don't memmove strings :)
I need to simulate an incremental garbage collection algorithm in C++ or Java. I had a doubt based on this.
As an input (stdin from keyboard), I will be asked to allocate some memory for this code. The syntax would be:
x = alloc(128KB);
My question: is it ok to use malloc for the assignment? Or is there any other way to allocate memory? I had this doubt because, the size can go up to GB for the assignment, so using malloc might not be a good idea I think.
First of all, if you want to prohibit a huge memory allocation, just check users' input value, but I'm not sure how much memory you think as a huge memory. I think you don't worry about that, because if memory allocation failed, malloc and calloc will return a NULL pointer.
Secondly, you can also use 'calloc' for this case.
void calloc(size_t num, size_t size);
'num' is mean elements' count for allocation and 'size' is, of course, the size of element. Below codes have the same result.
ar = (int *)malloc(5 * sizeof(int));
ar = (int *)calloc(5, sizeof(int));
However, if you choose 'calloc', you may manage more logically your code, since you can divide memory quantity by unit and count.
Also, if you use 'calloc', you don't need to use memset for setting memory value to zero.
'calloc' set automatically memory value to zero.
I hope this article can help you.
malloc can allocate as much memory as you wish provided you don't go past ulimits. Give the following a go to test it out:
#include <stdlib.h>
#include <string.h>
#define ONEGB (size_t)(1073741824)
int main() {
char *p;
p = malloc(ONEGB);
if (!p) {
perror("malloc");
}
else {
memset(p, 0, ONEGB);
}
return 0;
}
I have this function:
char* ReadBlock(fstream& stream, int size)
{
char* memblock;
memblock = new char[size];
stream.read(memblock, size);
return(memblock);
}
The function is called every time I have to read bytes from a file. I think it allocates new memory every time I use it but how can I free the memory once I have processed the data inside the array? Can I do it from outside the function? Processing data by allocating big blocks gives better performance than allocating and deleting small blocks of data?
Thank you very much for your help!
Dynamic arrays are freed using delete[]:
char* block = ReadBlock(...);
// ... do stuff
delete[] block;
Ideally however you don't use manual memory management here:
std::vector<char> ReadBlock(std::fstream& stream, int size) {
std::vector<char> memblock(size);
stream.read(&memblock[0], size);
return memblock;
}
Just delete[] the return value from this function when you've finished with it. It doesn't matter that you're deleting it from outside. Just don't delete it before you finish using it.
You can call:
char * block = ReadBlock(stream, size);
delete [] block;
But... that's a lot of heap allocation for no gain. Consider taking this approach
char *block = new char[size];
while (...) {
stream.read(block, size);
}
delete [] block;
*Note, if size can be a compile time constant, you can just stack allocate block.
I had a similar question, and produced a simple program to demonstrate why calling delete [] outside a function will still deallocate the memory that was allocated within the function:
#include <iostream>
#include <vector>
using namespace std;
int *allocatememory()
{
int *temppointer = new int[4]{0, 1, 2, 3};
cout << "The location of the pointer temppointer is " << &temppointer << ". Locations pointed to by temppointer:\n";
for (int x = 0; x < 4; x++)
cout << &temppointer[x] << " holds the value " << temppointer[x] << ".\n";
return temppointer;
}
int main()
{
int *mainpointer = allocatememory();
cout << "The location of the pointer mainpointer is " << &mainpointer << ". Locations pointed to by mainpointer:\n";
for (int x = 0; x < 4; x++)
cout << &mainpointer[x] << " holds the value " << mainpointer[x] << ".\n";
delete[] mainpointer;
}
Here was the resulting readout from this program on my terminal:
The location of the pointer temppointer is 0x61fdd0. Locations pointed to by temppointer:
0xfb1f20 holds the value 0.
0xfb1f24 holds the value 1.
0xfb1f28 holds the value 2.
0xfb1f2c holds the value 3.
The location of the pointer mainpointer is 0x61fe10. Locations pointed to by mainpointer:
0xfb1f20 holds the value 0.
0xfb1f24 holds the value 1.
0xfb1f28 holds the value 2.
0xfb1f2c holds the value 3.
This readout demonstrates that although temppointer (created within the allocatememory function) and mainpointer have different values, they point to memory at the same location. This demonstrates why calling delete[] for mainpointer will also deallocate the memory that temppointer had pointed to, as that memory is in the same location.
Yes. You may call delete from outside of the function. In this case though, may I suggest using an std::string so you don't have to worry about the management yourself?
first thing to note: memory allocated with new and delete is completely global. things are not automatically deleted when pointers go out of scope or a function is exited. as long as you have a pointer to the allocation (such as the pointer being returned there) you can delete it when ever and where ever you want. the trick, is just makeing sure other stuff doesn't delete it with out you knowing.
that is a benefit with the sort of function structure the fstream read function has. it is fairly clear that all that function is going to do is read 'size' number of bytes into the buffer you provide, it doesn't matter whether that buffer has been allocated using new, whether its a static or global buffer, or even a local buffer, or even just a pointer to a local struct. and it is also fairly clear that the function is going to do nothing more with the buffer you pass it once it's read the data to it.
on the other hand, take the structure of your ReadBlock function; if you didn't have the code for that it would be tricky to figure out exactly what it was returning. is it returning a pointer to new'd memory? if so is it expecting you to delete it? will it delete it it's self? if so, when? is it even a new pointer? is it just returning an address to some shared static buffer? if so, when will the buffer become invalid (for example, overwritten by something else)
looking at the code to ReadBlock, it is clear that it is returning a pointer to new'd memory, and is expecting you to delete it when ever you are done with it. that buffer will never be overwritten or become invalid until you delete it.
speed wise, thats the other advantage to fsream.read's 'you sort out the buffer' approach: YOU get the choice on when memory is allocated. if you are going "read data, process, delete buffer, read data process delete buffer, ect.... " it is going to be alot more efficient to just allocate one buffer (to the maximum size you will need, this will be the size of your biggest single read) and just use that for everything, as suggested by Stephen.
How about using a static char* memblock; It will be initialised just once and it wont allocate memblock a new space everytime.
Since c++11, one can use std::unique_ptr for this purpose.
From https://en.cppreference.com/book/intro/smart_pointers :
void my_func()
{
int* valuePtr = new int(15);
int x = 45;
// ...
if (x == 45)
return; // here we have a memory leak, valuePtr is not deleted
// ...
delete valuePtr;
}
But,
#include <memory>
void my_func()
{
std::unique_ptr<int> valuePtr(new int(15));
int x = 45;
// ...
if (x == 45)
return; // no memory leak anymore!
// ...
}