C++ Function Alters Value of Passed Parameter - c++

I have a simple swapping function to take an integer array, and return a new array with swapped values.
int* Node::dataSwap(int *data, int n_index, int swap_index){
printDatt(data);
int *path = data;
int swapped = data[n_index];
int to_swap = data[swap_index];
path[n_index] = to_swap;
path[swap_index] = swapped;
printDatt(data);
return path;
}
However, the reference to the original data is being altered by this function. The output looks something like this (printing the should be the same data to console).
0, 1, 2
3, 4, 5
6, 7, 8
0, 1, 2
3, 4, 8
6, 7, 5
Why is "data" being changed when I am not changing it? Is "path" a reference to the actual mem addr of "data"?

The type of the argument data and the local variable path is int *. You can read this as "pointer to int".
A pointer is a variable holding a memory address. Nothing more, nothing less. Since you set path = data, those two pointers are equal.
In your mind, data is an array. But that's not what the function dataSwap is seeing. To the function dataSwap, its argument data is just a pointer to an int. This int is the first element of your array. You accessed elements of the array using data[n_index]; but that's just a synonym for *(data + n_index).
How to remedy to your problem?
The C way: malloc and memcpy
Since you want to return a new array, you should return a new array. To do this, you should allocate a new region of memory with malloc, and then copy the values of the original array to the new region of memory, using memcpy.
Note that it is impossible to do this using only the current arguments of the function, since none of those arguments indicate the size of the array:
data is a pointer to the first element of the array;
n_index is the index of one of the elements in the array;
swap_index is the index of another element in the array.*
So you should add a fourth element to the function, int size, to specify how many elements are in the array. You can use size as argument to malloc and memcpy, or to write a for loop iterating over the elements of the array.
New problem arising: if you call malloc to allocate new memory, then the user will have to call free to free the memory at some point.
C++ has the cool keyword new whose syntax is somewhat lighter than the syntax of malloc. But this doesn't solve the main problem; if you allocate new memory with the keyword new, then the user will have to free the memory with the keyword delete at some point.
Urgh, so much burden!
But this was the C way. A good rule of thumb in C++ is: never handle arrays manually. The standard library has std::vector for that. There are situations where using new might be the best solution; but in most simple cases, it isn't.
The C++ way: std::vector
Using the class std::vector from the standard library, your code becomes:
#include <vector>
std::vector<int> Node::dataSwap(std::vector<int> data, int n_index, int swap_index)
{
std::vector<int> new_data = data;
int swapped = data[n_index];
int to_swap = data[swap_index];
new_data[n_index] = to_swap;
new_data[swap_index] = swapped;
return (new_data);
}
No malloc, no new, no free and no delete. The class std::vector handles all that internally. You don't need to manually copy the data either; the initialisation new_data = data calls the copy constructor of class std::vector and does that for you.
Avoid using new as much as you can; use a class that handles all the memory internally, like you would expect it in a higher-level language.
Or, even simpler:
The C++ way: std::vector and std::swap
#include <vector>
#include <algorithm>
std::vector<int> Node::dataSwap(std::vector<int> data, int n_index, int swap_index)
{
std::vector<int> new_data = data;
std::swap(new_data[n_index], new_data[swap_index]);
return (new_data);
}

Is "path" a reference to the actual mem addr of "data"?
Yes! In order to create a new array that is a copy of the passed data (only with one pair of values swapped over), then your function would need to create the new array (that is, allocate data for it), copy the passed data into it, then perform the swap. The function would then return the address of that new data, which should be freed later on, when it is no longer needed.
However, in order to do this, you would need to also pass the size of the data array to the function.
One way to do this, using 'old-style' C++, is with the new operator. With the added 'size' parameter, your function would look something like this:
int* Node::dataSwap(int *data, int n_index, int swap_index, int data_size)
{
printDatt(data);
int *path = new int[data_size]; // Create new array...
for (int i = 0; i < data_size; ++i) path[i] = data[i]; // ... and copy data
int swapped = data[n_index];
int to_swap = data[swap_index];
path[n_index] = to_swap;
path[swap_index] = swapped;
printDatt(data);
return path; // At some point later on, your CALLING code would "delete[] path"
}

You are changing the memory at which the pointer path point and that is data. I think try to understand better how the pointers works will help you. :)
Then you can use the swap function from the std library:
std::swap(data[n_index], data[swap_index]);
It will make your code nicer.

Related

C++ linked list declaration

I come across a code as follow:
int* list = new int[5];
I never saw such declaration. What does it do? I suppose list is a pointer to an int? Using VS debug environment, I can see list having one int value. So how are the other element accessed? Thanks.
The statement is called badly-mannered dynamic (memory) allocation, involving two operators, new (new[]) and delete (delete[]). The new operator allocates memory and the delete operator deallocates memory.
Since it's a chunk of memory assigned to a pointer, it behaves mostly the same as an array (int list[5]), so you should access it as usually as you do with a pointer. Like
int *list = new int[5];
list[0] = 10; list[3] = 25; // Whatever
for (int i = 0; i < 5; i++)
list[i] = 1+1;
You can see a list of topics about dynamic allocation in C++ on Stack Overflow here.
This is not a linked list, but a construct known as dynamic memory. If you want to create an array normally, you would write something like
int myArray[3] = {
1, 2, 3
};
Notice that when I write the size of myArray (3), I use a constant expression; If I were to write
int x = 3;
int myArray[x] = {
1, 2, 3
};
It wouldn’t work, because x is a variable, not a constant expression. Note that even if x is a const, this still wouldn’t work. This is because before the program is run, memory needs to be allocated for the arrays.
When you say int * myData = new int[3], you can create memory on the fly, without constant expressions. In this case, it would be perfectly fine to do this
int x = 3;
int * myData = new int[x];
However, myData is a pointer, not an array, so the common sizeof(x) / sizeof(*x) trick doesn’t work here.
Make sure that after your dynamic memory is no longer of use, you write delete[] myData. This de-allocates the memory block and allows other memory to be stored in its place.
This memory is a block of memory just like an array. A linked list, however, is totally different, and would take a while to explain. Check out the Wikipedia on it.

Pointer to array changes value of array elements [duplicate]

This question already has answers here:
How do I use arrays in C++?
(5 answers)
Closed 6 years ago.
I have an array of integers that I pass into function. Then I want to make a dynamic array in that function as a copy of the first array, but whenever I change the value of an element in second array (copy), the value in the first array also changes. What am I doing wrong?
example:
int *array1 = new int[N]
int *array2 = new int[N]
array2 = array1;
array2[1]=2; //element of the first array at index 1 also becomes 2
Thank you.
The Explanation:
Since we are dealing with C++, there is pretty much no reason to use new int[N] instead of std::vecotr<int> of a size N.
To explain what is happening in your code: You create a pointer named array1 and allocate memory enough to contain N integers. You do the same with second pointer, called array2. Since the names array1 and array2 are just pointers to memory, what they point to can be changed. In the line array2 = array1 you change to what is pointing array2 to memory allocated and pointed to by array1 pointer.
So what happens now? Really bad stuff. You are encountering a memory leak. The memory that was pointed to by array2 is still there, still allocated, but you are unable to access it, since your only access to it (array2 pointer) now points to entirely different part of memory. You now also have 2 pointers that point to the same memory (originally the memory that was allocated in the line int *array1 = new int[N]).
How to improve your code?
Use std::vector<int>. Vector class comes with well written and safe assignment operator that will work for you here:
std::vector<int> array1(N);
std::vector<int> array2(N);
array2 = array1;
Now you have 2 identical vectors, memory is managed well (array1 and array2 are separate entities. They do not share the same memory and can be freely changed without affecting the other one) and your code looks pretty.
What if you cannot change everything to std::vector?
You mentioned having an array that you pass into a function. Let's call it an original_array of a size N. Consider this code, which uses similar signature, but uses safe memory management by converting array to vector:
void copy_and_do_stuff(int original_array[], int N)
{
std::vector<int> array2;
std::copy(original_array, original_array + N, array2.begin());
// here, the vector "array2" is a copy of your `original_array`. Changes
// to it will not affect your argument.
// ... do whatever you need to do in this function ...
}
Remember to add #include <vector> and #include <algorithm> to use vectors and std::copy function.
To give a full answer, although the comments say everything important so far:
The line array2 = array1; does the following: take the address that is stored in array1 and store it also in array2. They are both pointing at the same location now (and the old, reserved storage is still reserved but not pointed at, aka a memory loss)
In any case, pointers are somewhat dangerous things, easily leading to unexpected behaviour, especially if you are a beginner. Therefore, you want to use std::vector:
//at the head of the file
#include <vector>
using std::vector;
//in the program
vector<int> array_1(n);
//do something with array_1:
array_1[0] = 1;
array_1[1] = ...
vector<int> array_2 = array_1; //actually copies the content
or:
vector<int> array_2(array_1); //copy constructor
At some point you will want to investigate how vector works internally (it wraps an array, actually), but for now, simply use vector. Read it's documentation. You can do all sorts of things on it with the STD library, like for example having it sorted by std::sort.
As mentioned in the comments you probably shouldn't be doing this in c++; std::vector is THE optimized; safe and reliable way to handle data of this sort.
But it is clear from your question that you don't really understand pointers.
This is what you code does:
int *array1 = new int[N]; //allocate memory for the first array
int *array2 = new int[N]; //allocate memory for the second array
array2 = array1; //OVERWRITE the location of the second array
//with that of the first (thus destroying your
//only pointer to the second array and creating a
//memory leak)
To achieve what you want in array2=array1 you need to write a loop and copy every integer ELEMENT of the array across to the new array - this creates a 'deep' copy.
array1 and 2 are pointers in your case.
When you do:
array2 = array1;
array2 points to the same memory location as array1, and the old array2 is lost in memory (and so it creates a memory leak, as Elemental said)
You need to copy the array elements by hand or use std::vector

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.]

initialize an int[][] with new()

I am a c++ newbie. While learning I came across this.
if I have a pointer like this
int (*a)[2][3]
cdecl.org describe this as declare a as pointer to array 2 of array 3 of int:
When I try
int x[2][3];
a = &x;
this works.
My question is how I can initialize a when using with new() say something like
a = new int [] [];
I tried some combinations but doesn't get it quite right.
Any help will be appreciated.
You will have to do it in two steps - first allocate an array of pointers to pointers(dynamically allocated arrays) and then, allocate each of them in turn. Overall I believe a better option is simply to use std::vector - that is the preferred C++ way of doing this kind of things.
Still here is an example on how to achieve what you want:
int a**;
a = new int*[2];
for (int i =0; i< 2;++i){
a[i] = new int[3]
}
... use them ...
// Don't forget to free the memory!
for (int i = 0; i< 2; ++i) {
delete [] a[i];
}
delete [] a;
EDIT: and as requested by Default - the vector version:
std::vector<std::vector<int> > a(2, std::vector<int>(3,0));
// Use a and C++ will take care to free the memory.
It's probably not the answer you're looking for, but what you
need is a new expression whose return type is (*)[2][3] This
is fairly simple to do; that's the return type of new int
[n][2][3], for example. Do this, and a will point to the
first element of an array of [2] of array of [3] int. A three
dimensional array, in sum.
The problem is that new doesn't return a pointer to the top
level array type; it returns a pointer to the first element of
the array. So if you do new int[2][3], the expression
allocates an array of 2 array of 3 int, but it returns
a pointer to an array of 3 int (int (*a)[3]), because in C++,
arrays are broken (for reasons of C compatibility). And there's
no way of forcing it to do otherwise. So if you want it to
return a pointer to a two dimensional array, you have to
allocate a three dimensional array. (The first dimension can be
1, so new [1][2][3] would do the trick, and effectively only
allocate a single [2][3].)
A better solution might be to wrap the array in a struct:
struct Array
{
int data[2][3];
};
You can then use new Array, and everything works as expected.
Except that the syntax needed to access the array will be
different.

C++ Allocate Memory Without Activating Constructors

I'm reading in values from a file which I will store in memory as I read them in. I've read on here that the correct way to handle memory location in C++ is to always use new/delete, but if I do:
DataType* foo = new DataType[sizeof(DataType) * numDataTypes];
Then that's going to call the default constructor for each instance created, and I don't want that. I was going to do this:
DataType* foo;
char* tempBuffer=new char[sizeof(DataType) * numDataTypes];
foo=(DataType*) tempBuffer;
But I figured that would be something poo-poo'd for some kind of type-unsafeness. So what should I do?
And in researching for this question now I've seen that some people are saying arrays are bad and vectors are good. I was trying to use arrays more because I thought I was being a bad boy by filling my programs with (what I thought were) slower vectors. What should I be using???
Use vectors!!! Since you know the number of elements, make sure that you reserve the memory first (by calling myVector.reserve(numObjects) before you then insert the elements.).
By doing this, you will not call the default constructors of your class.
So use
std::vector<DataType> myVector; // does not reserve anything
...
myVector.reserve(numObjects); // tells vector to reserve memory
You can use ::operator new to allocate an arbitrarily sized hunk of memory.
DataType* foo = static_cast<DataType*>(::operator new(sizeof(DataType) * numDataTypes));
The main advantage of using ::operator new over malloc here is that it throws on failure and will integrate with any new_handlers etc. You'll need to clean up the memory with ::operator delete
::operator delete(foo);
Regular new Something will of course invoke the constructor, that's the point of new after all.
It is one thing to avoid extra constructions (e.g. default constructor) or to defer them for performance reasons, it is another to skip any constructor altogether. I get the impression you have code like
DataType dt;
read(fd, &dt, sizeof(dt));
If you're doing that, you're already throwing type safety out the window anyway.
Why are you trying to accomplish by not invoking the constructor?
You can allocate memory with new char[], call the constructor you want for each element in the array, and then everything will be type-safe. Read What are uses of the C++ construct "placement new"?
That's how std::vector works underneath, since it allocates a little extra memory for efficiency, but doesn't construct any objects in the extra memory until they're actually needed.
You should be using a vector. It will allow you to construct its contents one-by-one (via push_back or the like), which sounds like what you're wanting to do.
I think you shouldn't care about efficiency using vector if you will not insert new elements anywhere but at the end of the vector (since elements of vector are stored in a contiguous memory block).
vector<DataType> dataTypeVec(numDataTypes);
And as you've been told, your first line there contains a bug (no need to multiply by sizeof).
Building on what others have said, if you ran this program while piping in a text file of integers that would fill the data field of the below class, like:
./allocate < ints.txt
Then you can do:
#include <vector>
#include <iostream>
using namespace std;
class MyDataType {
public:
int dataField;
};
int main() {
const int TO_RESERVE = 10;
vector<MyDataType> everything;
everything.reserve( TO_RESERVE );
MyDataType temp;
while( cin >> temp.dataField ) {
everything.push_back( temp );
}
for( unsigned i = 0; i < everything.size(); i++ ) {
cout << everything[i].dataField;
if( i < everything.size() - 1 ) {
cout << ", ";
}
}
}
Which, for me with a list of 4 integers, gives:
5, 6, 2, 6