Dynamic Arrays - c++

I'm just starting to learn C++ so excuse me for this simple question. What I'm doing is reading in numbers from a file and then trying to add them to an array. My problem is how do you increase the size of the array? For example I thought might be able to just do:
#include <iostream>
using namespace std;
int main() {
double *x;
x = new double[1];
x[0]=5;
x = new double[1];
x[1]=6;
cout << x[0] << "," << x[1] << endl;
return 0;
}
But this obviously just overwrites the value, 5, that I initially set to x[0] and so outputs 0,6. How would I make it so that it would output 5,6?Please realize that for the example I've included I didn't want to clutter it up with the code reading from a file or code to get numbers from a user. In the actual application I won't know how big of an array I need at compile time so please don't tell me to just make an array with two elements and set them equal to 5 and 6 respectively.Thanks for your help.

You don't want to work with arrays directly. Consider using a vector, instead. Then, you can call the push_back function to add things to the end, and it will automatically resize the vector for you.
#include <iostream>
#include <vector>
int
main() {
double value;
std::vector<double> values;
// Read in values
while (std::cin >> value) {
values.push_back(value);
}
// Print them back out
for (std::size_t i(0), len(values.size()); i != len; ++i) {
std::cout << values[i];
}
}

You should use a collection class to do this for you rather than managing it yourself. Have a look at the "vector" class. It's essentially a dynamic array that resizes automatically as required.
In your situation you would use "vector" with the "double" type. You may also need to read up on templates in C++.
http://www.cplusplus.com/reference/stl/vector/

Or, if you don't want to use STL or another dynamic thing, you can just create the array with the correct size from the beginning: x = new double[2];
Of course the problem there is how big to make it. If you don't know, then you'll need to just create it "big enough" (like a hundred, or a thousand)... which, at some point, won't be big enough and it will fail in some random looking way. So then you'll need to resize it. And once you get to that point, you'll wish you'd used the STL from the start, like the other answers are telling you to do.
#include <iostream>
using namespace std;
int main() {
double *x = new double[2];
x[0]=5;
x[1]=6;
cout << x[0] << "," << x[1] << endl;
return 0;
}

Here's an example though for good measure, so you can see the pattern:
#include <iostream>
using namespace std;
int main() {
// Allocate some memory for a double array of size 1 and store
// an address to the beginning of the memory in mem_address.
double* mem_address = new double[1];
// Assign 5 to the first element in the array.
mem_address[0] = 5;
// Save the address of the memory mem_address is currently
// referencing.
double* saved_address = mem_address;
// Allocate some memory for a double array of size 2 and store
// an address to the beginning of the memory in mem_address.
mem_address = new double[2];
// Copy over the 1 element from the first memory block
// to the new one.
mem_address[0] = saved_address[0];
// Done with the old memory, so clean it up.
delete [] saved_address;
// Assign 6 to the second element in the new array.
mem_address[1] = 6;
// Print out the 2 elements in the new array.
cout << mem_address[0] << "\n";
cout << mem_address[1] << "\n";
// Done with the new array memory now, so clean it up.
delete [] mem_address;
}

If for some reason you don't have access to STL -- or want to learn how to do this yourself -- you could use an algorithm like this:
Allocate your array as some arbitrary size, and remember how many elements are in it and how big it is:
int *a = malloc(int * ARBITRARY_SIZE);
int size = 0;
int allocated = ARBITRARY_SIZE;
each time you add a new element, increase "size". If size equals ARBITRARY_SIZE, multiply 'allocated' by 2, and reallocate the array. Either way, assign the new value to a[size].
void addElement(int value) {
++size;
if (size == allocated) {
allocated *= 2;
a = realloc(sizeof(int) * allocated);
a = new_a;
}
a[size] = value;
}
Note that your code above has at least one bug -- you aren't allocating enough space for x[1] in either case.
Also obviously in real code you'd check that the return from malloc & realloc isn't null.

An array always needs a contiguous block of memory. In a situation where you might need to resize the array later on, reallocation is probably the only solution. This is what Moishe and Shadow2531 do above.
The problem with reallocation is that it can be a costly operation. So if you need adding 5 more elements to a 5000 element array, you might end up copying all the 5000 elements across memory.
Using a linked list instead can be considered for such a scenario.

Related

Is it dumb to make a dynamic 2d array where the second dimension is a constant?

I am trying to make an array with a variable number of rows, but it will always have 4 columns. Is doing something like:
int** numGrades = new int* [num_exams];
for (int i = 0; i < num_exams; ++i)
{
numGrades[i] = new int[4];
}
a good way to do this? I feel like there's an easier way, but I can't think of one. Also, the array keeps giving me memory leaks so I'm wondering if that is because I'm doing something I shouldn't be. Vectors are banned for this program fyi.
You could make an array of rows.
struct Row{
int values[4];
};
Row* numGrades = new Row[num_exams];
Maybe you can try this.
typedef int row[4];
//or
using row = int[4];
row *numGrades = new row[num_exams];
Allocating some number of arrays of fixed size is fine and advantageous in many cases.
In addition to a struct (which is a very good option), another option is to declare a Pointer-To-Array of a fixed number of elements. The benefit there is you have a Single-Allocation and Single-Free for the block of memory. (as you do with an array of struct) If you need to grow the block of memory (with a -- declare bigger block, copy existing to bigger, delete existing reallocation), it simplifies the process. In your case:
int (*numGrades)[4] = new int[num_exams][4];
Which will allocate num_exams number of arrays of 4 int all at once. That provides the benefit of a single delete[] numGrades; when you are done with the memory.
A short example that uses a std::istringstream to hold example values to be read into a block of memory containing fixes size arrays could be:
#include <iostream>
#include <sstream>
int main (void) {
std::istringstream iss { "1 2 3 4 5 6 7 8 9" };
int npoints = 3,
(*points)[3] = new int[npoints][3],
n = 0;
while (n < 3 && iss >> points[n][0] >> points[n][1] >> points[n][2])
n++;
for (int i = 0; i < n; i++)
std::cout << points[i][0] << " " << points[i][1] << " " << points[i][2] << '\n';
delete[] points;
}
(note: you should avoid using new and delete in favor of a container such as std::vector if this is for other than educational purposes)
Example Use/Output
$ ./bin/newptr2array3
1 2 3
4 5 6
7 8 9
Worth noting, the benefit of the struct is that it will allow you to overload >> and << with std::istream and std::ostream to provide a convenient functions to read and write the data you need.
So either way, a Pointer-to-Array of fixed elements, or creating a struct and then an Array of struct is perfectly fine.
You could skip the for loop:
int* numGrades = new int[num_exams*4];
int firstElement = numGrades[x];
int secondElement = numGrades[x+1];
int thirdElement = numGrades[x+2];
int fourthElement = numGrades[x+3];
By skipping the for loop you gain this:
You don't have to have a for-loop for freeing the memory:
delete[] numGrades;
The heap does not fragment so much because you don't call "new" so many times.
BUT it all depends what you are using it for. In modern C++ is not such a good idea to use dynamic but make a struct in a std::vector.

how to initialize part of an array as zero c++

I am a new programming student. I am currently studying pointers and dynamic arrays. The assignment I need help with asked me to create an array then use a function to double the elements and initialize the last half of the array as zeros. Here is my code:
#include <iostream>
using namespace std;
// Function prototype
void doubleArray(int*, int);
// Global variable for array elements
int numElems = 5;
int main()
{
int* oldArray; // Array variable
oldArray = new int[numElems]{1, 3, 5, 7, 9}; // Makes the array dynamic
// Display old array
cout << "This is the old array.\n";
for (int a = 0; a < numElems; a++)
{
cout << oldArray[a] << endl;
}
// Double the array size, copy old array into new array, and initialize the rest of the space to zero
doubleArray(oldArray, numElems);
cout << endl;
delete[] oldArray;
oldArray = nullptr;
return 0;
}
// Function doubles array size, copies old array into new array, and initializes the rest of the space to zero
void doubleArray(int* newArray, int size)
{
size *= 2;
for (int b = 5; b < (size/2); b++)
{
newArray[b] = {0};
}
cout << "This is the new array.\n";
for (int c = 0; c < size; c++)
{
cout << newArray[c] << endl;
}
}
Here is the output:
This is the old array.
1
3
5
7
9
This is the new array.
1
3
5
7
9
0
138433
0
0
0
As you can see, there is garbage in the second 'for' loop in the function doubleArray when it runs through the loop a second time. I have been diligently searching for an answer here on the forum, but have not yet succeeded.
The array you have allocated memory for is only for 5 integers , when you try to increase the number of elements you have to allocate more memory for the array.
What you should do is allocate memory for an array with double the size copy the contents of the initial array , and then assign the other half of the elements as 0.
And then return the reference of the new array or you could make the old array "point" to the new reference
Nowhere in doubleArray do you double the array. Instead you start stomping on the data around the old array. This is not a good idea. You don't know what's there. Could be something important. Could crash your program. In the old days it could have crashed the computer or smashed some important information in another program. Maybe someone's bank account. Maybe the instructions on where to fly the plane. Not good.
To fix this you will need to new[] yourself another array of ints twice the size of the original. Do not reuse the variable for the old array. If you write over it, you lose the old array. You still need to get the old data from the old array into the new array and if you don't put the old array away properly you will leak memory.
Once you've done that, on to the next bit: preserving the old data and zeroing the rest of the new array. To do this, copy all of the data from the old array to the new array (a for loop is perfect for this job) and fill the remainder of the new array with zeros.
Next some house keeping. Since the old array is no longer needed, you can safely delete[] it to prevent the memory leak.
Finally return the new array to the caller.
If you're feeling brave, point out to your instructor that there's this really cool thing called std::vector that was invented back in the 1990s and basically does all this stuff (and a lot more!) for you.

Dynamic memory Points in C++

I am trying to write code in C++ that reads from a file, a sequence of points, stores it in a dynamic array and then prints back.
This is the specification I've been given:
"We want to take advantage of the fact that we can use dynamic memory, thus instead of allocating at beginning an amount of memory large enough according to our estimations, we implement the following algorithm:
Initially, very little memory is allocated.
At each iteration of the loop (reading from the file and storing into the
dynamic array) we keep track of:
The array maximum size (the allocated memory).
The number of elements in the array.
When, because of a new insertion, the number of elements would become
greater than the array maximum size, memory reallocation needs to take
place as follows:
Allocate another dynamic array with a greater maximum size.
Copy all the elements from the previous array to the new one.
Deallocate the memory area allocated for the previous array.
Get the pointer to the previous array to point to the new one.
Add the new item at the end of the array. This is where my problem is.
From my code below, I think everything else is fine but the last requirement, which is to add the new item at the end of the array.
The code works fine when the array Max_Size exceeds file's number of
elements, but when I try extending the num_elements, the result is
that the extra digits in the file are just saved as zeros
.
Also to add, the assignment doesn't allow use of vectors just yet.
Sorry I forgot to mention this, I'm new to stackoverflow and somewhat
to programming.
Any help please
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
struct point {
double x;
double y;
};
int main () {
ifstream inputfile;
inputfile.open("datainput.txt");
if(!inputfile.is_open()){
cout << "could not open file" << endl;
exit(EXIT_FAILURE);
}
//initially very little memory is allocated
int Max_Size = 10;
int num_elements = 0;
point *pp = new point[Max_Size];
//read from file and store in dynamic array
for (int i = 0; !inputfile.eof(); i++) {
inputfile >> pp[i].x >> pp[i].y;
num_elements++; //keep track of number of elements in array
}
//detecting when number of elements exeeds max size due to new insertion:
if (num_elements > Max_Size){
// allocate another dynamic array with a greater maximum size
Max_Size *= 2; // Max_Size = 2*Max_Size to double max size whenever there's memory problem
point *pp2 = new point[Max_Size];
//copy all elements from previous array to new one
for (int j=0; j<(Max_Size/2); j++) {
pp2[j].x = pp[j].x ;
pp2[j].y = pp[j].y;
}
//deallocate memory area allocated for previous array
delete [] pp;
//get pointer to previous array to point to the new one
pp = pp2;
**//add new item at end of the array
for (int k = ((Max_Size/2)-1); k<num_elements; k++) {
inputfile.seekg(k, ios::beg) >> pp2[k].x;
inputfile.seekg(k, ios::beg) >> pp2[k].y;
}**
//print out dynamic array values
for (int l = 0; l<num_elements; l++) {
cout << pp2[l].x << ",";
cout << pp2[l].y << endl;
}
//delete dynamic array
delete [] pp2;
}
else {
//print out dynamic array values
for (int m = 0; m<num_elements; m++) {
cout << pp[m].x << ",";
cout << pp[m].y << endl;
}
//delete dynamic array
delete [] pp;
}
cout <<"Number of elements = " << num_elements <<endl;
//close file
inputfile.close();
return 0;
}
Others have already pointed out std::vector. Here's roughly how code using it could look:
#include <vector>
#include <iostream>
struct point {
double x;
double y;
friend std::istream &operator>>(std::istream &is, point &p) {
return is >> p.x >> p.y;
}
friend std::ostream &operator<<(std::ostream &os, point const &p) {
return os << p.x << "," << p.y;
}
};
int main() {
// open the file of data
std::ifstream in("datainput.txt");
// initialize the vector from the file of data:
std::vector<point> p {
std::istream_iterator<point>(in),
std::istream_iterator<point>() };
// print out the data:
std::copy(p.begin(), p.end(), std::ostream_iterator<point>(std::cout, "\n"));
}
On top of being a lot shorter and simpler than the code you posted, getting this to work is likely to be a lot simpler and (as icing on the cake) it will almost certainly run faster1 (especially if you have a lot of data).
1. In fairness, I feel obliged to point out that the big difference in speed will mostly come from using \n instead of endl to terminate each line. This avoids flushing the file buffer as each line is written, which can easily give an order of magnitude speed improvement. See also: https://stackoverflow.com/a/1926432/179910
The program logic is flawed. You run the loop until EOF but you don't check to see if you have exeeded your array size. I would add an if statement inside of the first loop to check if you have passed the Max_Size. I would also write a function to reallocate the memory so you can simply call that function inside of your first loop.
Also you have problems with your memory allocation. You should do like this:
point temp = pp;
pp = new Point[...];
// Copy the contents of temp into pp
delete temp;
You need to set your pointer to the old array first so you don't lose it. Then after you have copied the contents of you old array into the new array, you can then delete the old array.

Expanding a dynamically allocated array

I have allocated an array as follows.
#include <iostream>
int main() {
const int first_dim = 3;
const int second_dim = 2;
// Allocate array and populate with dummy data
int** myArray = new int*[first_dim];
for (int i = 0; i < first_dim; i++) {
myArray[i] = new int[second_dim];
for (int j = 0; j < second_dim; j++) {
myArray[i][j] = i*second_dim + j;
std::cout << "[i = " << i << ", j = " << j << "] Value: " << myArray[i][j] << "\n";
}
}
// De-allocate array
for (int i = 0; i < first_dim; i++)
delete[] myArray[i];
delete[] myArray;
}
Let's say I want to add a 4th element to the first dimension, i.e. myArray[3]. Is this possible?
I've heard that Vectors are so much more efficient for this purpose, but I hardly know what they are and I've never used them before.
Yes, but in a very painful way. What you have to do is allocate new memory which now has your new desired dimensions, in this case 4 and 2, then copy all the contents of your matrix to your new matrix, and then free the memory of the previous matrix... that's painful. Now let's see how the same is done with vectors:
#include <vector>
using std::vector;
int main()
{
vector< vector <int> > matrix;
matrix.resize(3);
for(int i = 0; i < 3; ++i)
matrix[i].resize(2);
matrix[0][1] = 4;
//...
//now you want to make the first dimension 4? Piece of cake
matrix.resize(4);
matrix[3].resize(2);
}
HTH
edit:
some comments on your original code:
In C++ ALL_CAP_NAMES usually refer to macros (something you #define). Avoid using them in other contexts
why do you declare FIRSTDIM and SECONDDIM static? That is absolutely unnecessary. If a local variable is static it means informally that it will be the same variable next time you call the function with kept value. Since you technically can't call main a second sime this is useless. Even if you could do that it would still be useless.
you should wrire delete [] array[i]; and delete [] array; so the compiler knows that the int* and int** you're trying to delete actually point to an array, not just an int or int* respectively.
Let's say I want to add a 4th element to the first dimension, i.e. myArray[3]. Is this possible?
Yes, but it's a pain in the neck. It basically boils down to allocating a new array, just as your existing code does (hint: put it in the function and make the sizes arguments to that function) and copying compatible elements over.
Edit: One of the things that std::vector does for you is properly de-allocating you memory. In the code you have, failure to allocate one of the arrays along the 2nd dimension will result in a memory leak. A more robust solution would initialize pointers to 0 before performing any allocation. An exception block could then catch the exception and free whatever was partially allocated.
Because this code becomes complex quickly, people resort to allocating a single buffer and addressing using a stride or using a 1D array of 1D arrrays (i.e. std::vector of std::vectors).

length of array in c++

I read to get the length of array in C++, you do this:
int arr[17];
int arrSize = sizeof(arr) / sizeof(int);
I tried to do the same for a string:
where I have
string * arr;
arr = new (nothrow) string [213561];
And then I do
arr[k] = "stuff";
where I loop through each index and put "stuff" in it.
Now I want the size of the array which should be 213561, what's the correct way to do it and why is it so complex in C++?
What you are trying to do cannot work because sizeof works on types at compile-time (and pointer types never hold the size of the array they may be pointing to).
In your case, computing sizeof(arr) returns the size taken in memory by the pointer, not
size of the array * size of a std::string
I suggest you use one of these two options
either use fixed-size arrays (sizeof works)
or vectors (myVector.size() returns what you need)
... unless you have a good reason not to.
The correct way of doing this in C++ is to use a vector. That way you can either specify a size up-front, or resize it as you go.
Specifying size up-front:
using namespace std;
vector<string> arr(213561);
for (vector<string>::iterator p = arr.begin(); p != arr.end(); ++p)
{
*p = "abc";
}
Expanding the vector as you go:
using namespace std;
vector<string> arr; // <-- note, default constructor
for (int i = 0; i < 213561; ++i)
{
// add elements to the end of the array, automatically reallocating memory if necessary
arr.push_back("abc");
}
Either way, the size of the array is found with:
size_t elements = arr.size(); // = 213561
The sizeof method only works as long as your array is really an array, i.e. an object that has the array type. In your first example object arr has type int[17]. It is an array type, which means that you can use the sizeof method and get 17 as the result.
Once you convert your array type T[N] to a pointer type T *, you basically lose your array type. The sizeof method applied to a pointer will not evaluate to the size of the original array.
When you allocate array of type T[N] with new[], the result is a pointer of type T * right away. It is not an array type from the very beginning. The information about array size is lost right away and trying to use the sizeof method with such a pointer will not work. In order to preserve the size information about a dynamically allocated run-time sized array, you have to store it in a separate variable yourself.
Here is how you find the size of an array:
const size_t ARRAY_SIZE = 17;
int array[ARRAY_SIZE];
//...
std::cout << "My array size is: " << ARRAY_SIZE << "\n";
You can put ARRAY_SIZE into a header so that other translation units can access the array size.
If you want a dynamic array, that will grow as needed, try std::vector.
You need to keep track of the length using a separate variable. There is no way of getting the length of an area that you only have a pointer to, unless you store that length somewhere.
You cannot get the length of the allocated array.
What you can do is save it seperately at the time of allocation..
Also, you could check the length of the string (which isn't what you're asking, but still..) using strlen()
In c++ here arr is simply a reference to the first element of the array. In case of dynamic arrays it is not possible.
There is a subtle nuance in both C and C++ with memory allocation. Neither language supports dynamic arrays. Here is what you are seeing:
int ary[17];
int arrSize = sizeof(ary) / sizeof(ary[0]);
Here ary is a true array of 17 integers. The array size calculation works because sizeof(ary) returns the size of the memory block allocated for the entire array. You divide this by the size of each element and violĂ  you have the number of elements in the array.
std::string * arr;
arr = new (std::nothrow) std::string[213561];
In this case arr is a pointer to some memory. The new operator allocates a block of memory large enough to hold 213,561 contiguous std::string objects and constructs each of them into the memory. The arr variable simply points to the beginning of the block of memory. C++ does not track the number of elements that you have allocated. You didn't really create a dynamic array - instead, you have allocated enough memory for a bunch of contiguous objects.
C and C++ both allow you to apply the subscripting operator to a pointer as syntactical sugar. You will see a lot of comments about how arr[0] translates into *(arr + 0). The reality is that allocating memory using the new operator results in a block of memory that is not an array at all. The syntactical sugar makes it look like one. The next thing that you will encounter is that multi-dimensional arrays are similar sugar.
Consider the following snippet. Once you understand what is going on there, you will be a lot closer to understanding how memory works. This is the primary reason why C and C++ cannot tell you how large an array is if it is dynamically allocated - it does not know the size, all that it has is a pointer to the allocated memory.
#include <iostream>
int
main()
{
//
// The compiler translates array subscript notation into
// pointer arithmetic in simple cases so "hello"[3] is
// is translated into *("hello" + 3). Since addition is
// commutative, the order of "hello" and 3 are irrelevant.
//
std::cout
<< "\"hello\"[3] = '" << "hello"[3] << "'\n"
<< "3[\"hello\"] = " << 3["hello"] << "\n"
<< std::endl;
//
// All memory is linear in C or C++. So an 3x3 array of
// integers is a contiguous block of 9 integers in row
// major order. The following snippet prints out the 3x3
// identity matrix using row and column syntax.
//
int ary[3][3] = { { 1, 0, 0 },
{ 0, 1, 0 },
{ 0, 0, 1 } };
for (int r=0; r<3; ++r) {
for (int c=0; c<3; ++c) {
std::cout << "\t" << ary[r][c];
}
std::cout << "\n";
}
std::cout << "\n";
//
// Since memory is linear, we can also access the same
// 3x3 array linearly through a pointer. The inner loop
// is what the compiler is doing when you access ary[r][c]
// above - "ary[r][c]" becomes "*(ptr + (r * 3) + c)"
// since the compiler knows the dimensions of "ary" at
// compile time.
//
int *ptr = &ary[0][0];
for (int i=0; i<9; ++i) {
ptr[i] = i;
}
for (int r=0; r<3; ++r) {
for (int c=0; c<3; ++c) {
std::cout << "\t" << *(ptr + (r * 3) + c);
}
std::cout << "\n";
}
return 0;
}