I have been asked to describe what these lines of code are doing for a college assignment
int main() {
int t1[] = {0,0,1,1,1}, t2[] = {0,0,1,1,1};
int *p1 = t1, *p2 = t2;
while (!*p1++ || !*p2++);
cout << (p1-t1) << endl;
cout << (p2-t2) << endl;
}
My take on it is, 2 arrays of type int are created and filled with values, 2 pointers are created and pointed at each array, then I start to have trouble.
while (!*p1++ || !*p2++);
To me this is saying while 0 move the position of *p1one place or while 0 move the position of *p2 one place, I'm really not confident in that assumption?
cout << (p1-t1) << endl;
So then we move onto the cout, now my take on this is, I'm subtracting the position of p1 from the position of t1, where p1 was positioned by the while and t1 points to the first position in the array.
again I could be completely wrong I'm only learning about pointers so please bear this in mind if I'm wrong in my assumptions.
The while loop is actually quite horrid. I've never seen code like this in real life, and would declare any programmer doing it in real life as mad. We need to go through this step by step:
while (condition);
We have here a while statement with an empty statement (the ";" alone is an empty statement). The condition is evaluated, and if it is true, then the statement is executed (which does nothing because it is an empty statement) and we start all over again. In other words, the condition is evaluated repeatedly until it is false.
condition1 || condition2
This is an "or" statement. The first condition is evaluated. If it is true, then the second condition is not evaluated and the result is "true". If it is false, then the second condition is evaluated, and the result is "true" or "false" accordingly.
while (condition1 || condition2);
This evaluates the first condition. If it's true we start all over. If it is false, we evaluate the second condition. If that is true, we start all over. If both are false, we exit the loop. Note that the second condition is only evaluated if the first one is false. Now we look at the conditions:
!*p1++
!*p2++
This is the same as *(p1++) == 0 and *(p2++) == 0. Each condition increases p1 or p2 after it has been evaluated, no matter what the outcome. Each condition is true if *p1 or *p2 was zero and false otherwise. Now we check what happens at each iteration:
p1 = &t1 [0], p2 = &t2 [0]
*p1++ == 0 is true, *p2++ == 0 is never evaluated, p1 = &t1 [1], p2 = &t2 [0].
*p1++ == 0 is true, *p2++ == 0 is never evaluated, p1 = &t1 [2], p2 = &t2 [0].
*p1++ == 0 is false, *p2++ == 0 is true, p1 = &t1 [3], p2 = &t2 [1].
*p1++ == 0 is false, *p2++ == 0 is true, p1 = &t1 [4], p2 = &t2 [2].
*p1++ == 0 is false, *p2++ == 0 is false, p1 = &t1 [5], p2 = &t2 [3].
t1 is the same as &t1 [0]. p1 - t1 == &t1 [5] - &t1 [0] == 5.
t2 is the same as &t2 [0]. p2 - t2 == &t2 [3] - &t2 [0] == 3.
You are correct in you assessment of t1, t2, p1, and p2.
while (!*p1++ || !*p2++);
I don't like this coding style, as it is easy to assume the programmer placed the semi-colon there by mistake. To indicate that an empty body is truly intended, the empty body should be distinguished in some way (like with a comment, placed on a separate line, or use curly braces instead).
The while enters the body so long as the condition is true. Since this is a logical-or expression, both !*p1++ and !*p2++ must be false before the while loop terminates. This happens when both *p1++ and *p2++ become non-zero. Because logical-or short circuits (the second expression is not evaluated if the first one is true), the progression of the p1 and p2 take on the following at the start of each iteration:
iter p1 *p1 p2 *p2 condition
---- -- --- -- --- ---------
0 &t1[0] 0 &t2[0] 0 !*p1++ is true, !*p2++ not evaluated
1 &t1[1] 0 &t2[0] 0 !*p1++ is true, !*p2++ not evaluated
2 &t1[2] 1 &t2[0] 0 !*p1++ is false, !*p2++ is true
3 &t1[3] 1 &t2[1] 0 !*p1++ is false, !*p2++ is true
4 &t1[4] 1 &t2[2] 1 !*p1++ is false, !*p2++ is false
Since each iteration uses post-increment, p1 ends with the value &t1[5], and p2 ends with the value &t2[3].
Pointer subtraction within the same array measures the distance between the two pointers in terms of number of array elements. An array name used in most expressions will decay to the value equal to the pointer to its first element. So t1 decays to &t1[0], and t2 decays to &t2[0].
Thus:
p1 - t1 => 5
p2 - t2 => 3
The key thing to note here is how the expression (a || b) is evaluated. First, the expression a is evaluated. If a returns true, b is not evaluated since OR of anything with True is True. This is called short-circuiting.
It helps to augment the code in the following manner -
int main(void){
int t1[] = {0,0,1,1,1}, t2[] = {0,0,1,1,1};
int *p1 = t1, *p2 = t2;
cout << *p1 << " " << *p2 << endl;
cout << p1 << " " << p2 << endl;
while (!*p1++ || !*p2++) {
cout << *p1 << " " << *p2 << endl;
cout << p1 << " " << p2 << endl;
}
cout << (p1-t1) << endl;
cout << (p2-t2) << endl;
return 0;
}
Output:
0 0
0x7fff550709d0 0x7fff550709f0
0 0
0x7fff550709d4 0x7fff550709f0
1 0
0x7fff550709d8 0x7fff550709f0
1 0
0x7fff550709dc 0x7fff550709f4
1 1
0x7fff550709e0 0x7fff550709f8
5 // Final p1 - t1
3 // Final p2 - t2
!*p1++ is equivalent to (!(*(p1++)). This is the post-increment operator. It increments the pointer but returns the old value (before the increment).
The expression in the loop is evaluated 5 times.
In the first iteration, p1 is incremented. Since the current value of *p1 (before incrementing) is 0, a ! of 0 returns 1. Due to short-circuiting, the rest of the expression is not evaluated. Thus only p1 gets incremented.
Same thing happens in the next loop.
Now, we have p1 = t1 + 2 indices, and p2 = t2.
In the third iteration, current value of *p1 is no longer 0. Thus both p1 and p2 are incremented.
Same thing happens in the fourth iteration.
Note that in the first four iterations, either p1 or p2 points to a 0 - so the not of either the left side or the right side is True and hence the while loop continues.
In the fifth iteration, both p1 and p2 are incremented, but since neither points to a 0 value, the loop exits.
Thus p1 is incremented 5 times, and p2 is incremented 3 times.
Summarizing - p1 - t1 will contain 1 + the number of 0s appearing continuously in the beginning of t1 and t2 (2 + 2 + 1). p2 - t2 will evaluate to 1 + number of 0s appearing continuously in the beginning of t2 (2 + 1).
First:
while (!*p1++ || !*p2++);
That means while the contents of p1 is 0 keep looping adding 1 to p1 each time until it becomes non-zero. Thereafter while the contents of p2 is 0 keep looping adding 1 to both p1 and p2 each time. If at any time the content of p1 become 0 again the logic repeats (I know this is confusing).
Basically in a while(first || second) style test the second part is only tested if the first part fails. And the pointer gets incremented regardless if the test passes or fails.
Your assumption about (p1-t1) is correct. That calculation gives you the number of integers between t1 and p1 (because they are int pointers). Because t1 is the beginning of the array the calculation actually gives you the index (offset) into the array that p1 is pointing at.
NOTE #1: If p1 and t1 were char pointers then subtracting them would give you the number of characters between them. If they were float pointers then subtracting them would give you the number of floats etc... Pointer arithmetic adds and subtracts in units of the data type they are pointing to.
NOTE #2: Strictly speaking t1 is an array type. It collapses to a pointer when you use it in a pointer context. For example in pointer arithmetic or when you assign it to a pointer variable. If that confuses you, don't worry, mostly it just works as a pointer because the compiler makes the conversion automatically whenever it is implied by the context.
As far as question is what would this print on console , answer is 0 0 before you removes ; at the end of while loop.
What's the significance of this loop?
First you are using OR that means if either value pointed to by p1 or p2 is 0 block would be executed. So, till p1 points to 3rd element (p1-t1) will give you number of elements crossed in t1 while (p2-t2) will be 0 as (p1-t1) will return true so second condition will not be checked. When p1 points to 1 then it will start incrementing p2 till it points to 3rd element of t2 and there's the end.
This is all this assignment has for you I believe.
This relation can help you better understand the conditions within the while loop:
arr[ i ] == * ( arr + i )
When doing pointer subtraction (if pointers are of the same type), the result is the distance (in array elements) between the two elements.
Assume that p1 and p2 are both pointers of type T*. Then, the value computed is:
( p2 - p1 ) == ( addr( p2 ) - addr( p1 ) ) / sizeof( T )
Related
I have these lines of code:
int a = 10, b = 1;
a = --b ? b : (b = -99);
cout << "a= " << a << "b= " <<b<< endl;
the output gives me b=-99 as a is not equal to 0(which makes senses) but it also changes the value of a to a=-99 how?
Your code is the equivalent of:
int a = 10, b = 1;
b -= 1; // b == 0
int x;
if (b != 0) x = b;
else x = b = -99;
a = x;
// at this point a and b have the same value
The ternary operator works as follows:
if (--b != 0) { // b is not 0 means true
a = b;
} else { // b is 0 means false
a = (b = -99);
}
You assign the value to a, so --b is 0 which is considered as false. Then you assign to b value -99 and afterward, you assign b to a. So, both variables have their values -99 in the end. Hope it will help you.
According to ternary operator, The first argument is a comparison argument(condition), the second is the result upon a true comparison, and the third is the result upon a false comparison.
So In Your case, the condition is not True, So the false statement get executed.
so now b has -99.
In c, c++, java we've seen, assigns the value of the variable
a = b = -99
In this, the both a & b gets the same value. Like this, ternary operator also assigning the value of the variable from false statement .
(a = (b = -99 ))
I think what is confusing you here is that, in C, an expression (such as b = -99) has both consequences and a value. The consequence of b = -99 is that b is assigned the value of -99; but note also that the value of this expression is -99.
Thus, in a ternary expression, which takes the general form:
lhs = test ? v_if_true : v_if_false;
the expression test is first evaluated and lhs is assigned either v_if_true (if test evaluates to non-zero) or v_if_false (if test evaluates to zero).
In your case, test is --b. The consequence of this expression is that the value of b is decreased by one, and the value of the expression is the resulting (modified) value of b (which will be zero in your code).
So, your ternary expression assigns to a the value of the v_if_false expression which is b = -99 (the brackets you give add clarity to the expression, but don't change its evaluation). So, as mentioned above, this expression (as well as modifying b) also has a calculated value of -99, which is then given to a.
If you wanted to leave a unchanged in the case when the v_if_false expression is executed, then you could do this using the comma operator, as follows (though I would not recommend using such code):
a = --b ? b : ((b = -99), a); // If --b == 0, this becomes a = a
This works because the value of an expression containing the comma operator is the value of the sub-expression after (to the right of) the comma.
I am busy with pointers at the moment and specifically pointers pointing to different elements in an array when I increment.
When I incremented using ++ everything is fine, but when I incremented using +2 things turned out differently to what I expected.
Let me explain.
In the first instance I set p2 = p1++;. The result I got there was what I expected, ie. p2 gives the value 2 and p1 gives the value 3. This is obviously since the initial value of p1 is assigned to p2 and afterwards p1 is incremented by 1, giving a new value for p1. No problem with that.
However; in the second instance I setp2 = p1+2. The result I got was not what I expected. The result was p1 gives value of 2 and p2 gives value of 4. How can this be? Shouldn't, like in the first instance, the initial value of p1 have been assigned to p2 , and then afterwards p1 incremented by 2 and given a new value of 4?
Then I got thinking a bit. Maybe +2 and ++ have different characteristics. What I mean with this is that when using ++, in this case, the code is saying (in layman's terms): "Make p2 point to the same address as p1 did at the start, and then let p1 point to the address of the next element". But when using +2 the code is saying: "Go to the element two "blocks" down from p1 and let p2 point to the address of that specific element; BUT DON'T CHANGE THE ADDRESS p1 IS POINTING TO WHILE DOING SO!". And this is what I mean with "they show different characteristics". They don't act in the same manner.
Is my assumption correct?
Also, how do you increment by two(or three or four, etc.) in this instance whilst maintaining the same characteristics as the ++ operator?
Here are some links to sites I researched which dealt with increments. But none of them really address my problem properly. Nor do any other sites. Also, most of them suggest using something like a +=2 to increment by two, which is fine, but that also does not tackle my specific problem.
Link1
Link2 SO
Could you please explain in the simplest terms possible since I am still new to C++.
Instance One
#include <iostream>
int main()
{
int a[5] = {1,2,3,4,5};
int *p1, *p2;
p1 = &a[1];
p2 = p1++;
std::cout << "Value1: " << *p1 << "\n" << "Value2: " << *p2;
return 0;
}
Output result of instance one (What I expected)
Value1: 3
Value2: 2
Instance Two
#include <iostream>
int main()
{
int a[5] = {1,2,3,4,5};
int *p1, *p2;
p1 = &a[1];
p2 = p1+2;
std::cout << "Value1: " << *p1 << "\n" << "Value2: " << *p2;
return 0;
}
Output result of instance two (NOT what I expected)
Value1: 2
Value2: 4
p2 = p1+2; does not modify the value of p1. It just assigns the result of p1+2 to p2.
p2 = p1++; does modify the value of p1. It first assigns p1 to p2, then increments p1 by one.
The output is exactly what is expected. When you perform this assignment:
p2 = p1 + 2;
You just ask to assign the value p1 + 2 to p2, that's it. There is no reason for p1 being updated. You seem to confuse the + operator with the post-increment/pre-increment ++ operator.
A little reminder might help.
I was not really clear with the post increment operator that I always used with for loops.
My latest and newly acquired understanding of post increment operator is the following:
int a = 5
int b = a++ //a will increment and return back its old value 5
so b = 5
Armed with this new knowledge i decided to understand/apply it to the places where i commonly used the post increment operator as in a for loop . Now it seems like I am lost
since I am ending up with the wrong output theoretically
Consider the following code
for(int i=0 ; i< 3 ; i++)
{
std::cout << i;
}
First loop
i starts with 0 which is less than 3 so ( increment by 1 however since its i++ it returns old value 0)
so cout should display 1 // But it displays 0
Second Loop
i is now 1 which is less than 3 so i++ is applied - Now i is 2 and returns back 1
so cout should display 2 //But it display 1
Third Loop
i is now 2 which is less than 3 so i++ is applied - Now i is 3 and returns back 2
so cout should display 3 //But it display 2
Fourth Loop
i is now 3 which is not less than 3 so loop exits
Could anyone please clear my understanding and point me in the right direction.
The output should be 0,1,2 where am i going wrong ?
What you're missing is when each of those sections of the for statement happen:
for (int i = 0 ; i < 3 ; i++)
// 111111111 22222 333
The first bit happens once before any iterations are done.
The second expression is evaluated before each potential iteration and, if false, no further iterations are done.
The third bit is done at the end of each iteration, before returning to evaluate the second bit.
Now re-read that last bullet point carefully. The i++ is done at the end of an iteration, after the cout << i. And, immediately after that, the continuation condition is checked (the second part).
So the loop is effectively the same as:
{ // Outer braces just to limit scope of i, same as for loop.
int i = 0;
while (i < 3) {
cout << i;
i++;
}
}
That's why you get 0 1 2.
The semicolons in a for loop delimit three different expressions. The value of the third expression is irrelevant to the behavior of the loop. You could replace i++ with ++i and your loop would behave the same; either way, i is incremented by 1.
To observe the behavior of the increment operators, consider the following loops:
for(int i = 0 ; i++ < 3 ; ) cout << i;
/* ^^^ Nothing here! */
Note that the third expression is empty. The output is 123—0 is skipped because the test, including increment, occurs before every iteration of the loop.
How does the postincremented loop behave compared to a similar one with the preincrement operator?
for(int i = 0 ; ++i < 3 ; ) cout << i;
Now the output is 12—3 is not printed because the conditional test sees the value 3 as soon as it is incremented to that, so the loop exits.
You just need to know that the statement int i = 0 is executed first , i.e , i takes first the value 0 , checks if the condition is true and then what the loop body is executed .
Then , i is incremented.
Consider the following examples:
int x;
if (x = 1)
//...
if (std::cout << "Is it true?")
//...
Both are evaluated as true, but why?
The if (x = 1) is essentially the same as tmp = (x = 1); if (tmp) ...
The "result" of operator << (const char *) is an ostream&, which has an operator bool that the compiler calls to make it "comparable". operator bool will return "false if there was an error, otherwise true". Before C++11, it would return a void*, but the meaning was the same ("false (= 0) if there is an error, true otherwise".
The result of assignment is its left operand, so the value of x = 1 is its left operand x, which has the value of 1 now. And any non-zero integer is treated as true in the condition.
Because x = 1 is an assignment setting x to 1, not a comparison for equality. Comparison is done via x == 1.
It is a common mistake. Often people write 1 == x to catch these errors, since assignment to a constant triggers a compile-time error.
Besides the assignment result for x as mentioned in the other answers the
if (std::cout << "Is it true?")
evaluates to true, because the statement is equivalent to
if ((std::cout << "Is it true?").good())
which checks for the stream state of std::cout.
Both statements return a value other than 0 and are thus considered to be "true".
If you assign a value to a variable, the result of that statement is the assigned value so you can assign multiple variables at once. For example, foo = bar = baz = 1. This works because baz = 1 yields 1, which is then assigned to bar, then to foo. So x = 1 has the value 1 and is thus true.
Next, the std::cout << "foo": the operator<< on a ostream returns the ostream so you can do things like std::cout << "foo" << "bar";. Again, there is a value returned that is not 0 and thus true.
In this condition x = 1 you firstly assign 1 to your x variable, and then test x, so it is exactly the same with:
x = 1;
if( x ) // which is 1, so true
About the output operator <<, the compiler will return true if the output-stream's state cout is ok. So it is not going to be a valid stream if some error occurs.
In the first one, you're assigning the value of 1 to x. A non-zero value will always evaluate to true in a condition.
For the second one, when std::cout << "Is it true?" is called, operator<< will return a reference to std::cout. At that point, the condition is simply reduced to:
if (std::cout)
//
This is now evaluating whether or not std::cout is in a good state.
Why are the two following code segments not equivalent?
void print (char* s) {
if (*s == '\0')
return;
print(s+1);
cout << *s;
}
void print (char* s) {
if (*s == '\0')
return;
print(++s);
cout << *s;
}
The ++ operator increments the pointer value, but then returns the original value ... so print(s++) will print the value of s before the increment, since even though it adds a value of 1 to s, making the value stored at s equal to s+1, it still returns the original value of s as the result of the operation. On the otherhand print(s+1) prints the value after the increment, but very importantly does not modify the original value of s. So the result of the statement s+1 is just a new temporary pointer value ... the original value of s is not modified.
Furthermore, since you've incremented and changed the value of s with the ++ operator, when you call cout, you're now printing the value to wherever the new pointer is pointing (this could cause a crash or segmentation fault if you're not careful and there's no user accessible memory at the new memory location s is pointing to). With s+1, the value of s remains unmodified, so the result of cout will be to wherever s was originally pointing.
Edit:
As Michael points out, this is actually a recursive function, so the second example simply keeps calling print() with the same argument, since as mentioned before, the returned value from s++ is the original value of s. That means you'll end up with a stack overflow at some point and just crash unless the value that s pointed to was already the NULL character.
Since it looks like the OP changed print(s++) to print(++s), which is hugely different, here's an explanation for this new version.
In the first example, you have:
print(s+1);
cout << *s;
s+1 does not modify s. So if s is 4, and you print(s+1), afterwards s will still be 4.
print(++s);
cout << *s;
In this case, ++s modifies the local value of s. It increments it by 1. So if it was 4 before print(++s), it will be 5 afterwards.
In both cases, a value equivalent to s+1 would be passed to the print function, causing it to print the next character.
So the difference between the 2 functions is that the first one will recursively print character #0, then 1, 2, 3, ..., while the second function prints 1, 2, 3, 4, ... (it skips the first character and prints the "\0" afterwards).
Example:
For the s+1 version, print("hello") will result in h e l l o
For the ++s version, print("hello") will result in e l l o \0
Both of the expressions s++ and s+1 are to do with increasing the position of the pointer itself, not the value contained at the pointer locations
The value of s++ is just s, and the value of s+1 is, well, one position further on than s!
The value of s after executing s++ is one position further on than it was before. After using s+1, the value of s is unchanged.
Therefore the order they print out the letters is reversed!
I will try to explain an example of pre and post increment from which you can solve the question posted yourself.
#include <iostream>
void foo(int num)
{
std::cout << num << "\n" ;
}
int main()
{
int number = 10 ;
foo( number++ ) ;
foo( ++number ) ;
foo( number + 1 ) ;
getchar() ;
return 0 ;
}
Output:
10
12
13
Why 10?
foo( number++ ) ;
Post-increment operation is done on number. Meaning, value of number is first passed to foo and then the value of number is incremented upon foo return. So, after function return, number is 11.
Why 12?
foo( ++number ) ;
Pre-increment operation is done on number. Meaning, before even call to foo, the value of number is incremented to 12. And then it is passed to foo. So, even after the function return, number is still 12.
Why 13?
It's just straight forward. Value of number is not modified but passed a value adding 1 to the value of number. In this process, number is not modified. So, even after function return, number is still 12.
Hope this helps to solve the problem yourself ( though in your case it is paper-pencil exercise ) :)