"Grow" function for dynamic arrays generating an error - c++

Beginner programmer here.
The code below seems to always run into an error called: "pointer being freed was not allocated", and I can't figure out why.
A struct contains dynamic arrays to store integers and strings after reading in a file. This file contains a list of city names, high and low temperatures. Then, these are stored into the dynamic arrays after reading those lines, and grow the dynamic arrays if necessary (double the size).
Did I write something incorrect for this "grow" code function?
int i = 0;
if ( i >= arr1.size){ //arr1 is a int declared in a struct
string *tempStr; //temporary string
tempStr = new string[arr1.size*2];
int *tempInt; //temporary int
tempInt = new int[arr1.size*2];
for (int a = 0; a < arr1.size; a++){
tempStr[a] = arr1.cityName[a]; //cityName is a dynamic array declared in struct as a string
tempInt[a] = arr1.hiTemp[a]; //hiTemp --> dynamic array declared in struct as an int
tempInt[a] = arr1.loTemp[a]; //loTemp --> dynamic array declared in struct as an int
}
delete[] arr1.cityName;
delete[] arr1.hiTemp;
delete[] arr1.loTemp;
arr1.cityName = tempStr;
arr1.hiTemp = tempInt;
arr1.loTemp = tempInt;
arr1.size = arr1.size*2; //doubling the size
}
i++;

tempInt[a] = arr1.hiTemp[a];
tempInt[a] = arr1.loTemp[a];
You've using the same temp array for both.
And then you do:
arr1.hiTemp = tempInt;
arr1.loTemp = tempInt;
So now your struct has two different pointers pointing to the same array.
That means the next time something runs your grow algorithm on that struct, it'll get to:
delete[] arr1.hiTemp;
delete[] arr1.loTemp;
and consequently try to delete the same memory twice, which is of course very bad.
So you need to fix this to use two separate new int arrays.
(Or just replace all this with std::vectors since those are much easier to manage.)

Related

Why use a dynamic array instead of a regular array?

The following code is used to demonstrate how to insert a new value in a dynamic array:
#include <iostream>
int main()
{
int* items = new int[5] {1, 2, 3, 4, 5}; // I have 5 items
for (int i = 0; i < 5; i++)
std::cout << items[i] << std::endl;
// oh, I found a new item. I'm going to add it to my collection.
// I do this by
// (1) allocating a bigger dynamic array
// (2) copying the existing elements from the old array to the new array
// (3) deleting the old array, redirecting its pointer to the new array
int* items_temp = new int[6];
for (int i = 0; i < 5; i++)
items_temp[i] = items[i];
items_temp[5] = 42;
delete[] items;
items = items_temp;
for (int i = 0; i < 6; i++)
std::cout << items[i] << std::endl;
delete[] items;
}
I am confused about the necessity of using it over a regular array. Can't I just do the same thing with a regular array? Basically, you just define a new array with a larger size and move elements in the previous array to this new array. Why is it better to use a dynamic array here?
You are right, the example you are looking at isn't very good at demonstrating the need for dynamic arrays, but what if instead of going from size 5->6, we had no idea how many items we found until we need to add until the code is actually running?
Regular arrays need to be constructed with their size known at compile time
int foo [5] = { 16, 2, 77, 40, 12071 };
But dynamic arrays can be be assigned as size at runtime
int* Arrary(int size) {
return new int[size];
}
So if you don't know the size of your array, or it may need to grow/shrink you need to use a dynamic array (or better yet just use a std::vector).
Suppose you want to do what you mentioned a multiple times.
for(int i = 0; i < some_val; ++i)
{
int val_to_add;
std::cin >> val_to_add;
int* new_arr = new int[old_size + 1]; // the value is suppsoed to be big in order to indicate that it takes much memory.
copy_old_to_new(new_arr, old_arr); //some function which does the copying.
new_arr[old_size + 1] = val_to_add;
delete[] old_arr;
old_arr = new_arr;
}
Now think about what would happen if we tried to do the same with static arrays.
We wouldn't be able to remove the memory allocated by the old_arr, and the program would use a lot of memory.
We wouldn't be able to construct an array which would be accessible outside the loop, which, obviously, is not intended.
In your example it is not much clear how the usage of dynamic arrays would make use in your intention. So if you feel you could do the same without dynamic arrays, do it without them.

Dynamic resizing array code not working in C++?

I am trying to create an array, which doubles every time it is completely filled.
#include <iostream>
using namespace std;
int* array_doubler(int* array, int size){
int *new_array = new int[size*2];
for(int i = 0; i < size; i++){
new_array[i] = array[i];
}
delete[] array;
return new_array;
}
int main()
{
int N = 10; // Size of array to be created
int *array = new int[0];
for(int i = 0; i < N; i++)
{
if(array[i] == '\0')
array = array_doubler(array, i);
array[i] = i*2;
}
//Printing array elemensts
for(int i = 0; i < N; i++)
cout << array[i] << '\t';
cout << '\n';
return 0;
}
Problem is when I create dynamic memory with new, all the spots have the null character \0 value in them (not just the last spot). i.e. If i write:
int* p = new int[5];
then all the 5 blocks in memory p[0],p[1],p[2],p[3],p[4],p[5] have \0 in them, not just the p[5]. So the if(array[i] == '\0') in my main() calls array_doubler for every single iteration of for loop. I want it to fill the available spots in the array first and when it reaches the last element, then call array_doubler.
Problem is when I create dynamic memory with new, all the spots have the null character \0 value in them (not just the last spot).
Actually they have undefined values in them. 0 is a valid value for them to have, but tomorrow the compiler might suddenly decide that they should all have 1 instead of 0.
If you want to detect the end of an array, then you have to remember how big the array is. C++ doesn't do it for you. Actually, it does do it for you if you use std::vector, but I suppose that's not the point of this exercise.
I'm not sure why you'd want to do this, as std::vector offer this kind of feature, and are more idiomatic of c++ (see isocpp faq on why C-style array are evil).
One of the issue of C-style array is the fact that they donĀ“t know their own size, and that they don't have default value, thus stay uninitialized.
If for some reason you need to not use std::vector, the next best solution would be to wrap the array with it's size in a structure or a class (which is kinda what std::vector is doing), or to initialize your array using std::memset (which is the C function you would use if you were in C).
Do keep in mind that this is not considered as good practices, and that the STL offer plenty of solution when you need containers.

C++ Dynamic Ragged Array

I have been trying to figure out this assignment for hours and can't grasp it yet. I'm trying to read in names from a txt document, which is working, and I need to store them in an char pointer array. Once the number of names is as big as the array size, I need to use REALLOCATION to make the array bigger (I can't use vector library).
I'm struggling with changing the name array size to make it bigger and deleting the old array from memory (it just crashes when I write delete [] names;).
Here is my currently broken code:
int numNames = 2;
char * names[numNames] = {};
ifstream namesFile("names.txt");
//get names from user, put names in ragged array
int i = 0;
while (i < numNames) {
if (namesFile.good() && !namesFile.eof()) {
//add name to ragged array
names[i] = new char[257];
namesFile >> setw(256) >> names[i];
i++;
if (i == numNames) {
//need a bigger array
numNames *= 2;
char * temp[20] = {};
for (int j = 0; j < numNames / 2; j++) {
temp[j] = names[j];
}
delete [] names;
names = temp;
}
}
else {
//end of file or corrupt file
break;
}
}
namesFile.close();
Any help is appreciated!
The following statement does not do any dynamic allocation. It just declares an array of pointers to char (char*) on a stack of size numNames. So, it is not dynamic by any means:
char * names[numNames] = {};
As such, you cannot change its size.
Instead you need to create a pointer to the array like the following:
char **names = new (char*)[numNames];
Same story for your temp down the road. Now you are free to delete/new and to assign pointers as well: names = temp.
Now, you need to read your char data from a file line by line and put it in the 'names' array. When you read a string, you can allocate space for it in the array member, i.e.
names[i] = new char [strlen(inputString) + 1]; // you need '+1' for termination char
and you can copy data from your string after allocation, i.e.
strcpy(name[i], inputString); // this is a standard 'c' string copy
you can also use std::copy or a for loop do do a copy or whatever. Another method is to use a standard 'c' malloc function to do allocation:
name[i] = (char *)malloc(strlen(inputString) + 1);
The difference is that when you would need to free memory, you would use delete[] name[i] in the first case and free(name[i]) in the second. Though it looks like you do not need to free the memory in your task.
Now you just have to figure out how to read from the file.

c++ read into c-style string one char at a time?

in c++ id like to read input into a c-style string one character at a time. how do you do this without first creating a char array with a set size (you don't know how many chars the user will enter). And since you can't resize the array, how is this done? I was thinking something along these lines, but this does not work.
char words[1];
int count = 0;
char c;
while(cin.get(c))
{
words[count] = c;
char temp[count+1];
count++;
words = temp;
delete[] temp;
}
Since you cannot use std::vector, I am assuming you cannot use std::string either. If you can use std::string, you can the solution provide by the answer by #ilia.
Without that, your only option is to:
Use a pointer that points to dynamically allocated memory.
Keep track of the size of the allocated array. If the number of characters to be stored exceeds the current size, increase the array size, allocate new memory, copy the contents from the old memory to new memory, delete old memory, use the new memory.
Delete the allocated memory at the end of the function.
Here's what I suggest:
#include <iostream>
int main()
{
size_t currentSize = 10;
// Always make space for the terminating null character.
char* words = new char[currentSize+1];
size_t count = 0;
char c;
while(std::cin.get(c))
{
if ( count == currentSize )
{
// Allocate memory to hold more data.
size_t newSize = currentSize*2;
char* temp = new char[newSize+1];
// Copy the contents from the old location to the new location.
for ( size_t i = 0; i < currentSize; ++i )
{
temp[i] = words[i];
}
// Delete the old memory.
delete [] words;
// Use the new memory
words = temp;
currentSize = newSize;
}
words[count] = c;
count++;
}
// Terminate the string with a null character.
words[count] = '\0';
std::cout << words << std::endl;
// Deallocate the memory.
delete [] words;
}
You asked for C-style array. Stack or dynamic allocation will not serve you in this case. You need to change the count of the array number in each time you add new element which is not possible automatically. You have to work around and delete and reserve the array each time a new chae is read. So you have to options:
Use std::vector (which was created for this purpose)
Duplicate what is inside std::vector and write it yourself during your code( which seems terrible)
std::vector solution:
std::vector<char> words;
words.reserve(ESTIMATED_COUNT); // if you you do not the estimated count just delete this line
char c;
while(cin.get(c)){
words.push_back(c);
}
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1;
char c;
while (cin.get(c))
{
if (c == '\n')
continue;
s1 += c;
cout << "s1 is: " << s1.c_str() << endl; //s1.c_str() returns c style string
}
}
You have two ways, first is to use an zero size array, after each input you delete the array and allocate a new one that is +1 bigger, then store the input. This uses less memory but inefficient. (In C, you can use realloc to improve efficiency)
Second is to use a buffer, for example you store read input in a fixed size array and when it get full, you append the buffer at the end of main array (by deleting and re-allocating).
By the way, you can use std::vector which grows the size of itself automatically and efficiently.
If you're set on using c-style strings then:
char* words;
int count = 0;
char c;
while(cin.get(c))
{
// Create a new array and store the value at the end.
char* temp = new char[++count];
temp[count - 1] = c;
// Copy over the previous values. Notice the -1.
// You could also replace this FOR loop with a memcpy().
for(int i = 0; i < count - 1; i++)
temp[i] = words[i];
// Delete the data in the old memory location.
delete[] words;
// Point to the newly updated memory location.
words = temp;
}
I would do what Humam Helfawi suggested and use std::vector<char> since you are using C++, it will make your life easier. The implementation above is basically the less elegant version of vector. If you don't know the size before hand then you will have to resize memory.
You need to allocate a string buffer of arbitrary size. Then, if the maximum number of characters is reached upon appending, you need to enlarge the buffer with realloc.
In order to avoid calling realloc at each character, which is not optimal, a growth strategy is recommended, such as doubling the size at each allocation. There are even more fine-tuned growth strategies, which depend on the platform.
Then, at the end, you may use realloc to trim the buffer to the exact number of appended bytes, if necessary.

Defining a constant/declaring an array

I am trying to declare two arrays, one 2D and one 1D. I know the dimensions need to be const values. So the const value is assigned from the return value of a function call. That goes well, but when I use the derived value to declare the array, COMPILE errors! WHY???
Here is my code:
int populateMatrixFromFile(string fname) {
std::ifstream fileIn;
int s = determineDimensions(fname); // return value (CONST INT)
const int size = s; // assign to const
cout << "Value returned from determineDimensions(): " << size << endl;
if (size > 10){
cout << "Maximum dimensions for array is 10 rows and 10 columns. Exiting" << endl;
return 1;
}
fileIn.open(fname.c_str(), ios::in); //opened for reading only.
float aMatrix[size][size]; // ERROR
float bMatrix[size]; // ERROR
BUT it works here:
// assign the pth row of aMatrix to temp
const int alen = sizeof (aMatrix[p]) / sizeof (float);
float temp[alen]; // WORKS!!!
for (size_t i = 0; i < alen; i++) {
temp[i] = aMatrix[p][i];
}
Thanks for all help.
The compiler enforces this rule about a constant size of an array because it allocates the needed memory at compile time. In otherwords, all values needed to calculate the size of the array must be known at compile-time. In your first example, this is not the case, so the compiler complains.
If you really need to have dynamically sized arrays, you should use pointers and the new[] operator to allocate the array. You will also need to remember to use the delete[] operator to return the memory to the system and avoid any memory leaks.
The size of the second dimension, third, etc. in any array is always constant. Period. The standard is very clear about this.
The first dimension (actually the last index) can be variable if you allocate variable on the heap with array form of new, like this:
int size = 50;
float *p = new float[size];
.... do stuffs
delete[] p;
Some compilers allow variable sized arrays on the stack, but it is better not to use this.