How do pointers work - c++

Here is simple code I'm asking my questions about.
struct Class{
public:
int key;
Class*next;
};
int main(){
Class c;
c.key = 1;
Class* p = &c;
for (int i = 2; i < 5; i++){
Class next;
next.key = i;
p->next = &next;
p = p->next;
}
p = &c;
for (int i = 1; i < 5; i++){
std::cout << p->key;
p = p->next;
}
}
Output I was expecting: 1234
Output I've got: 1444
Can you, please, tell me what is wrong with my code, and what do I have to do to get 1234.

for (int i = 2; i < 5; i++){
Class next;
next.key = 2;
p->next = &next;
p = p->next;
}
The lifetime of the next object ends at the end of each iteration. Since you're assigning the address of this object to p->next, this pointer is left dangling when the iteration ends. In the next iteration, when you attempt to use p, you are invoking undefined behaviour.

Your logic seems correct but as the other commentators pointed out the variables created inside a loop are local to that loop so expire as soon as you are out of the loop. You need a minor modification.
Alternate solution: Just replace your first loop with:
for (int i = 2; i < 5; i++){
p->next = new Class;
p->next->key = i;
p = p->next;
}
This will allocate required memory and create a new entry at each iteration.
Hope that helps!

To explain Chris' comment - accessing a variable outside of its scope is undefined behavior. Your next variable's scope is one iteration of the for loop, once you have reached the closing } for the loop (and i++ has run, I think), it is up to the compiler to deal with deallocating the memory for next, and then reinitializing it next run. Your compiler appears to be making the reasonable decision to keep next in the same piece of memory and run the constructor again on each iteration, which is why your memory access is not throwing segmentation faults (IE, trying to access memory your program hasn't been granted access to). Your compiler could also decide to deallocate next as soon as you exit the for loop, but also doesn't appear to be doing that, which is why you are able to access its memory to print.
Long story short, don't worry too much about figuring out why your program does what it does, instead use heap memory as shown by kvorobiev, which will persist past the end of the for loop's scope. As good practice, you should also delete the memory once you are done wit it.

The problem is that inside this loop
for (int i = 2; i < 5; i++){
Class next;
next.key = 2;
p->next = &next;
p = p->next;
}
for each its iteration you are using the same local variable. Thus for the second iteration of the loop p->next points to the same local object.
So your porgram has undefined behaviour because this local object is not alive after exiting the loop. In general case the memory occupied by the local variable can be overwritten.
It seems that as result you have to nodes. One is c that points to already "died" node next and the died node next that points to itself and keeps the last value that was stored in data member key that is 4.
You should either dynamically allocate each node or use an array of nodes of the list.
Here is a demonstrative program that shows how you could use a simialr approach by means of an array.
#include <iostream>
struct Class
{
public:
int key;
Class *next;
};
int main()
{
const size_t N = 4;
Class c[N];
c[0].key = 1;
Class *p = &c[0];
for ( size_t i = 1; i < N; i++ )
{
c[i].key = i + 1;
p->next = &c[i];
p = p->next;
}
p = &c[0];
for ( int i = 0; i < N; i++ )
{
std::cout << p->key;
p = p->next;
}
std::cout << std::endl;
return 0;
}
The output is
1234

Related

How do I properly reference this pointer multiple times?

This is my function to find the union of 2 set arrays located by a void pointer which I have issues running the first part to copy Set A into the union Set before doing comparisons with Set B
Right now the output of this code produces example
Set A = {1,5,7,8}
Union Set = {8,8,8,8} Copies last element of Set A 4 times
as the last loop causes the temp pointer to point at 8.
Do I have to create a new int pointer for each loop or is there a better way of going around this
// Note I cannot use vectors or sorting methods as it isnt in my learning scope yet so i'll have to stick to the primitive comparison way
//Definitions
// VoidPtr is Void*
// aSet is (VoidPtr *a = new VoidPtr[MAX])
// getElementI(aSet[i]) Returns an integer value at that position of the pointer
void findUnion(VoidPtr * aSet,VoidPtr * bSet,VoidPtr * unionSet,int sizea,int sizeb,int &sizec)
{
int* temp;
VoidPtr vp;
int notEqual = 0;
// Copy set a into set c
for(int i =0; i < sizea; i++)
{
*temp = getElementI(aSet[i]);
vp = temp;
unionSet[i] = vp;
}
}
int* temp;
Here temp is an uninitiaised pointer
*temp = getElementI(aSet[i]);
Here temp is being dereferenced. Dereferencing uninitialised pointers results in a program crash (at best) and all sorts of weird behaviour (at worst).
I'm finding it quite hard to understand what you really need to do, but allocating a new int pointer every time round the loop sounds reasonable. Like this
for(int i =0; i < sizea; i++)
{
int *temp = new int (getElementI(aSet[i]));
unionSet[i] = temp;
}
But I am guessing.

C++ Pointers and Dynamic Arrays and Delete Operator

Ok so I am going to lay out two programs. Both are dynamic arrays using pointers and the new operator. But one doesn't seem to like the delete operator.
#include <iostream>
int main()
{
int *p;
p = new int[5];
for (int i = 0; i < 5; i++)
{
p[i] = 25 + (i * 10);
std::cout << p[i] << " ";
}
std::cout << std::endl;
delete [] p;
p = NULL;
return 0;
}
That's the first program. It likes the delete operator just fine. Now the program that dislikes the delete operator:
#include <iostream>
int main()
{
int x;
int *p;
p = new int[5];
*p = 4;
for (int i = 0; i < 5; i++)
{
std::cout << *p << " ";
x = *p;
p++;
*p = x + 1;
}
std::cout << std::endl;
delete [] p;
p = NULL;
return 0;
}
This program compiles just fine. But during execution, it throws an error - free(): invalid pointer: 0xfdb038 .. or whatever the memory address is for that particular execution. So, the question is:
Why can't the delete operator be used in the second case?
I don't want to have memory leak; I don't want the pointer to be dangling.
If I just say p = NULL;, then p = 0, but I believe the pointer is still dangling?, but I'm not sure. Thanks in advance.
Look at this loop in the second piece of code:
for (int i = 0; i < 5; i++)
{
std::cout << *p << " ";
x = *p;
p++;
*p = x + 1; // <--- Here
}
Notice that in this line, you write to the memory address currently pointed at by p. Since you always increment p and then write to it, you end up writing off past the end of the region that you allocated for p. (If we imagine pOrig as a pointer to where p initially points, then this writes to pOrig[1], pOrig[2], pOrig[3], pOrig[4], and pOrig[5], and that last write is past the end of the region). This results in undefined behavior, meaning that literally anything can happen. This is Bad News.
Additionally, delete[] assumes that you are passing in a pointer to the very first element of the array that you allocated. Since you've incremented p so many times in that loop, you're trying to delete[] a pointer that wasn't at the base of the allocated array, hence the issue.
To fix this, don't write to p after incrementing it, and store a pointer to the original array allocated with new[] so that you can free that rather than the modified pointer p.
You have to delete the pointer that you got from new. However, in your second code you did p++ which changed the pointer. Therefore you tried to delete a pointer you didn't get from new and delete crashes.
To fix this type of error never use new. Instead use std::vector<int> p;. Since you never need new you cannot forget a delete.
Problem is changing p in p++.
You should always store (to delete) original pointer. Like this:
#include <iostream>
int main()
{
int *original = new int[5];
int *p = original;
for (int i = 0; i < 5; i++)
{
std::cout << *p << " ";
int x = *p;
p++;
*p = x + 1;
}
std::cout << std::endl;
delete [] original;
return 0;
}

Program not exiting because of delete[]

So my program executes as expected and prints out the correct result. The only issue is that after it is done it does not exit. If I wait a few more seconds windows pops up an error message saying "bignumbs.exe has stopped working". Here is the code to the new function which seems to be causing the problem.
void BigInt::u_basic_mult(const BigInt& n, int digs)
{
const base_int* tptr = n.used > used ? n.data : data;
const base_int* bptr = tptr == data ? n.data : data;
const int tlen = tptr == data ? used : n.used;
const int blen = bptr == data ? used : n.used;
if(digs < 1)
digs = tlen + blen + 1;
base_int* new_data = new base_int[digs];
for(int i = 0; i < digs; ++i)
*new_data++ = 0;
for(int i = 0; i < blen; ++i)
{
int stop_pt = MIN(tlen, digs - i);
overflow_int carry = 0;
overflow_int btmp = bptr[i];
for(int j = 0; j < stop_pt; ++j)
{
overflow_int prod = btmp * tptr[j] + carry;
carry = prod >> BASE_BITS;
overflow_int sum = new_data[i + j] + carry + (prod & MAX_DIG);
carry += sum >> BASE_BITS;
new_data[i + j] = sum;
}
}
//delete[] data; these two lines cause the error
//data = new_data;
used = digs;
alloc = digs;
strip_zeros();
}
Notice the two lines I commented out. Without them the program executes and finishes (although now the result is incorrect). What is it about changing the value of a pointer or deleting it which could make my program have this strange error? Also I am pretty sure data is valid since I use it in the code above.
Also I am compiling with G++ through Netbeans.
After inspecting further it seems that the problem may be with my deconstructor. If I comment out the delete[] data in the deconstructor the error seems to go away. I don't know why.
BigInt::~BigInt()
{
if(data) delete[] data;
}
for(int i = 0; i < digs; ++i)
*new_data++ = 0;
This code is modifying where the new_data pointer is pointing at, so that it is no longer pointing at the original array when you enter the subsequent loop, or do anything with it for that matter. The pointer you pass to delete[] must be pointing at the same memory address that new[] returned.
The correct way to zero-initialize the array is to do this instead:
for(int i = 0; i < digs; ++i)
new_data[i] = 0;
Or, get rid of the loop and just use memset() instead:
memset(new_data, 0, digs * sizeof(base_int));
You must be very careful about matching up uses of new and delete. If you allocate something using the array form of new, you must delete it using the array form of delete. If you mix-and-match the array and non-array forms, you'll get crashes like this. You also must never delete something that wasn't allocated with new, and you must never delete the same thing twice.
I can't give you any more specific advice about this particular program, because you do not show us where the pointer named data is allocated.
I got it. I managed to screw up my new_data pointer.
for(int i = 0; i < digs; ++i)
*new_data++ = 0;
I changed it to this.
for(int i = 0; i < digs; ++i)
new_data[i] = 0;

Dynamic array of pointers to struct throws SIGSEGV on member variable assignment

I'm quite sure this a simple issue, but I am trying to create a data structure that implements a dynamic array of structs.
Each struct will implement a linked list.
So I think that I want an array of pointers, which will point to the head of each list. For some reason, assigning method variables gives me a seg fault. I would love a little explanation of what I am doing wrong if you could. THANKS!
Oh, also, all of this is inside a class called Cache, so that is why there are some variables that don't appear to be defined, but I assure you they are. The program seg faults on indexes[i]->next = NULL; and the similar lines below that one.
typedef struct setNode {
char valid, dirty;
unsigned int tag;
setNode *next;
Cache *nextCache;
} set;
set **indexes;
arrayLength = cache_size / block_size;
indexes = new setNode *[arrayLength];
set *temp;
//Step through the array. The array is full of pointers to "Dummy Nodes"
for (size_t i = 0; i < arrayLength; i++) {
indexes[i]->next = NULL;
indexes[i]->valid = 0;
indexes[i]->dirty = 0;
indexes[i]->tag = 0;
//create empty linked list for each tag spot (One for direct mapped. etc...)
for(size_t i = 0; i < associativity; i++)
{
temp = indexes[i];
temp->next = new setNode;
temp = temp->next;
temp->next = NULL;
temp->valid = 0;
temp->dirty = 0;
temp->tag = 0;
}
}
}
indexes is an array of pointers to set objects, but they are uninitialized. They don't point to actual set objects, but merely to random memory locations. Trying to write to random memory is the very essence of the segmentation violation.
Before using your pointers, you need to allocate set objects and make the pointers point to them -- i.e.,
for (size_t i = 0; i < arrayLength; i++) {
indexes[i] = new set;
indexes[i]->next = NULL;
indexes[i]->valid = 0;
...

strange behavior with stl containers and pointers

I don't understand why the following does not work:
queue<int*> q;
int counter = 1;
for (int i = 0; i < 3; i++) {
int a[1] = {counter};
q.push(a);
counter++;
}
while (!q.empty()) {
int *top = q.front();
q.pop();
cout << top[0] << endl;
}
It should print out: 1 2 3, but instead 3 3 3 is printed out. This is because the pointers in the queue are all the same after each run through the loop. Why does that happen?
You are storing pointers to local variables and using those pointers after the local variables they point to have gone out of scope.
In other words: you are invoking Undefined Behavior.
Result: It should not print out "1 2 3". It doesn't have to do anything and is allowed to do whatever it likes. "3 3 3" seems reasonable to me, as it is also allowed to crash.
int a[1] = {counter};
q.push(a);
Not correct. It invokes undefined behvaiour, as a doesn't exist outside the curly braces (the for-loop block). Even if it were well-defined, your code has another problem, all the items in queue is same, as a (the same memory) gets used repeatedly in the loop.
The solution is this:
int *a = new int[1];
a[0] = counter;
q.push(a);
If you do so, then you've to deallocate the memory yourself, of course.
But I'm wondering if every item in queue is just one int,then why not use the following:
queue<int> q;
for (int i = 0; i < 3; i++)
{
q.push(counter);
counter++;
}
Or if you really want array, then why not use std::queue<std::vector<int> > as :
std::queue<std::vector<int> > q;
for (int i = 0; i < 3; i++)
{
std::vector<int> v;
v.push_back(counter);
q.push(v); //dont worry - a copy of the vector is being pushed!
counter++;
}
In this way, you don't have to deal with raw pointers. You don't have to allocate or deallocate memory yourself which in my opinion is a safe approach!
You have undefined behavior, since your declaration of a goes out of scope at the end of the loop where you're pushing it into the queue.
What's probably happening is that the memory location of a gets reused each time through, but there are absolutely no guarantees. You might get a different output next time you run it, or you might get a crash, or demons may fly out of your nostrils.
If you insist on using pointers to integers, the following code does what you want:
#include <queue>
#include <iostream>
int main()
{
std::queue<int*> q;
int counter = 1;
for (int i = 0; i < 3; i++) {
int* a = new int;
*a = counter;
q.push(a);
counter++;
}
while (!q.empty()) {
int *top = q.front();
q.pop();
std::cout << *top << std::endl;
delete top;
}
return 0;
}