pointer dereference: actual mechanism of compiler - c++

I'm struggling a little bit with my understanding concerning the actual mechanism in dereferencing pointers (what the compiler actually does).
I red a lot through google and on here on stackoverflow, but I coulnd't quite get it yet :-(
I wrote a simple program with multiple pointers:
#include <iostream>
int main()
{
int a = 5;
int* ptr = &a;
int** pptr = &ptr;
int*** ppptr = &pptr;
int**** p4tr = &ppptr;
std::cout << "a = 5 \nint*ptr = &a \nint** pptr = *ptr\nint*** ppptr = &pptr\nint**** p4tr= &ppptr\n" << std::endl;
std::cout << "a: " << a << std::endl;
std::cout << "&a: " << &a << std::endl << std::endl;
std::cout << "ptr: " << ptr << std::endl;
std::cout << "*ptr: " << *ptr << std::endl;
std::cout << "&ptr: " << &ptr << std::endl << std::endl;
std::cout << "pptr: " << pptr << std::endl;
std::cout << "*ptr: " << *pptr << std::endl;
std::cout << "**pptr: "<< **pptr << std::endl;
std::cout << "&pptr: " << &pptr << std::endl << std::endl;
std::cout << "ppptr: " << ppptr << std::endl;
std::cout << "*ppptr: " << *ppptr << std::endl;
std::cout << "**pptr: " << **ppptr << std::endl;
std::cout << "***pptr: " << ***ppptr << std::endl;
std::cout<< "&pptr: " << &ppptr << std::endl << std::endl;
std::cout << "p4tr: " << p4tr<< std::endl;
std::cout << "*p4tr: " << *p4tr<< std::endl;
std::cout << "**p4tr: " << **p4tr<< std::endl;
std::cout << "***p4tr: " << ***p4tr<< std::endl;
std::cout << "****p4tr: " << ****p4tr<< std::endl;
std::cout << "&p4tr: " << &p4tr<< std::endl << std::endl;
return 0;
}
Which gives me this on my machine:
a = 5
int*ptr = &a
int** pptr = *ptr
int*** ppptr = &pptr
int**** p4tr= &ppptr
a: 5
&a: 0x7fffe4db870c
ptr: 0x7fffe4db870c
*ptr: 5
&ptr: 0x7fffe4db8700
pptr: 0x7fffe4db8700
*ptr: 0x7fffe4db870c
**pptr: 5
&pptr: 0x7fffe4db86f8
ppptr: 0x7fffe4db86f8
*ppptr: 0x7fffe4db8700
**pptr: 0x7fffe4db870c
***pptr: 5
&pptr: 0x7fffe4db86f0
p4tr: 0x7fffe4db86f0
*p4tr: 0x7fffe4db86f8
**p4tr: 0x7fffe4db8700
***p4tr: 0x7fffe4db870c
****p4tr: 5
&p4tr: 0x7fffe4db86e8
What I figured out, how dereference works is:
int* ptr = &a; tells the compiler that the "variable" ptr is of type "int*" (pointer to an interger; i.e. memory address)
Hence, when I write *ptr, the compiler takes the value of ptr, takes it as an address and interpretes what is stored at the very address as type int.
So far, so good.
But what does int** pptr = &ptr actually mean to the compiler ?
Does it mean pptr is of type " int** " ?
or does it still mean pptr is of type " int* " (i mean, &ptr is as good a memory address as &a)
What does the second asterix actually mean to the compiler and why can't I write: "int* pptr = &ptr"
(at least g++ won't let me do that)
thank you so much for your efforts,
it hurts my brain, if things seem unlogical to me :-))

But what does int** pptr = &ptr actually mean to the compiler? Does it mean pptr is of type int**?
Yes, pptr is of type int**. And int** is pointer to pointer to int. So *pptr has type int*, and **pptr has type int.
Why can't I write: int* pptr = &ptr?
Well, ptr has type int*. And so &ptr has type int** which is not assignment compatible with a variable of type int*. A pointer to int is a different type of thing to a pointer to pointer to int.

Related

strange problem in a c++ program with pointers

I wrote this simple c++ program and I got some strange results that I don't understand (results are described in the line comments)
int arr[3] {1, 2, 3};
int* p{ nullptr };
p = arr;
std::cout << p[0] << " " << p[1] << " " << p[2]; // prints 1 2 3, OK
p = arr;
std::cout << *(p++) << " " << *(p++) << " " << *(p); // prints 2 1 3 ??
p = arr;
std::cout << *p << " " << *(++p) << " " << *(++p); // prints 3 3 3 ??
p = arr;
std::cout << *p << " "; ++p;
std::cout << *p << " "; ++p;
std::cout << *p; // prints 1 2 3, OK
it seems that the pointer increments along a std::cout concatenation don't work.
What's wrong in my idea?
I supposed it should have worked.
best
final edit: I was using c++14, I switched to c++20 and now it works properly
thank you everybody!
int* p{ nullptr };
std::cout << p[0] << " " << p[1] << " " << p[2];
This is Undefined Behavior, as you are dereferencing nullptr, p does not point at valid memory yet.
p = arr;
std::cout << p[0] << " " << p[1] << " " << p[2];
This is well-defined behavior. p points at valid memory, is always incremented before dereferenced, and is incremented in a deterministic and valid manner. This is the same as if you had written the following instead:
std::cout << *(p+0) << " " << *(p+1) << " " << *(p+2);
p = arr;
std::cout << *(p++) << " " << *(p++) << " " << *(p);
p = arr;
std::cout << *p << " " << *(++p) << " " << *(++p);
Both of these are Undefined Behavior prior to C++17, because the order in which chained operator<< calls are evaluated is not guaranteed in earlier versions, the compiler is free to evaluate them in whatever order it wants. This is no longer the case in C++17 onward.
p = arr;
std::cout << *p << " "; ++p;
std::cout << *p << " "; ++p;
std::cout << *p;
This is well-defined behavior. p points at valid memory, is always dereferenced before incremented, and is incremented in a deterministic and valid manner.

Pointers and references in functions

I have a problem with a school homework. I have to write a few function, and I have problem with the ShiftPointerVal which argument is a pointer to int. This is the most important in that homework, I mean that argument. I have that issue: error: lvalue required as left operand of assignment. Target of this function is to make a pointer bigger by one. I don't know how to write this function so the pointer to int can be an argument.
void ShiftPointerVal (int& pointer)
{
&pointer = &pointer + 1;
}
void ShiftPointerRef (int *&pointer)
{
pointer = pointer + 1;
}
void ShiftPointerPointer (int **pointer)
{
*pointer = *pointer +1;
}
int main ()
{
int number = 5;
int* p_number = &number;
std::cout << "\n----- 4 -----\n";
std::cout << &number << "\t" << p_number << "\n";
std::cout << *p_number << "\n";
ShiftPointerVal (p_number);
std::cout << &number << "\t" << p_number << "\n";
std::cout << *p_number << "\n";
std::cout << "\n----- 5 -----\n";
std::cout << &number << "\t" << p_number << "\n";
std::cout << *p_number << "\n";
ShiftPointerRef (*&p_number);
std::cout << &number << "\t" << p_number << "\n";
std::cout << *p_number << "\n";
std::cout << "\n----- 6 -----\n";
std::cout << &number << "\t" << p_number << "\n";
std::cout << *p_number << "\n";
ShiftPointerPointer (&p_number);
std::cout << &number << "\t" << p_number << "\n";
std::cout << *p_number << "\n";
}

Explain C++ pointer initialization

int value = 3;
int *pValue1 = &value;
int *pValue2(pValue1);
cout << (*pValue1) << " " << (*pValue2);
In the above code if you have noticed I have written
int *pValue2(pValue1);
instead of
int *pValue2 = new int;
pValue2 = pValue1;
Still it is working and giving proper result.
Can any one explain to me which of the default function or constructor is getting called in this case?
int *pValue2(pValue1);
is equivalent to
int* pValue2 = pValue1;
Just assign to pValue2 pValue1 (assign to pValue2 address of variable value).
The difference should be apparent if you print the pointers themselves (the addresses) in addition to the values which they reference:
#include <iostream>
using namespace std;
int main() {
int value = 3;
int *pValue1 = &value;
int *pValue2(pValue1);
int *pValue3 = new int;
cout << pValue1 << " " << pValue2 << " " << pValue3 << endl;
cout << *pValue1 << " " << *pValue2 << " " << *pValue3 << endl;
pValue3 = pValue1;
cout << pValue1 << " " << pValue2 << " " << pValue3 << endl;
cout << *pValue1 << " " << *pValue2 << " " << *pValue3 << endl;
return 0;
}
You will also see that after new int, the memory pointed to by the pointer contains uninitialized data.

Displaying the Address of Chars

So we have an assignment in my C++ class to create a pointer to a char and the instructions are:
For each declaration make sure to:
Initialize the pointer to an appropriate address value
Show the contents of the pointer (match this value with the address of what is pointing to)
Show the contents of what the pointer points to (match this value with the original contents)
Whenever I try to display the address of char a with &a , it just outputs the value stored in char a rather than the address. When I try this with integers it works like I want it to.
Can anybody give me an idea as to what I'm doing wrong?
#include <iostream>
using namespace std;
int main()
{
// Question 1, Part I
// (a)
char a = 'A';
char * pa = &a;
//(b)
cout << "Address of a = " << &a << endl;
cout << "Contents of pa = " << pa << endl;
//(c)
cout << "Contents of a = "<< a << endl;
cout << "What pa points to = "<< *pa << endl;
return 0;
}
Edit & Run
When you give a pointer to char to cout, it will consider it as a null terminated c string.
Recast it to a void pointer:
cout << "Address of a = " << static_cast<void*>(&a) << endl;
The standard guarantees that the adress is unchanged in section 4.10/2:
A prvalue of type “pointer to cv T,” where T is an object type, can be
converted to a prvalue of type “pointer to cv void”. The result of
converting a non-null pointer value of a pointer to object type to a
“pointer to cv void” represents the address of the same byte in memory
as the original pointer value.
Here an explanation about pointer to char in output streams. And here an explanation why void* causes the value of the pointer to be displayed.
Change these statements
cout << "Address of a = " << &a << endl;
cout << "Contents of pa = " << pa << endl;
to
cout << "Address of a = " << ( void * )&a << endl;
cout << "Contents of pa = " << ( void * )pa << endl;
or
cout << "Address of a = " << reinterpret_cast<void *>( &a ) << endl;
cout << "Contents of pa = " << reinterpret_cast<void *>( pa ) << endl;
or
cout << "Address of a = " << static_cast<void *>( &a ) << endl;
cout << "Contents of pa = " << static_cast<void *>( pa ) << endl;
All three variants will work.

C++ strcpy pointers that are passed to a function

I am passing an string or a char array to a function and swapping them but losing the first char array's value for some reason. Here is my code:
void foo(char* a, char* b){
char* temp;
temp = new char[strlen(a)+1];
strcpy(temp, a);
strcpy(a, b);
strcpy(b, temp);
delete[] temp;
}
So in foo the function gets passed two pointers and the are attempted to be swapped.
Here is the main function. There may be a problem with the passing of the variable, but the compiler did not give me an issue.
int main(){
char a[] = "First";
char b[] = "Last";
std::cout << "A Before: "<< a << "\n";
std::cout << "B Before: " << b << "\n\n";
foo(a, b);
std::cout << "A After: "<< a << "\n";
std::cout << "B After: "<< b << "\n\n";
return 0;
}
The output I am getting is as follows:
A Before: first
B Before: last
A After:
B After: first
Now I have tested the values of the strings while in the function during the strcpy's and turns empty after the final strcpy, which means, or at lest I think, that the problem lies within the pointers to the original variables. It could be a chain reaction type of thing where all of the pointers are pointing to the "a" and it confuses the program.
Any help would be appreciated, also why this is happening would be very useful as well.
Because your string a is longer than b.So strcpy does not work as you expect in line:
strcpy(b, temp);
Tips:
Use strncpy instead of strcpy
Use c++ Strings instead of the c style string.Then you can swap
them with a.swap(b);
The problem is your array sizes happen to be such that you are clobbering your stack; fortunately, for you, the effect is simply to place a null byte in the first character of a, making it an empty string.
#include <iostream>
#include <string.h>
void foo(char* a, char* b){
char* temp = new char[strlen(a)+1];
strcpy(temp, a);
std::cout << "temp = " << temp << " a = " << a << " b = " << b << std::endl;
strcpy(a, b);
std::cout << "temp = " << temp << " a = " << a << " b = " << b << std::endl;
strcpy(b, temp); // this copies 6 bytes to b, which puts a 0 in the first byte of a.
std::cout << "temp = " << temp << " a = " << a << " b = " << b << std::endl;
delete[] temp;
}
int main() {
char a[] = "First";
char b[] = "Last";
std::cout << "a size is " << sizeof(a) << std::endl;
std::cout << "b size is " << sizeof(b) << std::endl;
std::cout << "address of a[0] is " << (void*)&a[0] << std::endl;
std::cout << "address of b[0] is " << (void*)&b[0] << std::endl;
foo(a, b);
std::cout << "A After: "<< a << "\n";
std::cout << "B After: "<< b << "\n\n";
}
http://ideone.com/fDvnnH
a size is 6
b size is 5
address of a[0] is 0xbfec5caa
address of b[0] is 0xbfec5ca5
temp = First a = First b = Last
temp = First a = Last b = Last
temp = First a = b = First
A After:
B After: First
You might want to investigate std::string or look at using std::strncpy