Returning structure array value - c++

So I am writing quite a long code and now I came to a problem. How to change structure's arrray's values and get them back to main function.
What I am trying to do this function is: to insert a new value at first array spot(which is 0). The whole for cycle frees the Z[0] and works fine. But I do not know how to return whole CHANGED structure array to the main program. How to do this?
Thank you.
P.S. sorry, for my broken english.
Here are the neccessary parts of the code:
void insertion(Player Z[], int size); //declaration of the funcion
...
int main()
{
int size=5;
Player *Z = new Player[size];
Insertion(Z, size); //calling the function
...
}
void Insertion(Player Z[], int size) //function
{
size++;
Player* temp = new Player[size];
for(int i=0;i<=size-1;i++)
{
temp[i+1]=Z[i];
}
delete [] Z;
Z = temp;
cin>>Z[0].name;
cin>>Z[0].surname;
}

I see many problems in your code.
For example, why are you allocating an array of 5 Players, then deallocating the array and allocating the array again, having the same size? What's the benefit?
You should also note that C++ has call-by-value semantics so the delete[] Z and Z = temp lines have no effect outside of the function you're calling. So, that function should have a signature void Insertion(Player **Z, int size); or Player *Insertion(Player *Z, int size) if you don't want to modify the argument in-place but instead return the new value.
The comments suggested using std::vector. I heavily recommend that approach. If you need a variable-sized container, std::vector is the best choice.
If you however have a reason to do the manual allocations yourself (such as homework assignment) you should use the following strategy: maintain the size of the array in addition to its capacity, and whenever the size would be greater than the capacity, allocate a new array with twice the capacity, copy the contents and deallocate the old array.

Related

Helper function to construct 2D arrays

Am I breaking C++ coding conventions writing a helper function which allocates a 2D array outside main()? Because my application calls for many N-dimensional arrays I want to ensure the same process is followed. A prototype which demonstrates what I am doing :
#include <iostream>
// my helper function which allocates the memory for a 2D int array, then returns its pointer.
// the final version will be templated so I can return arrays of any primitive type.
int** make2DArray(int dim1, int dim2)
{
int** out = new int* [dim1];
for (int i = 0; i < dim2; i++) { out[i] = new int[dim2];}
return out;
}
//helper function to deallocate the 2D array.
void destroy2DArray(int** name, int dim1, int dim2)
{
for (int i = 0; i < dim2; i++) { delete[] name[i]; }
delete[] name;
return;
}
int main()
{
int** test = make2DArray(2,2); //makes a 2x2 array and stores its pointer in test.
//set the values to show setting works
test[0][0] = 5;
test[0][1] = 2;
test[1][0] = 1;
test[1][1] = -5;
// print the array values to show accessing works
printf("array test is test[0][0] = %d, test[0][1] = %d, test[1][0] = %d, test[1][1] = %d",
test[0][0],test[0][1],test[1][0],test[1][1]);
//deallocate the memory held by test
destroy2DArray(test,2,2);
return 0;
}
My concern is this may not be memory-safe, since it appears I am allocating memory outside of the function in which it is used (potential out-of-scope error). I can read and write to the array when I am making a single small array, but am worried when I scale this up and there are many operations going on the code might access and alter these values.
I may be able to sidestep these issues by making an array class which includes these functions as members, but I am curious about this as an edge case of C++ style and scoping.
There is a difference between allocating 2D arrays like this and what you get when you declare a local variable like int ary[10][10] that based on your statement
My concern is that this operation may not be memory-safe, since it
appears that I am allocating memory for an array outside of the
function in which it is used (potential out-of-scope error)
I am guessing you do not fully understand.
You are allocating arrays on the heap. Declaring a local variable like int ary[10][10] places it on the stack. It is the latter case where you need to worry about not referencing that memory outside of its scope-based lifetime; that is, it is the following that is totally wrong:
//DON'T DO THIS.
template<size_t M, size_t N>
int* make2DArray( ) {
int ary[M][N];
return reinterpret_cast<int*>(ary);
}
int main()
{
auto foo = make2DArray<10, 10>();
}
because ary is local to the function and when the stack frame created by the call to make2DArray<10,10> goes away the pointer the function returns will be dangling.
Heap allocation is a different story. It outlives the scope in which it was created. It lasts until it is deleted.
But anyway, as others have said in comments, your code looks like C not C++. Prefer an std::vector<std::vector<int>> rather than rolling your own.
If you must use an array and are allergic to std::vector, create the 2d array (matrix) as one contiguous area in memory:
int * matrix = new int [dim1 * dim2];
If you want to set the values to zero:
std::fill(matrix, (matrix + (dim1 * dim2)), 0);
If you want to access a value at <row, column>:
int value = matrix[(row * column) + column];
Since the matrix was one allocation, you only need one delete:
delete [] matrix;

Revisited: difference between static array and dynamic array in C++?

I'm a beginner for C++ and I saw the post here. However, it is very unclear for me what is the benefit of dynamic array.
One advantage is that one can change the length of a dynamic array, here is the code
int *p = new int[10];
// when run out of the memory, we can resize
int *temp = new int[20];
copy(p, temp); // copy every element from p to temp
delete[] p; // delete the old array
p = temp;
temp = nullptr;
Above is for dynamic allocation, it says the array will be on the heap, and need to manually delete it. However, why not use the static array as follow
int array1[10];
int *p = array1;
// when run out of the memory, we can resize
int array2[20];
copy(array1, array2); // copy every elements from array1 to array2;
p = array2;
In this code, we don't need to delete the array1 since it is on the stack area. Here are my question:
what is the benefit of the dynamic array? It seems for me, resizing is not a big issue. People always say the size of static array are fixed, the size of dynamic array is not fixed. Why the size of dynamic array is not fixed. for example, int p=new int[10], the size of p is fixed.
Thanks a lot.
int array1[10];
int *p = array1;
// when run out of the memory, we can resize
int array2[20];
copy(array1, array2); // copy every elements from array1 to array2;
p = array2;
In whichever function, or inner scope, array1 and array2 get declared these arrays get automatically destroyed when the function or inner scope returns. Full stop.
This is why this is called "automatic scope". The fact that there may be a pointer to one of the arrays is immaterial. The array will be gone and any attempt to dereference that pointer will result in demons flying out of your nose.
So if you had any grand designs to continue using this array, in some form or fashion, after returning from the function where they get declared, too bad. It's not going to happen.
On the other hand, after newing something, as long as you properly track the pointer to the newed object(s) they can be used anywhere else, until they get deleted. This function, another function, anywhere. Even a different execution thread.
Having said all of that, you should not be using new or delete either. You should be using C++ library's containers which will correctly handle all memory allocation, deallocation, and copying, for you. In this case, you are simply reinventing what std::vector already does for you, and it will actually do it, in some ways, far more efficient than you can do easily on your own. You just call resize(), and, presto, your vector is bigger or smaller, as the case may be. And, in all other respects the vector will be indistinguishable from your array. It will be very hard to tell the difference.
So, use C++ library's containers. They are your friends. They want you to do memory allocation correctly, on your behalf. Modern C++ code rarely uses new or delete, any more. It's important to understand how it works, but 99% of the time you don't really need it.
Doing your own dynamic array with new int[20] and delete[] etc, is no doubt good for learning how it all works.
In real C++ programs you would use std::vector. Maybe like this:
#include <iostream>
#include <string>
#include <vector>
int main() {
std::vector<std::string> lines;
std::string line;
while (std::getline(std::cin, line)) {
lines.push_back(line);
}
std::cout << "Read " << lines.size() << " lines of input\n";
}
The reason you would use dynamic allocation is so your program can handle any number of lines of any line length. This program can read four lines or 400,000. The std::vector is dynamic. So is std::string.
I have write a code on static and dynamics array, hope this will help.
#include<iostream>
using namespace std;
int main (){
//creating the static array .. rember the syntax of it.
int array[4]= {1,2,3,4}; // size is fixed and can not be changeable at run time.
cout<<"Static Array."<<endl;
cout<<"Printing using index."<<endl;
for(int x=0;x<4;x++){
cout<<"\t"<<array[x];
}
cout<<endl;
cout<<"Printing using pointer."<<endl;
int*ptr= array;
for(int x=0;x<4;x++){
cout<<"\t"<<*ptr++;
}
//delete [] array ;// error, because we can not free the size from stack
// array[6]= {1,2,3,4,5,6}; //Error: We can not change the size of static array if it already defined.
// we can not change the size of the static aray at run time.
cout<<endl;
cout<<"\n\nDynamic Array."<<endl;
int n=4;
//Creating a dynamic Array, remember the systex of it.
int *array2 = new int [n]; // size is not fixed and changeable at run time.
array2[0]= 1;
array2[1]= 2;
array2[2]= 3;
array2[3]= 4;
cout<<endl;
cout<<"Printing using index."<<endl;
for(int x=0;x<4;x++){
cout<<"\t"<<array2[x];
}
cout<<endl;
cout<<"Printing using pointer."<<endl;
int*ptr2= array2;
for(int x=0;x<4;x++){
cout<<"\t"<<*ptr2++;
}
cout<<endl<<endl<<endl;
delete array2; //Size is remove at runtime
cout<<"Chnaging the size of dynamic array at runtime... :)";
// Changing the size of the array to 10.. at runtime
array2 = new int [10]; // Array size is now change to 10 at runtime
array2[0]= 1;
array2[1]= 2;
array2[2]= 3;
array2[3]= 4;
array2[4]= 5;
array2[5]= 6;
array2[6]= 7;
array2[7]= 8;
cout<<endl;
cout<<"Printing using index."<<endl;
for(int x=0;x<7;x++){
cout<<"\t"<<array2[x];
}
// free the memory/ heap
delete [] array2;
return 0;
}
Output

Dynamic array crashing at constructor

I'm trying to implement a dynamic array of strings for educational purpose. The problem that I ran into is the program crashing whenever I try to add strings to the empty array in my constructor.
Array::Array(string dir, string dim)
{
size = 0;
ptr = new string[size + 1];
ptr[size] = dir;
size++;
ptr[size] = dim;
size++;
}
I have int size and string *ptr declared in my header file. I originally thought this to be a out-of-bounds problem, but after looking at this post, I fixed the initial allocation to size + 1, but the persisting problem seems to prove otherwise.
Changing the value of size does not change the size of the array.
You allocate an array of size 1.
Then you assign something to the first (only) element of that array.
Then you assign something to the second element of that array - but the array only has one element.
Also note that using new does not allocate a dynamic array. Once allocated, the size can't change.
As mentioned by Sid S, "changing the value of size does not change the size of the array."
And for your "inefficient" concern, a common trick that reflect to PaulMcKenzie and Daniel H's idea, is to use the doubling strategy. See the following C code for an simple idea:
#include <stdlib.h>
struct MyArray {
int capacity;
int size;
int *data;
}
/* any other functions you would use, eg: create, destroy of MyArray */
void push(struct MyArray myarray, int n) {
if (size == capacity) {
capacity *= 2;
data = realloc(data, capacity*sizeof(int));
}
/* add the element to the end of data and increase size */
}
In this way, instead of doing realloc every time there is an element added, you would have a lower runtime in average.
A detailed amortized analysis about doubling strategy can be found here.
Instead of string use pointer and allocate memory dynamically every time how much they need not 0 and then ++.
Array :: Array(char *dir,char *dim)
{
int l1,l2;
l1=strlen(dir);
l2=strlen(dim);
/**assume n1 & n2 are data member of "Array" class.**/
n1=new char[l1+1];// allocating memory dynamically
n2=new char[l2+1];
}
I hope it helps.

Copy array then delete original

I have an array of a structure (with the parameters of name and number), and the initial array takes in elements from a document that I've made. The initial list size starts at 1000. When the list fills up, I call another method that I'm struggling with. I would like for it to copy the data into a new array that doubled the size, and then delete the old array.
If I name it: array1 and array2, I have my program use array1 throughout. I need help with the pointers that would get array2 to work as array1.
Is there a way to copy the array to a temp array of the same or new size, and then remake the initial array reassigning back to that? For this exercise, I can't use vectors. While I know how to use them, and that they solve this issue while being better, I'm trying to do it with only arrays.
using namespace std;
struct Information {
char functionality;
int SSN;
string name;
};
int numPeople = 1000;
//Gets called if the initial array (whatever size) is filled
void doubleArray(Information *array){
numPeople = numPeople * 2;
//Will now be the doubled array size
Information temp[numPeople]
for(int i = 0; i < numArray; i++){
temp[i].SSN = array[i].SSN;
temp[i].name = array[i].name;
}
//Normally makes it crash
delete[] array;
}
edit: This is what I currently have
void doubleArray(Information *person){
numPeople = numPeople * 2;
Information* temp = new Information[numPeople];
memcpy(temp, person, numPeople);
delete[] person;
person = temp;
}
It gets to numPeople = 1000 (the initial list size) but then crashes shortly after. Is the doubling array correct?
Arrays are fixed size. You cannot change the capacity of the original array.
{Use std::vector}
You can have a pointer to an array. And use the same pointer. When the array is full, you can allocate another array, copy old array items to new array, delete the old array and assign your array pointer to the new array.
{Did I mention std::vector?}
By the way, there is a data structure that performs resizing as necessary. If I recall correctly, it is std::vector. Try it out. :-)
Assuming you are using std::array (which you should be), then copying the array is very easy.
std::array<myStruct, 1000> array1{};
std::array<myStruct, 2000> array2{};
// codes...
std::copy(array1.begin(), array1.end(), array2.begin())
However, this is a specific scenario in which you only use these two arrays. It will not dynamically double the size of the array as you simply cannot do this dynamically with stack-based arrays, just like c arrays[].
What you can, and should, be using is std::vector<myStruct>. This will dynamically grow as you need it. Until you provide us with code and a more specific issue, this is the best advice that I can offer with the information provided.
If you aren't allowed to use std::vector, as one of your comments stated, then you'll want to look at dynamic allocation.
size_t sz = [whatever];
// Dynamically allocate an array of size sz.
T* T_array = new T[sz];
// Do whatever...
delete[] T_array; // new[] needs to be paired with delete[].
T_array = nullptr; // Not strictly necessary, but a good idea if you have more code after.
As the size doesn't need to be constant for a dynamic array, this will allow you to allocate memory as necessary. You can then use std::copy() to copy data from one array to the other, as Goodies mentioned.
[For more information on dynamic allocation, see here.]

UPDATE: C++ Pointer Snippet

Greetings again, and thanks once more to all of you who provided answers to the first question. The following code is updated to include the two functions per the assignment.
To see the original question, click here.
I am pretty sure this fulfills the requirements of the assignment, but once again I would greatly appreciate any assistance. Did I modify the delete statements appropriately? Thanks again.
#include<iostream>
#include<string>
int** createArray(int, int);
void deleteArray(int*[], int);
using namespace std;
int main()
{
int nRows;
int nColumns;
cout<<"Number of rows: ";
cin>>nRows;
cout<<"Number of columns: ";
cin>>nColumns;
int** ppInt = createArray(nRows, nColumns);
deleteArray(ppInt, nRows);
}
int** createArray(int nRows, int nColumns)
{
int** ppInt = new int*[nRows];
for (int nCount = 0; nCount < nRows; nCount++)
{
ppInt[nCount] = new int[nColumns];
}
return ppInt;
}
void deleteArray(int** nPointer, int nRows)
{
for (int nCount = 0; nCount < nRows; nCount++)
{
delete[] nPointer[nCount];
}
delete[] nPointer;
}
P.S. Here is the assignment documentation itself, in case it helps:
(1) Design and implement a function to allocate memory for a 2-D integer array: the function is supposed to take two integers as parameters, one for number of rows and one for number of columns. You need to use “new” operator in this function. Remember that we need to first create an array of pointers. Then, for each pointer in that array, we need to create an array of integers. This function is supposed to return a pointer which points to a 2-D integer array.
(2) Design and implement a function to de-allocate memory for this 2-D array: the function is supposed to have two parameters (a pointer which points to a 2-D integer array, and the other one is number of rows in the array). In the function, you are supposed to de-allocate memory for this 2-D array using the “delete” operator. You should delete each row (an array of integers) first, and then delete the array of pointers.
The code looks good.
However, there are some problems you may want to address, for us humans:
Your function signatures (declarations) lack parameter names. More suitable:
int** createArray(int rows, int columns);
void deleteArray(int** array, int rows);
Your function names aren't too descriptive as to what they really create/delete. create2DArray would be a wiser choice, for example.
Your n prefixes to your variables hurt my eyes. numRows or rowCount is more readable.
Similarly, ppInt is crazy. Try array (for nPointer as well, for consistency). (Sadly, you can't write 2dArray.)
Using i as a loop counter is more common than nCount or similar (especially for array indexes). I suggest you use that instead.
Some things which go Above And Beyond, for your personal practice:
Create a class which takes rows and cols as arguments to its constructor. Make sure to deallocate the array automatically.
Use std::vector and create a resize member function for your class. Note that this deviates from the original question, which asked for pointers.
Create a copy function and a clone function to copy data to another 2D array (possibly of a different size!) or clone an existing array.
Its OK.
The problem is that you are not thinking about exception safety in your code.
int** ppInt = new int*[nRows]; // ALLOC 1
for (int nCount = 0; nCount < nRows; nCount++)
{
ppInt[nCount] = new int[nColumns]; // ALLOC 2
}
Say ALLOC 1 goes fine.
But if any of the ALLOC 2 fail then you have an exception and a severe memory leak.
For example.
You fail on the fourth call to ALLOC 2. Then you leak the memory from ALLOC 1 and the first three calls to ALLOC 2. Now in your situation the code is so trivial it probably does not matter. BUT this is the kind of thing you should always keep in mind when writting C++ code.
What will happen here if an exception is throw, what resources are going to be leaked what resources are not going to be cleaned up correctly.
I think you should think about wrapping your 2D array inside a class so that you can guarantee that memory is allocated and de-allocated correctly even in the presence of exceptions.
Looks reasonable to me.
I'm not sure about submitting a whole new question, though. It might have been better as an amendment to the original.
For "deleteArray", your prototype and definition aren't exactly the same:
void deleteArray(int*[], int);
void deleteArray(int** nPointer, int nRows)
They do have the same meaning, but for clarity I think it would be best to have them exactly the same (favoring `int**' to emphasize the fact that you're passing pointers) for consistency.
Also, include the argument names in the prototype.