Updating map values in c++ - c++

Newb question here:
how can I have the value stored in Maptest[2] update along with the variable?
I thought you could do it with pointers, but this doesn't work:
map<int, int*> MapTest; //create a map
int x = 7;
//this part gives an error:
//"Indirection requires pointer operand ("int" invalid)"
MapTest[2] = *x;
cout << MapTest[2]<<endl; //should print out 7...
x = 10;
cout <<MapTest[2]<<endl; //should print out 10...
What am I doing wrong?

You need the address of x. Your current code is attempting to dereference an integer.
MapTest[2] = &x;
You then need to dereference what MapTest[2] returns.
cout << *MapTest[2]<<endl;

Try this instead:
MapTest[2] = &x;
You want the address of x to store in the int*. Not the dereference of x, which would be what ever is at the memory location 0x7, which is not going to be valid.

There are at least 2 problems here:
int x = 7;
*x; // dereferences a pointer and x is not a pointer.
m[2] = x; // tries to assign an int value to a pointer-to-int value
// right
m[2] = &x; // & returns the address of a value
Now you have a new problem. x has automatic lifetime, it will be
destroyed at the end of its surrounding scope. You need to allocate it
from the free store (a.k.a. the heap).
int* x = new int(7);
m[2] = x; // works assigns pointer-to-int value to a pointer-to-int value
Now you have to remember to delete every element in the map before
it goes out of scope or you will leak memory.
It is smarter to store values in a map, or if you really need to
store pointers to store a suitable smart pointer (shared_ptr or
unique_ptr).
For the printing:
m[2]; // returns pointer value
*m[2]; // dereferences said pointer value and gives you the value that is being pointed to

Related

Variable referencing and how pointers interact with memory

When a variable is created such as:
int x = 5;
it will be stored somewhere in memory, cool.
However when I change the value of the variable by doing the following:
x = 10;
What happens in memory?
Does the new value of x overwrite the old value using the same memory address?
or is it that the new value is stored in a new memory address and then the old address is deleted?
This question arose when I came across pointers. It seems that using pointers to change the value of a variable is the same as defining the variable with another value.
this is my code (most of it are comments (lol)):
#include "iostream"
int main()
{
int x = 5; // declaring and defining x to be 5
int *xPointer = &x; // declare and define xPointer as a pointer to store the reference of x
printf("%d\n",x); // print the value of x
printf("%p\n",xPointer); // print the reference of x
x = 10; //changing value of x
printf("%d\n",x); //print new value of x
printf("%p\n",xPointer); //print the reference of x to see if it changed when the value of x changed
*xPointer = 15; //changing the value of x using a pointer
printf("%d\n",x); //print new value of x
printf("%p\n",xPointer); //print reference of x to see if it changed
return 0;
}
this is the output:
5
00AFF9C0
10
00AFF9C0
15
00AFF9C0
As you can see the memory addresses are the same, hence what is the point of pointers (pun intended).
When you declare int x = 5; you are saying that x has automatic storage duration and is initialised with the value 5.
For the lifetime of x, a pointer to x (i.e. &x) will have the same value.
You can change the value of x with the assignment x = 10 or via a pointer dereference *xPointer = 15 having set int* xPointer = &x;.
The language standard mentions nothing about the pointer value being a memory address, although it might be. That's a common misconception as to how the language works.
(Indeed a new value of x might cause the location in memory to change. That's permitted by the language so long as the pointer value doesn't change. An operating system may well do something similar to this, in the interests of obviating memory defragmentation.)

Modify the location a pointer points to in a C++ function

I have gotten stuck on modifying pointers of pointers. The problem is that I don't understand why my code works. What I am trying to do is modify where a pointer-to-pointer points to in a function. Then accessing that value in my main function. I tried quite a few attempts and this is the only way I got it to work.
#include <iostream>
using namespace std;
void changePP(int **ppint) {
int *n = new int;
*n = 9; //just a value for demonstration purposes
*ppint = n; //THE LINE IN QUESTION
delete n;
}
int main() {
int **ppint = NULL;
int *p = new int;
*p = 4; //another value for demonstrating
ppint = &p;
cout << **ppint << endl;
changePP(ppint);
cout << **ppint << endl;
}
So, the output is 4 and then a 9 on seperate lines. However, I am not sure about the line *ppint = n in the code. Why do I have to use the * to change where ppint points to in the changePP function but not in the main? Also why do I not have to use the & in the function? I can't seem to find an explanation that I can understand on the internet and I was wondering if someone could explain this for me?
Note: these memory addresses are only for illustration.
Memory Layout
0x0A | 4
0x0B | 'p' -> 0x0A // Pointer to the value 4 in location 0x0A
0x0C | 'ppint' -> NULL // Initially a null pointer
Performing ppint = &p; produces the following because here ppint is the pointer located at 0x0C.
0x0A | 4
0x0B | 'p' -> 0x0A
0x0C | 'ppint' -> 0x0B
As for the parameter in the changePP function, I will refer to it as ppintCopy for less confusion. It's a copy (i.e., a pointer different than ppint) and modifying it only modifies the copy.
0x0D | 'ppintCopy' -> 0x0C // A pointer that points to `ppint`
Performing ppintCopy = &n would modify the pointer at 0x0D which is not the location of the pointer from the main function. However, deferencing ppintCopy (i.e., *ppintCopy) yields 0X0C which is the pointer from the main function therefore *ppintCopy = n; is changing where the pointer 0x0C points.
Why do I have to use the * to change where ppint points to in the changePP function but not in the main?
With the above illustration I hope it is more clear why it works in main and why you have to use a different syntax in the changePP function.
Also why do I not have to use the & in the function?
In the main function the variable ppint is of type int** (i.e., a pointer to a pointer) and p is of type int*. You cannot perform ppint = p; because the they are different types. This may be easier to see if you remove one level of indirection. For example:
int* pMyInt = NULL;
int myInt = 3;
I think it's pretty self explanatory that this cannot work (i.e., they are different types).
pMyInt = myInt;
However you can take the address of myInt using the & operator which results in a pointer to int (i.e., int*) and since this type is the same as the type of pMyInt the assignment is now possible.
pMyInt = &myInt;
ppint; // the variable name
*ppint; // dereference the first layer of pointer
*(*ppint); // dereference the first layer of pointer which points to another pointer that contains a **value**
Thus *ppint = n; means point ppint to another memory location which is the location assigned to n or it could be rewritten as *ppint = &n;
After that line, you have deleted the n but you didn't change its value so the value remains unchanged unless something have accessed and modified it.
The reason why you still retain the value of n after deleting it is considered as undefined behaviour though.
Pointers are already messy to deal with, you didn't have to make it worse. This works as well:
#include <iostream>
using namespace std;
void changePP(int *ppint) {
*ppint = 9;
}
int main() {
int p = 4;
int *ppint = &p;
cout << *ppint << endl; // this could be replaced with /*p*/
changePP(ppint); // note you could have replaced this parameter with /*&p*/
cout << *ppint << endl; // this could be replaced with /*p*/
}
Let me try to explain what your code is doing, but please for future, don't ever do it this way. Do it the way I've shown
#include <iostream>
using namespace std;
void changePP(int **ppint) {
int *n = new int; // you allocate memory for a single integer (again it is uninitialised)
*n = 9; // the value at the above pointer is now changed to 9
*ppint = n; // here you have just dereferenced a pointer to pointer which gives you a pointer, so in essence you are changing the location in memory where this pointer is pointing and it is now pointing to whatever memory address n was
delete n;
}
int main() {
int **ppint = NULL; // Here you have declared a pointer to pointer which is NULL
int *p = new int; // You can do better here with /*new int(4)*/
*p = 4; // this changes the value that p initially held (which could be anything)
ppint = &p; // reference to a pointer always creates a pointer to a pointer and since that is what ppint is, you are safe here
cout << **ppint << endl; // print the value nested within this pointer
changePP(ppint); // now you call the function with a variable of type pointer to pointer. Note you could have passed &p as parameter here and it would have still worked
cout << **ppint << endl;
}
What is the moral of the story?
When passing a parameter v to a function,
&v will produce a pointer to v
*v will dereference v and will give you access to whatever v was pointing to
When v is a parameter in a function,
&v will bring the actual object v into the scope of the function. This is called pass by reference
*v Is a pointer to v, and this is still pass by reference called pass by value because you are passing a pointer(Thanks Kirk)

De-allocating memory within loops

I was reading through MIT's Introduction to C++ and one code example showed:
int *getPtrToFive() {
int *x = new int;
*x = 5;
return x;
}
int main() {
int *p;
for (int i = 0; i < 3; ++i) {
p = getPtrToFive();
cout << *p << endl;
delete p;
}
}
I was wondering why it is possible to delete "p" after every iteration despite "p" being declared once before the loop started and was not allocated using "new".
Another question is when "*x" is assigned the value 5 in the function, since it is a pointer the memory address would be changed right? So it would be something like 0x00005 instead of the actual value 5?
I was wondering why it is possible to delete "p" after every iteration despite "p" being declared once before the loop started and was not allocated using "new"
No. You are not deleting p, you are deleting the object p points to, which is allocated using new each iteration.
Another question is when "*x" is assigned the value 5 in the function, since it is a pointer the memory address would be changed right? So it would be something like 0x00005 instead of the actual value 5?
The value of x would be something like 0xFFd00whatever. but you are printing the value of *x, which is "the number that is in the memory at address 0xFFd00whatever". There is no x=5 in your code; there's only *x=5. It means "go to the address to which x points to, and put the number 5 in there".
You can think about it this way: you have a hand, okay? let's call it "x". The command
x = new int;
Means "point your finger at some empty place on your desk." Where
*x = 5;
Means "draw the number five where your hand points to".
p is simply a variable of the type int* (pointer to int). Its value is an address. When you assign a new value to it then it points to a new object. delete expects an address; that's all it needs to deallocate the memory you allocated.
The variable used to store said address is irrelevant. It's value has changed, and that's all delete cares about; the value.

Operator precedence and pointer arithmetic

Given the following code:
void Allocate(int *p)
{
p = new int;
*p++ = 2;
}
int main()
{
int i = 10;
Allocate(&i);
std::cout << i << std::endl;
}
I'm a bit confised about the meaning of:
*p++ = 2;
The output is 10 and my reasoning as to why this is the case is that *p++ is a temporary therefore any assignment to it is lost at the end of the scope of Allocate(int *p).
Is this the case?
Thanks in adv!
On input to Allocate, p points to the variable i in the main
function.
The address of this variable then lost and replaced by the
new int.
The value of this int (which is uninitialized and so could
start as anything) is set to 2.
The p pointer is incremented.
The Allocate function returns at this point, leaking the int that was
allocated.
The value of i in the main function is unchanged,
because Allocate did not modify it.
when you pass the the address of i into Allocate, another (temp) pointer is created that points to i's address (i.e. passing by pointer). then that temp pointer is pointed to a new location (via new int). thus the value of i is left alone.
p = new int;
You're assigning p new memory to point to instead of what it was pointing to before. You then change this newly allocated memory and it's lost forever when the function ends, causing a memory leak. If you remove the allocation line, it should cause an output of 2. The ++ does nothing in this case. It just increments the pointer and returns the old value to dereference.
As soon as you enter Allocate, you assign p to point to a new block of memory, so it no longer points to i. Then you modify that new block of memory (which is then leaked when the method returns.) i is unaffected because you've moved that pointer before you set the pointed-to memory cell.
void Allocate(int **p)
{
*p = new int;
**p = 2;
}
int main()
{
int j = 10;
int *i = &j;
std::cout << i << std::endl;
Allocate(&i);
std::cout << i << std::endl;
}
Output is :
10
2
You need a pointer to pointer to change the address of the location being pointed to.

Pointers problem

I have a question.
I created a correctly initialized integer pointer
int * p
and a correctly initialized integer array
int * array1 = new int[]
Which of the following is legal code?
p = array1;
array1 = p;
Or are both correct?
is this possible as well
p[0] since, to my pointer arithmetic knowledge, it doesn't add anything.
All in c++
If the question is trying to get at pointers versus arrays, they are not always compatible. This is hidden in the presented code because the array is immediately converted to a pointer.
int* array1 = new int[5]; // Legal, initialising pointer with heap allocated array
int array2[5] = {0}; // Declaring array directly on the stack and initalising with zeros
int *p = 0; // Declaring pointer and initialising to numm
p = array2; // Legal, assigning array to pointer
p = array1; // Legal, assigning pointer to pointer
array1 = p; // Legal, assigning pointer to pointer
array2 = p; // ILLEGAL, assigning pointer to array
Here array2 has an array type and cannot be used to store a pointer. Actually, the array cannot be reassigned at all, as it is not an l-value.
int array3[5] = {0}; // Declaring array directly on the stack and initalising with zeroes
array3 = array2; // ILLEGAL, array not an l-value
The array has a fixed address and reassiging it would be similar to trying to write:
int i = 0;
&i = p;
[Hopefully, trying to reassign the location of a variable is obvious nonsense.]
Both are legal.
The first, "p = array1", will cause your correctly initialized integer pointer to be leaked and to point p to the first occurrence of the array that array1 points to.
The second, "array1 = p", will cause the correctly initialized integer array to to be leaked and to point array1 to the single int that p points to.
So I suspect I'm missing something. Could you perhaps post complete code?
If both p and array1 are declared as "int *", as you imply here, then either assignment is legal, by definition.
both are leagal.
passing adresses to eachother. dont knw what u want to do
According to the explanation provided in this site. The first assigned in is correct but the second assignment cannot be considered valid. Please look under the title 'Pointers and arrays'.
You can assign your array variable to pointer variable. So p = array1 is correct.
You can refer this code.
#include <iostream>
using namespace std;
int main ()
{
int numbers[5];
int * p;
p = numbers; *p = 10;
p++; *p = 20;
p = &numbers[2]; *p = 30;
p = numbers + 3; *p = 40;
p = numbers; *(p+4) = 50;
for (int n=0; n<5; n++)
cout << numbers[n] << ", ";
for (int n=0; n<5; n++)
cout << p[n] << ", ";
return 0;
}
If both are pointers then no need to declare pointer as array like int *array1 = new int[].
Both variables are of type pointer to int. So both assignments are legal. The fact that one of the variables is an array doesn't matter in C. Arrays and pointers are the same after initialization.
"I created a correctly initialized integer pointer int * p and a correctly initialized integer array int * array1 = new int[]"
First of all, keeping the syntactical mistakes aside, the terminology is wrong.
int *p; - Here you are just declaring a pointer to hold an integer variable's address. You are not initializing it. Declaration is different from initialization and initialization is different from assignment.
int *array1 = new int[]; - Keeping the error aside, this is not an initialized integer array. array1 is a pointer pointing to an array of integers.
And passing nothing to [] is incorrect. A value needs to be passed that decides number of memory locations to be allocated for holding integer values.
Answering the questions.
Which of the following is legal code?
p = array1;
If, array1 is properly initialized it's correct. p points to the first integer in the array1. Even if it is not properly initialized also, it is correct. In this case, both array and p points to garbage values.
int* array1 = new int[5]; // Notice **5** being passed.
array1 = p;
Infact this operation is useless. Both p and array1 were both pointing to the same location earlier. But this is legally correct.
is this possible as well p[0] ?
Yes, it's correct. p can dereference to 0 to 4 as it's index values. If you just want to p[0], in that case -
int* array1 = new int ; // Notice nothing being passed.