I am getting started with C++. I wanted to understand the different
outputs while playing around with this snippet of code.
int main()
{
int i = 3;
int *ptr = &i; //stores address of the i
while(*(ptr)--) //the same as i--
{
cout << *ptr << endl;
}
}
When I run this code I understand that the deferenced value
of ptr, which is "i", gets 1 subtracted from it and the loop exits
when "i" equals 0. But when I use while(*ptr--) instead of while(*(ptr)--) I get a list of random integers which eventually go down to 0 and the loop breaks.
To my understanding when I use *ptr-- I am subtracting a byte(size of one int) from the initial address of &i(*ptr) with each loop. But why does the program terminate eventually? No matter what the value of "i" is, the program prints 23 random numbers with the last one being 0 and the loop exits. Should I not get an overflow error since the program runs out of memory?
However, when I use while(ptr--) the program does go into an infinite loop.
What exactly is happening?
Thank you very much.
(ptr) is the same as ptr, thus (ptr)-- is the same as ptr--.
*ptr-- IS NOT the same as i-- !
You are applying operator-- to the right side of the pointer. The suffix/postfix operator-- has a higher precedence than operator*. So, *ptr-- is the same as *(ptr--), not (*ptr)-- like you are expecting.
IOW, ptr-- gets evaluated first, which returns a copy of the current pointer and then decrements the pointer, and then you are dereferencing the copied pointer to retrieve the value that was previously being pointing at.
That is why you are seeing garbage - you are decrementing the pointer into memory that does not belong to you.
To simply decrement the int and not the pointer, use (*ptr)-- instead. IOW, dereference the pointer first, then decrement the value being pointed at, eg:
int main()
{
int i = 3;
int *ptr = &i; //stores address of the i
while((*ptr)--) //the same as i--
{
cout << *ptr << endl;
}
}
Live demo
Parenthesis and operator precedence matter!
Related
An array is right now pointed by a single pointer. And a double pointer is pointing to the single pointer. I am trying to fetch the value of the array using this double pointer. As far I have only fetched the first index value of the array by the double pointer.
I know that if I dereference (*ptr2) a double pointer then it will give the address where the first pointer is pointed (ptr1) which means the first index address of the array(&array[0]).
#include <iostream>
using namespace std;
int main(){
int array[5]{15,25,35,45,55};
int* ptr1;
int** ptr2;
ptr1 = &array[0];
ptr2 = &ptr1;
In the following for loop, I have tried to print the value of array using pointer ptr1.
for(int i =0; i<5; i++){
cout<<"the value: "<<*(ptr1+i)<<" lives at "<<ptr1+i<<" address\n";
}
cout<<"\n";
In the following for loop I have tried to check *ptr2 is all-time giving me address pointed by ptr1 or not. But I have found that it only works/same for the first index then it is (*ptr2) giving me a different address
for(int j=0; j<5; j++){
cout<<"adress of array: "<<&array[j]<<" , ptr1: "<<(ptr1+j)<<" , val of ptr2: "<<*(ptr2+j)<<endl;
}
cout<<"\n";
return 0;
}
While I have tried to fetch the value from ptr2 by using **ptr2+i using a for loop it continues only for 2 times. First-time correct value which is obvious as I am seeing the address of array[0] and *(ptr2+0) are same. Second-time garbage value and then Segmentation fault (core dumped).
One guess came in my mind that ptr1 and ptr2 both are int type but one is pointing to a variable and another is to a pointer. So maybe there is a memory allocation concept arises from the very beginning which I am skipped.
Is there any way where I can fetch the value of the array using the mentioned structure?
ptr2 is pointing at ptr1. (ptr2+j), when j is not 0, is an address you haven't allocated so dereferencing it (*(ptr2+j)) makes your program have undefined behavior and getting a Segmentation fault is one possible outcome.
You should dereference it first, then index: (*ptr2)[j] or *((*ptr2)+j) if you will.
Your reasoning is close, but you did not apply it well.
I know that if I dereference (*ptr2) a double pointer then it will give the address where the first pointer is pointed (ptr1)
In other words, *ptr2 is a synonym for ptr1. So any place you see ptr1 (after assigning ptr2 = &ptr1) you can substitute in *ptr2. Even better, substitute in (*ptr2) to avoid interference from operators with a higher precedence than de-reference. Let's take an example:
for(int i =0; i<5; i++){
cout<<"the value: "<<*(ptr1+i)<<" lives at "<<ptr1+i<<" address\n";
}
cout<<"\n";
Now do a simple find-and-replace. Replace ptr1 with (*ptr2). Don't try to adjust anything; once you've decided to do this, the process is mindless.
for(int i =0; i<5; i++){
cout<<"the value: "<<*((*ptr2)+i)<<" lives at "<<(*ptr2)+i<<" address\n";
}
cout<<"\n";
This is almost what you tried in your loop, except you used *(ptr2+j) instead of (*ptr2)+i. We can ignore the change from i to j, but those parentheses are significant. You changed the order of operations, which is comparable to using 3(1+4) instead of (3×1)+4. It shouldn't be surprising that 15 does not work where 7 is needed, and similarly adding j before de-referencing does not work where the de-reference needs to be done first.
Note: Since de-reference has a higher precedence than addition, the parentheses around *ptr2 could be dropped from this particular example. That is, *ptr2+i and *(*ptr2+i) would also work.
Note: This question can serve as a demonstration of why it's often wise to avoid pointers-to-pointer.
I've been stuck on this problem and I'm hoping someone can explain where I'm wrong on this. I'm working on an assignment where I need to:
1) Allocate an array that can contain 100 int values by calling allocIntArray and assign the returned pointer to ptr1.
2) Use the new operator to allocate an array of integers using the parameter as the size of the array.
3) Return the pointer that is returned by the new operator.
4) Print out the new array.
I'm trying to print out the array after passing the size I want through the function.
int main() {
int *ptr = NULL;
ptr1 = *allocIntArray(100);
cout << ptr1 << endl;
return 0;
}
//The function I want to call
int *allocIntArray(int size) {
int *newarr = nullptr;
newarr = new int[size];
return newarr;
}
However when I call the function, the output comes out as 00F011E8.
I'm currently trying to understand why this is the output and not the first value in the array. (Just the number 1)
I've been having a lot of trouble grasping pointers any help understanding would be greatly appreciated.
Thanks to everyone who took the time to respond.
From what I understand from assignment directions, I shouldn't need to use vectors. I'm trying to modify my current code to display the array output and this is what currently comes up when I run it.[enter image description hereMy current results
At first, if you're using C++, you should use std::vector/std::array. This avoids a huge amount of possible problems.
It would look like:
#include <iostream>
#include <vector>
int main()
{
// create array of size 10 and initialize it with 0's
std::vector<int> vec(10, 0);
// print array
for(auto a : vec)
std::cout << a << '\t';
std::cout << std::endl;
}
If it's some kind of exercise, you have done four big mistakes:
you dereference the returned pointer to the array. So you get the value of the first element in the array and not the array itself. Simply remove the *.
you print out the address of the first element of the array. To print the array, you have to iterate over each element of the array. This can be done in a for loop:
for(int i = 0; i < 10; ++i)
std::cout << ptr1[i] << '\t';
you want to print out the array uninitialized. In fact, you try to print out some random values which are there in the memory. At first, you have to assign the elements values.
you forget to delete the array by using
delete[] ptr1;
I just have to answer as you seem to be missing some important fundamentals. Either the instructor should be dismissed or you have not paid enough attention in the class. So...
ptr1 = *allocIntArray(100);
You could not have pasted code that compiles, ptr1 is not declared.
You need to understand what the * operator does. What ever value to the right of * must be a pointer. What a pointer is should be fundamental in your understanding. If you had:
int* ptr1 = *allocIntArray(100);
You should have gotten a compiler error, so you must have:
int ptr1;
Somewhere along the line. As allocIntArray(...) returns a pointer, then *allocIntArray(...) gives you an integer.
You would have wanted to:
int* ptr1 = allocIntArray(100);
To get a pointer to the new array. Then you:
std::cout << ptr1 << std::endl;
So, what is ptr1? If it is a pointer then all you are doing is printing the pointer value. Per your stated problem, I'd say ptr1 is in fact a pointer. std::cout has not facility to work with a pointer as you expect. At that, it would have no way of determining the size of your array.
You would want to (And it hurts my fingers to write like this):
for(size_t i= 0; i < 100; ++i)
std::cout << ptr1[i] <<" ";
But!!!
4) Print out the new array.
So what will it print? There was never an instruction to initialize the array. It will print out what ever garbage is sitting in the array when it was created.
Side note, that the instructor has you doing a:
using namespace std;
Says much, as he/she should never have allowed it.
I'm playing around with pointers to understand this concept better
and wanted to ask
Why do i get null pointer as return for the second function?
and why it isn't possible to get the address 0x7fff15504044.
What is happening and where inside memory is the integer 5 stored,
when im working with it inside the function?.
#include <iostream>
using namespace std;
int* return_adress(int* input){ return input; }
int* return_adress_from_input(int input){ return &input; }
int main(){
int k = 3;
cout << return_adress(&k) << endl;
cout << return_adress_from_input(k) << endl;
}
Output:
0x7fff15504044
0
With int* return_adress_from_input(int input), input is a value copy of k in the caller. They are two different variables therefore with different addresses.
input goes out of scope conceptually once the closing brace of the function is reached.
The pointer &input then points to memory that you no longer own, and the behaviour of reading that pointer value (let alone dereferencing it) is undefined prior to C++14, and implementation defined from and including C++14.
Because you pass input by value, not by reference. Compiller first creates a local copy of input and then returns address of this local copy. To get the variable address use
int* return_adress_from_input(int& input){ return &input; }
In general, you get undefined behavior which can lead to returning nullptr in the particular case
On my PC i get
00AFFC80
00AFFBA8
so you are just lucky with zero return
when I work on pointers on a website I stick at a point.
When I write the given example I can assign adresses of array on a pointer for an increment a pointer example like ptr = arr; and it works correctly, but when I do the same thing for the decrement example it doesn't work it works only when I write like this ptr = &arr[2]. Why I have to write ampersand for decrement example? what is the difference between those two?
int main()
{
int arr[3]={10,20,30};
int *ptr,i;
ptr=arr;
for(i=0;i<3;i++)
{
printf("adress of variable arr[%d] %x\n",i+1,ptr);
printf("value of arr[%d] = %d\n",i+1,*ptr);
ptr++;
}
return 0;
}
You don't have to write it, just use the pointer:
ptr = var + 2 ;
for(i=0;i<3;i++)
{
printf("%d" , *ptr ) ;
ptr-- ;
Note that the last element is at +2 not +3.
in case of an int arr[3], &arr[0] and arr points to the same thing, the base address of the array, or, the address of the first element in the array. That's why in your increment case, you're allowed to write ptr = var which is nothing but storing the starting address in a separate pointer.
In case of decrements, there is nothing which can point directly to the end-of-array element address. So , you have to use the address-of-last-element [&arr[n-1], n being the size] to denote the address of the last element.
The difference is that in "decrement" case you use []. Think of arr as reference to whole array thus it is ok (compiler wise) to do ptr=arr or ptr=&arr with same result. On the other hand arr[3] is a reference to object in array, so you need to get its address explicitly (no compiler optimization for you).
Wouldn't the highest pointer be the one which can't be incremented through pointer arithmetic?
#include <iostream>
int main()
{
// Find the largest pointer
int x = 0;
int* px = &x;
while ((px+1) != px)
++px;
std::cout << "The largest pointer is: " << px;
return 0;
}
yields
Timeout
As already mentioned, you've got an infinite loop because the condition can never be false.
That being said, what you're doing is undefined behaviour, illegal C++. Pointer arithmetic is only legal with pointers pointing to the same array (and a single object is treated as an array of one element) and right past the end of it. You can't expect a reasonable outcome of your program even if you fix the loop.
I suspect the value of std::numeric_limits<uintptr_t>::max() is the theoretical maximum value of pointer (converted to integer), but it might not be avaliable to your program. There are things such as virtual address space and segmented memory model to consider. Anyway, exact values of pointers (except for nullptr) is not something you should be concerned with. You get pointers by taking addresses of existing objects or by calling allocation functions and that's that.
N.B. I think you have a misconception that attempting to increment an integer type beyond its maximum value will just do nothing. That's incorrect - unsigned integers will wrap around to 0 and with signed integers you get undefined behaviour again (see signed integer overflow).
Hope that helps.
This will never be false and thus never quit
while ((px+1) != px)
Look at this program:
#include <iostream>
int main()
{
int *px = (int *) (~0);
std::cout << "Value: " << px;
++px;
std::cout << " Value: " << px << std::endl;
}
whose output is:
Value: 0xffffffffffffffff Value: 0x3
As you can see, when you increment a pointer that is at its maximum, it values is reseted and begins again
You might want to look for the largest pointer value that occurs before wrap-around, i.e.:
while (px+1 > px)
px++;
...which will not work, of course, without the proper casts:
while ((unsigned long long)(px + 1) > (unsigned long long)px)
px++;