Consider this piece of code.
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector <int *> test;
vector <int *> v;
int *a = new int;
int *b = new int;
*a = 1;
*b = 2;
v.push_back (a);
v.push_back (b);
for (int i = 0; i < 2; ++i)
{
int n = *v[i];
test.push_back (&n);
}
cout << *test[0] << " " << *test[1] << endl;
delete a;
delete b;
return 0;
}
The problem's statement is:
"Given this code, answer the following questions:
Why does "test" vector contain only 2's?
How can we change for loop to copy properly (only code inside for loop)?"
I couldn't answer any of these questions, so a little bit of help will be appreciated.
Thanks in advance.
That code introduces dangling pointers. The body of the loop looks like this:
{
int n = *v[i];
test.push_back (&n);
}
The local variable n loses scope as soon as the loop body ends, so the pointer &n is now a dangling pointer. If it happens that test contains only 2's, that's just what randomly came out of what is undefined behavior.
If you want to "properly" copy the data over to test, you can change the for loop body to this:
{
int* n = new int;
*n = *v[i];
test.push_back (n);
}
Please take the "properly" with a grain of salt...
You push two the same pointers to n into test array. n equals the last element of your first array. Note that after control flow exited the loop, all pointers to n become invalid. So, in fact your test array contains invalid pointers, not pointers to 2s.
You should create a copy of each integer:
int* n = new int(*v[i]);
test.push_back (n);
Note also that you have memory leak here. Each int created using new should be later destroyed using delete.
The first question is a trick question: The vector contains pointers to a variable that no longer exists, and dereferencing that could cause pretty much any output. I imagine on some machines and compilers it prints all 2s however.
I can't understand what the exercise is trying to do (why does it use vectors of pointers for example) so I can't really help with how to solve the problem.
One way you could do it is by making test store by value:
First change the test vector to vector <int> test;
Then change the push_back to something like test.push_back (n); and finally the print statements to remove the now-unneeded * operators.
EDIT for comment:
First, I'm suspect of this book: It shouldn't be demonstrating undefined behavior or raw pointers to single builtin types. But you can change your loop body if you want:
for (int i = 0; i < 2; ++i)
{
int* n = new int;
*n = *v[i];
test.push_back (&n);
}
Note that both this will cause a memory leak unless you later delete those pointers, a problem that storing by value eliminates.
1) I think that the premise of the question is faulty. The loop adds two elements to test, each contains the address of the automatic variable n, the scope of which is limited to the body of the loop. It's not guaranteed that n will be allocated the same memory location in both passes through the loop, but I suppose that it's likely that most compilers will reuse the same location in both passes.
Moreover, n is out of scope at the output statement. So referencing the pointers in test to those memory locations is undefined. Again, there's a good chance that they will still contain the values assigned in the loop.
So, only if the same location gets reused for n in the second pass of the loop and that location has not been overwritten at the time the output statement is executed, will the output be "2 2". There is no guarantee of either of these premises.
2) To get the output "1 2" without changing anything outside the loop, one could change the definition of n to int& n = *v[i], which would be a single character change from the given code, though the end result is rather strange.
A simpler solution would be to eliminate the temporary n and simply test.push_back(v[i]).
Related
I want to ask a question regarding entering elements in a dynamic array. I declare an array and then I want to enter elements in it. How can I do this using pointers into the array arr[] that I have declared previously?
Thanks in advance!
#include <iostream>
#include <algorithm>
using namespace std;
int *n = new int ;
int main()
{
cin>>*n;
int *arr = new int[*n];
int *i=new int;
for(*i=0; *i<=*n; *i++)
{
//Here, I should enter the elements but I cannot figure out how?
cin>>(*arr+i);
}
return 0;
}
While I question your usage of pointers for the size of the array and the index (They should just be int n; and int i = 0;, respectively), you can fix your code by using the subscript operator, or in code:
cin >> arr[*i];
Using pointer arithmetic is just unclear and makes it hard to tell what your goal is (In case you're wondering, the correct notation is *(arr+*i), which looks horrible IMO).
On a side note, consider using std::vector as a container, which will make your life a lot easier and prevent you from having to deal with pointers. Usage of std::vector may look like:
int main()
{
std::vector<int> arr;
for (int x; std::cin >> x;)
{
arr.push_back(x);
}
return 0;
}
This would prevent you from having to ask the user for the size of the std::vector as well and allow them to keep entering elements until they enter an EOF.
Here I am not changing your original approach at all so that you can understand pointer concept a bit more clear. As you know that array and pointer address calculation are exactly same. First you need to calculate the address and then dereference it. You just need to change it like below:-
cin>>*arr++;
Also you need to change your for loop like below:-
for(*i=0; *i<=*n; (*i)++)
But now after the above for loop you are going to face problem. The reason is that after storing each element in arr we have incremented the address of arr(arr++), so after the end of for loop arr is now pointing to the last element ( because arr = arr+*n). So first simply try with the below code:-
cout<<*arr<<endl<<endl;
if you have entered five numbers for example 0,1,2,3, and 4 the above statement will print some junk value as pointer is increment one more time.
now try with below:-
arr--;// Now arr will point to last element i.e. 4
cout<<*arr<<endl<<endl;
Hence you need one more int pointer and should store the first address of arr in it like below:-
int *arr = new int[*n];//exactly after this line of code
int *first = arr;
Now use a for loop to print the array:-
arr = first; //pointing to the first eliment
for(*i=0; *i<=*n; (*i)++)
{
//Here, I should enter the elements but I cannot figure out how?
cout<<*arr++<<endl;
}
I have an array of structs. I am trying to delete a list of elements from that array and shift other elements to the left. After shifting the elements I am trying to delete/free the memory at the end of the array which we don't require anymore. I have the following code:
#include <iostream>
#include<stdio.h>
#include<stdlib.h>
void removeelement(int*);
void displayelements();
typedef struct {
int n;
}element;
element** array;
int numofelements=5;
int main() {
array = (element**)malloc(5*sizeof(element*));
for(int i=0;i<5;i++){
array[i] = new element;
array[i]->n=i;
}
int removelist[3] = {1,3,4};
removeelement(removelist);
displayelements();
return 0;
}
void removeelement(int* removelist){
for(int i=0;i<3;i++){
int index = removelist[i];
int j;
for(j=index;j<numofelements-2;j++){
array[j] = array[j+1];
}
delete [] array[j+1];
numofelements--;
}
}
void displayelements(){
int i=0;
while(i<numofelements){
printf("%d\n",array[i]->n);
i++;
}
}
But delete [] array[j+1]; is causing an exception:
*** Error in `main': double free or corruption (fasttop): 0x0000000001861cb0 ***
I don't understand what's causing this. As many people have suggested in other forums, I am using the 'new' operator to create a new,dynamic element.
EDIT:
I made the following changes:
I changed for(j=index;j<numofelements-2;j++){ to for(j=index;j<numofelements-1;j++){
int index = removelist[i] to int index = removelist[i]-i
I removed delete [] array[j+1] put delete array[numofelements+1] outside both the for loops.
Though I had used delete only on one element, It dealloced memory for the other redundant elements as well, which is interesting.
This is the final code:
#include <iostream>
#include<stdio.h>
#include<stdlib.h>
void removeelement(int*);
void displayelements();
typedef struct {
int n;
}element;
element** array;
int numofelements=5;
int main() {
array = (element**)malloc(5*sizeof(element*));
for(int i=0;i<5;i++){
array[i] = new element;
array[i]->n=i;
}
int removelist[3] = {1,3,4};
removeelement(removelist);
displayelements();
return 0;
}
void removeelement(int* removelist){
for(int i=0;i<3;i++){
int index = removelist[i]-i;
int j=index;
for(;j<numofelements-1;j++){
array[j] = array[j+1];
}
numofelements--;
}
delete array[numofelements+1];
}
void displayelements(){
int i=0;
while(i<5){
printf("%d\n",array[i]->n);
i++;
}
}
I got it working using this code. But I am going to use std::vector as many of you suggested.
You used delete[] expression on a pointer that was not returned by new[] expression. Therefore the behaviour of the program is undefined.
Anything that was allocated with new must be deallocated with delete. delete[] will not do.
Even if you had used the correct expression, there's another bug:
int numofelements=5;
//...
for(int i=0;i<3;i++){
int index = removelist[i];
int j;
for(j=index;j<numofelements-2;j++){
array[j] = array[j+1];
}
delete [] array[j+1];
numofelements--;
}
After the first iteration of the outer loop, array[4] has been deleted. Note that since removelist[i] == 1, I suspect that array[4] wasn't supposed to be deleted in the first place.
During the second iteration, array[4] will be deleted again. Since this points to the already deleted object, the behaviour is undefined.
Furthermore, copies of the deleted pointer remain in the array due array[j] = array[j+1] in the inner loop, while some of the pointers will be overwritten and therefore their memory will be leaked. Simple fix to your algorithm: Delete the pointer at index first, and shift elements after deletion.
Even more: If your loop worked as you intended, first 2 iterations would have each removed an element of the array, thus reducing numofelements to 3. Then, you'd be removing an element at index 4 of an array that has valid pointers in indices 0..2. Presumably the indices to be removed must be sorted; In that case, this can be fixed by deleting the index removelist[i] - i to acount for the shifts. Another clever strategy is to remove the indices from high to low, as suggested by Paul.
Other things to consider:
The program leaks the memory allocated for array. That might not be a problem to this trivial program, but it would be a good idea to have a habit of deallocating all memory that was allocated lest you forget to do so when it matters.
It's a bad idea to use malloc unless one has specific and reasonable justification to do so. One usually doesn't have a reasonable justification to use malloc.
It's a bad idea to allocate dynamic memory at all without using a RAII container. The bugs in this program would have been trivially been avoided if std::vector had been used.
Apart from the obvious errors in memory management, the approach in general could have been made simpler if you first sorted the removelist array, and then work backwards in that array starting from the last entry going toward the first entry.
Doing this would have changed the way the array was being resized in that you would have been doing the resizing (shifting elements) on entries that will no longer be affected. In your current code, you are shifting entries, and in subsequent iterations of the loop, you need to revisit those shifted entries with a now "invalid" removelist set of indices to remove.
See mayaknife's and user2079303 answers to illustrate the issue of invalid entries after removing each item (going from lowest entry to highest entry in the removelist array). As pointed out, even a usage of std::vector would not have helped you, since this issue points out the flaw in the basic logic being used to remove the elements.
Here is how you might have addressed this in your current code if you were to work going backwards in the removelist array ( I say "might have addressed", since this is not fully tested, but it illustrates more or less the point being made):
void removeelement(int* removelist)
{
for(int i = 2; i >= 0 ; --i)
{
int index = removelist[i];
array* elementToDelete = array[index];
for(j=index; j < numofelements -2; j++)
{
array[j] = array[j+1];
}
delete [] elementToDelete;
numofelements--;
}
}
Thus on each iteration, the removelist index will still be valid, since you're going from highest entry to lowest entry in the entries to delete. Work this out on paper and you see if you reversed the way you iterated through the removelist array, you should see how this works, as opposed to going forward through the removelist array.
You also have other issues with the code, such as mixing malloc with delete[]. Doing so is undefined behavior -- never mix allocation / deallocation methods like this in a C++ program.
Having said this, here is another version of your program, but not using manual memory management:
#include <vector>
#include <algorithm>
#include <iostream>
#include <array>
struct element {
int n;
};
int main()
{
std::vector<element> arr(5);
for (int i = 0; i < 5; ++i)
arr[i].n = i;
std::array<int, 3> removelist = {1,3,4};
// sort the list
std::sort(removelist.begin(), removelist.end());
// work backwards, erasing each element
std::for_each(removelist.rbegin(), removelist.rend(),[&](int n){arr.erase(arr.begin() + n);});
// output results
for( auto& v : arr)
std::cout << v.n << '\n';
}
Live Example
Note the usage of the reverse iterators rbegin() and rend(), thus mimicking the backwards traversal of the removelist container.
This line:
delete [] array[j+1];
deletes the array of elements pointed to by 'array[j+1]'. But 'array[j+1]' was initialized by this line:
array[i] = new element;
which only allocates a single element, not an array of elements, so the deletion should only delete a single element as well. E.g:
delete array[j+1];
The main problem, however, is that the wrong elements are being deleted. To see why, let's assume that the loop which initializes 'array' assigns it pointers to five 'element' structures which we will refer to as A, B, C, D and E.
Before the call to removeelements(), 'array' contains the following pointers:
array[0] -> A
array[1] -> B
array[2] -> C
array[3] -> D
array[4] -> E
'numofelements' is 5.
Inside removeelements(), the first element to be removed is 1 and the inner loop looks like this:
for(j=1;j<3;j++){
array[j] = array[j+1];
}
This will result in the contents of 'array[2]' being copied into 'array[1]' and 'array[3]' being copied into 'array[2]. After that 'array' contains the following:
array[0] -> A
array[1] -> C
array[2] -> D
array[3] -> D
array[4] -> E
At this point 'j' contains 3 so 'delete array[j+1]' will delete the element pointed to by 'array[4]', which is 'E'.
'numofelements' is then decremented to 4.
The second element to be removed is 3. Because 'numofelements' is now 4, the inner loop will look like this:
for(j=3;j<2;j++){
array[j] = array[j+1];
}
'j' will be initialized to 3. That is greater than 2 so the body of the loop won't execute and 'array' will be left unchanged.
Since 'j' is 3 'delete array[j+1]' will again delete 'array[4]', which still points to E. So E is deleted a second time, resulting in the error that you are getting.
Were the program to continue, 'numofelements' would be decremented to 3 and we'd move on to the third element to be removed, which would be 4. This would give an inner loop like this:
for(j=4;j<1;j++){
array[j] = array[j+1];
}
'j' would be initialized to 4 and once again the body of the loop would not be executed. 'delete array[j+1]' would attempt to delete the element pointed to by 'array[5]', which is beyond the bounds of 'array' and would result in an exception.
As others have suggested, the best way to handle this is to use std::vector. However, the way your code is structured even std::vector will fail to give you the results you want because as soon as you delete one element from 'array' the indices of all of those which follow it will change, meaning that the remaining indices in 'removelist' will no longer be correct.
I suggest that whatever changes you make, you manually step through the code, as I have above, tracking the contents of the array and relevant variables so you can understand exactly what your code is doing.
So i read this thread and many others:
Function does not change passed pointer C++
Yet i still can't solve my issue.
I have a function declared like this:
void test(list<int*> *listNodes){
int v=5;
(*listNodes).push_back(&v);
(*listNodes).push_back(&v);
(*listNodes).push_back(&v);
for(int a = 0; a < (*listNodes).size(); a ++){
std::list<int*>::iterator i = (*listNodes).begin();
advance(i, a);
int *totry = *i;
cout << *totry;
cout << ",";
}
}
Wich works, and prints fine, by the i mean: the listNodes variable has 3 elements, all 5's. However, when this functions returns, the values are not updated. By that, i mean that the variable has trash. I call this function in another one like this:
void create(list<int*> listNodes){
test(&listNodes);
for(list<int*>::const_iterator it=listNodes.begin();
it!=listNodes.end(); it++){
int *show=*it;
cout << *show << '\n';
}
}
Again, in this function, the cout will output memory garbage instead of outputting the 3 fives.
Any ideas on how should i proceed to, when the function test comes back, i have the list populated?
The problem I believe you're thinking about (as opposed to other problems in this code) is not actually what you're thinking. The list DOES maintain its values, the problem is that the values it has are pointing to garbage memory.
When you do this:
int v=5;
(*listNodes).push_back(&v);
(*listNodes).push_back(&v);
(*listNodes).push_back(&v);
You are putting three copies of the address of v into the list. You have declared v as a stack variable that only exists for the duration of this function. When you print the values pointed to by the elements of listNodes inside function test, that variable still exists in that memory location.
When you later print out the values pointed to by the elements of listNodes in function create, that variable has gone out of scope and has been used by something else, hence the garbage.
Here are two possible solutions to consider:
Use list<int> instead of list<int *>. If all you want to do is store a list of integers, this is the way to go.
If, on the other hand, you really need to store pointers to those integers, you'll need to allocate memory off the heap:
int* v = new int(); // allocate an int on the heap
*v = 5; // store 5 in that int
(*listNodes).push_back(v); // save the pointer to the allocated
// memory in *listNodes
etc
This is not very good in terms of modern c++, however, as you generally don't want to be handling raw pointers at all, but it illustrates the point I think you are struggling with.
In this code,
void create(list<int*> listNodes){
listNodes=teste(&listNodes);
… the formal argument listNodes is passed by value. That means that the function receives a copy of whatever was passed as actual argument in a call siste. Changes to this copy will not be reflected in the actual argument.
The call to teste won't call the test function, since it's a different name.
In a way that's good, because test is declared as a void function so it can't return anything.
But it's also bad, because it means that a very crucial piece of your code, the teste function that's actually called, isn't shown at all in your question.
The test function,
void test(list<int*> *listNodes){
int v=5;
(*listNodes).push_back(&v);
for(int a = 0; a < (*listNodes).size(); a ++){
std::list<int*>::iterator i = (*listNodes).begin();
advance(i, a);
int *totry = *i;
cout << *totry;
cout << ",";
}
printf("\n");
}
… has a lot wrong with it.
Starting at the top, in C++ the pointer argument
void test(list<int*> *listNodes){
… should better be a pass-by-reference argument. A pointer can be null. That doesn't make sense for this function, and the code is not prepared to handle that.
Next, in
int v=5;
(*listNodes).push_back(&v);
… the address of a local variable is pushed on a list that's returned. But at that point the local variable ceases to exist, and you have a dangling pointer, one that used to point to something, but doesn't anymore. If the caller uses that pointer then you have Undefined Behavior.
Next, this loop,
for(int a = 0; a < (*listNodes).size(); a ++){
std::list<int*>::iterator i = (*listNodes).begin();
advance(i, a);
… will work, but it needlessly has O(n2) complexity, i.e. execution time.
Just iterate with the iterator. That's what iterators are for. Iterating.
Summing up, the garbage you see is due to the undefined behavior.
Just, don't do that.
here is my code and im not allowed to use a loop in the subarray function im pretty confused maybe someone can point me in the right direction i feel like im almost there..
int *duplicateArray(int *arr, int size)
{
int *newArray;
if (size<=0)
return NULL;
newArray = new int[size];
for (int index=0;index<size;index++)
newArray[index]=arr[index];
return newArray;
}
int* subArray(int *sub, int start, int length)
{
int aa[10]={1,2,3,4,5,6,7,8,9,10};
int *dup;
dup = aa;
duplicateArray(dup,10);
return dup;
}
int main()
{ cout << "Testing subArray: " << endl
<< "Expected result: 5, 6, 7, 8 " << endl;
int *subArr;
int start = 5;
subArr = subArray(subArr, 5,4);
for (int index = start; index<10; index++)
cout << subArr[index];
delete [] subArr;
subArr = 0;
So, since this is homework, I'm going to avoid posting a solution directly. You say that;
im not allowed to use a loop in the subarray function
Yet, currently, subArray calls duplicateArray, which uses a loop. This seems to be in conflict with the spirit of the requirement.
Since you haven't said otherwise, I'm assuming that subArray should duplicate the contents of its argument between start and the end. So, what do we know?
We know that the size of the returned array should be length - start elements. We also know (well, perhaps) that a function named memcpy exists which allows you to copy a block of bytes from one place to another (assuming they do not overlap).
(note that I am suggesting memcpy here because we are dealing with POD types (Plain Old Data) and because I doubt your class has delved into the STL. In the future you will be better served by something like std::copy(), but for now this is ok)
So, in order, we need to:
Declare a new array to return with length - start elements. You must dynamically allocate this array! Currently you are returning a pointer to a locally declared array. That pointer becomes invalid as soon as the function returns.
Copy length - start elements (elements, not bytes! Make sure to take into account the number of elements as well as the size of an individual element) from sub + start into this new array.
Return the new array (pointer really).
If I have somehow violated the requirements or intent of your assignment then you need to elaborate on your problem for me. Currently there is not much to go on.
I am attempting to write a template/class that has a few functions, but I'm running into what seems like a rather newbie problem. I have a simple insert function and a display values function, however whenever I attempt to display the value, I always receive what looks like a memory address(but I have no idea), but I would like to receive the value stored (in this particular example, the int 2). I'm not sure how to dereference that to a value, or if I'm just completely messing up. I know that vectors are a better alternative, however I need to use an array in this implementation - and honestly I would like to gain a more thorough understanding of the code and what's going on. Any help as to how to accomplish this task would be greatly appreciated.
Example Output (running the program in the same way every time):
003358C0
001A58C0
007158C0
Code:
#include <iostream>
using namespace std;
template <typename Comparable>
class Collection
{
public: Collection() {
currentSize = 0;
count = 0;
}
Comparable * values;
int currentSize; // internal counter for the number of elements stored
void insert(Comparable value) {
currentSize++;
// temparray below is used as a way to increase the size of the
// values array each time the insert function is called
Comparable * temparray = new Comparable[currentSize];
memcpy(temparray,values,sizeof values);
// Not sure if the commented section below is necessary,
// but either way it doesn't run the way I intended
temparray[currentSize/* * (sizeof Comparable) */] = value;
values = temparray;
}
void displayValues() {
for (int i = 0; i < currentSize; i++) {
cout << values[i] << endl;
}
}
};
int main()
{
Collection<int> test;
int inserter = 2;
test.insert(inserter);
test.displayValues();
cin.get();
return 0;
}
Well, if you insist, you can write and debug your own limited version of std::vector.
First, don't memcpy from an uninitialized pointer. Set values to new Comparable[0] in the constructor.
Second, memcpy the right number of bytes: (currentSize-1)*sizeof(Comparable).
Third, don't memcpy at all. That assumes that Comparable types can all be copied byte-by-byte, which is a severe limitation in C++. Instead:
EDIT: changed uninitialized_copy to copy:
std::copy(values, values + currentSize - 1, temparray);
Fourth, delete the old array when it's no longer in use:
delete [] values;
Fifth, unless the code is going to make very few insertions, expand the array by more than one. std::vector typically increases its size by a factor of 1.5.
Sixth, don't increment currentSize until the size changes. That will change all those currentSize-1s into currentSize, which is much less annoying. <g>
Seventh, an array of size N has indices from 0 to N-1, so the top element of the new array is at currentSize - 1, not currentSize.
Eighth, did I mention, you really should use std::vector.
This line is wrong:
memcpy(temparray,values,sizeof values);
The first time this line is run, the values pointer is uninitialized, so it will cause undefined behavior. Additionally, using sizeof values is wrong since that will always give the size of a pointer.
Another issue:
temparray[currentSize] = value;
This will also cause undefined bahavior because you have only allocated currentSize items in temparray, so you can only access indices 0 to currentSize-1.
There is also an error in your array access.
temparray[currentSize/* * (sizeof Comparable) */] = value;
Remember that arrays start at index zero. So for an array of length 1, you would set temparray[0] = value. Since you increment currentSize at the top of the insert function, you will need to do this instead:
temparray[currentSize-1] = value;