I was reading some code and came across this thing. I don't have the whole context now save this line.
cout<<(*--*++ptr+1)<< endl;
this compiles fine and works when we input values in it..
its declaration is like this.
char ***ptr ;
What is this operator and is it included in the standard?
It's not a single operator, it's a combination of several unary operators. It gets parsed like this:
*(--(*(++ptr))) + 1
So, ptr1 is first incremented, then dereferenced, then that value is decremented and dereferenced again.
Related
I am trying to call a variable in my class using the this keyword in two ways but I am confused with the 2nd way. The correct way of dereferencing happens to be "(*this).num" however, I was wondering why "*(this).num" is not right as well. The error I get with *(this).num is
request for member 'num' in 'this', which is of pointer type çlass const'*
class::class(int n): num(n)
{
cout << "num= " << num << endl;
cout << "this->num" << this->num << endl;
cout << "(*this).num" << (*this).num << endl;
}
Because if you define
int i = 9;
int *ptr = &i;
cout<<*(ptr)<<endl;
and call *(ptr) it works. But why doesn't it work in my class?
It's simply a matter of operator precedence. The binary dot operator has a higher precedence than the unary star operator, so *(this).num (the parentheses have no effect there) is interpreted as *(this.num), and not as (*this).num. The compiler is telling you that, because this is a pointer, this.num doesn't make sense: you can't apply the dot operator directly to a pointer.
You are using two operators: the indirection/dereferincing operator * and the member access operator ..
If you have a look at the precedence of these operators, you'll see that . has higher precedence than * (that is, . will be applied before *), so thus *(this).num is basically the same as writing *(this.num).
Since this is a pointer, you can't use the . operator on it, which is also what the error message is telling you (try using -> instead).
The reason why your second example works, is that you're not using the . operator, and thus there is no precedence to be messed up.
. has higher precedence than *.
So writing *(this).num is equivalent to (*((this).num))). Or *(this.num).
Your second example is completely different from the first since there is no access to members . or ->.
If you don't know all the precedences, or even if you do, it's usually more readable to add the appropriate brackets.
One works and the other doesn't because they are not the same thing!
*(ptr) and *(this) are the same, but *(this).num and (*this).num are not the same, that's the whole point of adding the parentheses! They change how the sub-expressions are grouped, just like in mathematics.
The parentheses in (ptr) and (this) are completely redundant, you are grouping a single sub-expression, which does nothing. In (*this) it's not redundant, it ensures that you dereference the pointer, so in (*this).num it dereferences the pointer first and then the member access .num is applied to the result of that dereference.
Compare it to mathematics:
(1) is just 1, and similarly (ptr) is just ptr
-(1) is just -1, and similarly *(ptr) is just *ptr
But -(1 + 3) and -(1) + 3 are completely different, because you change the order of the operators.
Similarly, *(this.num) and (*this).num are completely different.
The short answer is syntax.
(ptr) looks like this: evaluate expr inside () first, then dereference the result which is in this case is int. It's fine, the same as *ptr.
*(this).num is eq. with *this.num which means get the num member of this. After that dereference num. It's incorrect as you can see because "this" is a pointer to the current object.
(*this).num means dereference this, then get the num member.
This is an excercise in my textbook. I need to find the output of this code.
#include<iostream>
using namespace std;
int main()
{
int x[]={10,20,30,40,50};
int *p,**q,*t;
p=x;
t=x+1;
q=&t;
cout<<*p<<","<<**q<<","<<*t++;
return 0;
}
The output is
10,30,20
Here I dont understand the declaration of **q, and also how its value comes out to be 30. I also noticed that changing the last statement to
cout<<*p<<","<<**q<<","<<*t;
changes the output to
10,20,20
Could somebody explain what goes on behind the scenes here? Thanks a lot in advance.
Here, q is a pointer to a pointer to int, and it was set to point to t. So *q is identical to t, and **q is *t. Which means the cout expression can be rewritten as:
cout<<*p<<","<<*t<<","<<*t++;
Here you can see that t is read and modified in different parts of the expression, and the standard says that the order in which these parts are executed is not specified. So t may be modified before or after (or even while) it is read. When this kind of thing (unsequenced read and write to a variable) happens, we get undefined behavior: Anything can happen as a result. A specific compiler may give a specific result on a specific computer, but there is no guarantee that you will always get this result.
So this exercise is invalid, and there is no point in trying to figure out why you saw a specific output.
On the other hand, the second line you attempted:
cout<<*p<<","<<**q<<","<<*t;
is perfectly valid, because it doesn't modify t anywhere.
p and t are both of the type pointer to int, q is of the type pointer to (pointer to int)
The * operator makes a pointer to a reference.
So *p is of the type int&, so is *t.
*q is of the type int*& (read reference to a pointer to int)
You want to print an int value here and must therefore use the * operator a second time.
So the **q is just making a pointer to a pointer to int to a reference to int
I forgot to mention it: The process is called dereferencing pointers.
Maybe the descirption on this side will give you a better insight:
http://www.cplusplus.com/doc/tutorial/pointers/
++ operator has higher precedence than <<
When program is executed this are events:
int x[]={10,20,30,40,50};
int *p,**q,*t;
p=x;
t=x+1;
q=&t;
cout<<*p<<","<<**q<<","<<*t++; //1st change value of t to t+1,
//but return old t in place ^
//then to output stream 'p'=10, then 'q'=new 't'=old 't'+1=30,
//then old 't'=20 which is returned by sufix ++ operator
Given the code below
char buf[] = "asfsf";
char *a=buf;
++*a++;
cout<<*a;
I expect the result is the next character of 's' that is 't', but the result is still 's'. Why?
Why ++*a++ is not the same as
*a++;
++*a;
cout<<*a;
Is that really a duplicate question with ++i++? I know ++i++ is a undefined behavior and will cause compile error, but ++*i++ actually can run. Is my case also a undefined behavior?
According to the language grammar, the operators associate as:
++(*a++)
Note: associativity does not imply an order of operations.
*a++ evaluates to an lvalue designating the location where a was originally pointing, with side-effect of modifying a. All fine so far.
Applying prefix-++ to that lvalue increments the value stored there (changing 'a' to 'b').
Although the two increments are unsequenced, this does not cause UB because different objects are being incremented, and the lvalue designating the latter location does not depend on the increment. (It uses the old value of a).
As it stands right now, your code has undefined behavior, because it attempts to modify the contents of a string literal.
One way (probably the preferred way) to prevent the compiler from accepting such code is to define your a like:
char const *a="asfsf";
This way, the ++*a part simply won't compile.
For the sake of exposition, let's change the code a little bit, to become:
#include <iostream>
int main(){
char x[]="asfsf";
char *a = x;
++*a++;
std::cout<<x;
}
Now a points at memory we can actually write to, and get meaningful results. This prints out bsfsf. If we print out a, we'll get sfsf.
What's happening is that a++ increments a, but still yields the original value of a. That is dereferenced, giving a reference to the first element of x. Then the pre-increment is applied to that, changing it from a to b.
If you want to increment the pointer, dereference the result, then increment that, you'd use: ++*++a;. Well, no, you wouldn't use that--or at least I hope you wouldn't. It does increment a to point at the second element of the array, then increment that second element to change it from s to t--but anybody who read the code would be completely forgiven if they hated you for writing it that way.
#include<stdio.h>
int main(){
char *ptr="Helio";
ptr++;
printf("%s\n",ptr);
//*ptr++;
printf("%c\n",++*ptr);/*Segmentation fault on GCC*/
return 0;
}
Q1) This works fine in Turbo C++ but on GCC it gives segmentation fault. I am not getting the exact reason.
May be operator precedence is one of the reason.
Q2) Do each compiler has different operator precedence?
As I can see here ++ has higher precedence than dereference operator. May be GCC and Turbo C++ treats them differently.
No, the operator precedence is defined by the C standard, all the compiler follows the same one.
The reason of difference result of Turbo C++ and GCC in this case is because you modified the string literal, which is undefined behavior.
Change it to:
char arr[] = "Helio";
char *ptr = arr;
and you can modify the content of the string now. Note that arr itself is the array name and cannot be modified, so I added a new pointer variable ptr and initialize it to point to the first element of the array.
In your last printf() line, the expression ++*ptr is equivalent to ++ptr[0], which is, in turn, equivalent to ptr[0] = ptr[0]+1. Since ptr[0]=='H', you are trying to change the value of ptr[0] to 'I'.
That's the key problem there. Since &ptr[0] points to the first element of the constant "Helio", the attempt to change the first character, H, is giving trouble, because it is Undefined Behaviour.
char* p = "some literal";
This is only legal because of a smelly argument that C-people fought over during standard comitee negociations. You should consider it as an oddity that exists for backward compatibility.
This is the message you get with GCC:
warning: deprecated conversion from string constant to 'char*'
Please next time, write the following:
char const* p = "some literal";
And make it a reflex in your coding habits. Then you would not have been able to compile your faulty line.
which is:
++*ptr
Here you are taking the first character of the constant literal and try to increment it, to what comes after H, therefore I. But this memory zone happens to be in a write protected page, because this is a constant. This is very much undefined by standard and you should consider it illegal. Your segfault comes from here.
I suggest you run your program in valgrind next time to get more elaborate error messages.
In the answer that Yu Hao wrote for you, what is happenning is that all the characters gets copied one by one, from the constant string pool where the literal are stored, to a stack-allocated char array, by a code that the compiler writes at the initialization/declaration site, therefore you can dereference its content.
Today, I found out that you can write such code in C++ and compile it:
int* ptr = new int(5, 6);
What is the purpose of this? I know of course the dynamic new int(5) thing, but here i'm lost. Any clues?
You are using the comma operator, it evaluates to only one value (the rightmost).
The comma operator (,) is used to
separate two or more expressions that
are included where only one expression
is expected. When the set of
expressions has to be evaluated for a
value, only the rightmost expression
is considered.
Source
The memory address that the pointer is pointing to is initialized with a value of 6 above.
My compiler, g++, returns an error when attempting to do this.
What compiler or code did you see this in?
I believe it is bug which meant to allocate some sort of 2D array. You can't do that in C++ however. The snippet actually compiles because it's utilizing the comma operator, which returns the last expression and ignores the results of all the others. This means that the statement is equivalent to:
int* ptr = new int(6);
The 5 is ignored. this allocates an int on the heap and initializes it to (5,6).
the result of a set of statements separated by the comma operator is the value of the last statement, so the int is initialized to 6
Simply do this:
int* ptr = new int(6);
As far as comma operator is concerned, use it when you can't do the desired task without it. There is no use of applying tricks such as:
int* ptr = new int(5, 6);