Stroustrup C++ 4th Ed Page 197 has the following examples, which result in an incrementing stream of characters printed until null and not "abc". Questions: how is the ++*p being evaluated? ++ and * are the same precedence and evaluation right-to-left, therefore it's my understanding *p is evaluated first, leading to the character p points to, then this character is incremented by ++. Is this understanding correct? Thanks
#include <iostream>
using namespace std;
void fp(char* p)
{
while (*p)
cout << ++*p;
}
void fr2(char& r)
{
char* p = &r;
while (*p)
cout << ++*p;
}
int main(int argc, char *argv[])
{
char s[] = "abc";
char *p = s;
fp(p);
fr2(*p);
return 0;
}
Yes, you are right about the precedence and the associativity. This expression:
++*p;
is parsed as
++(*p);
i.e. first the indirection of p is done, and then the value returned is incremented.
This means that in the while loop:
while (*p)
cout << ++*p;
the pointer p is never actually incremented. This results in an infinite loop where just the value of p[0] is incremented forever.
Here's a demo, which shows the output as a very long sequence of ascii values starting from a. Note that abc is not printed.
By the same reasoning, the expression:
*++p;
is parsed as:
*(++p);
which is fine, since the pointer is incremented first, and then the pointer is dereferenced.
Related
Playing with pointers in c++. I have come across something unexpected. I have the code:
int main(){
char p=0;
char* ptr=&p;
cout<<"This is the pointer: "<<ptr;
return 0;
}
When I run this code the output of ptr is blank. If I change the value of p to any other value it seems to output a random pointer, e.g. value changes between runs, as I would expect. The question then is what is different about assigning a char value to 0.
Extra info: compiling with g++ 4.8.4
char p=0;
Your variable is defined as character and assigned an integer value zero, so internally you are assigning a null terminated character on variable p.
If you correct above statement as follows and print more details it may be clear to you.
char p='0';
std::cout<<"This is the pointer: "<<&ptr<<" ---"<<*ptr <<"----"<<ptr;
&&ptr- > getting the address of ptr
*ptr-> getting the value assigned to the ptr
ptr-> getting the string from ptr until it see a null terminating character, so expects garbage value as output.
Demo: http://coliru.stacked-crooked.com/a/2d134412490ca59a
char p = 0;
char* ptr=&p;
here ptr is a pointer of a zero length string. Because it is a char* pointer which point to a zore(\0) which is considered as the end of a string.
The program has undefined behaviour in case when p is not set to 0. To make it well-formed write
int main(){
char p=0;
char* ptr=&p;
cout<<"This is the character: ";
// ^^^^^^^^^^^^^^
cout.write( ptr, 1 );
return 0;
}
Or
int main(){
char p=0;
char* ptr=&p;
cout<<"This is the pointer: "<<( const void * )ptr;
return 0;
}
Otherwise this statement
cout<<"This is the pointer: "<< ptr;
simply outputs an empty string only when p is set to 0.. In other cases it will output some garbage after character p until a zero character is encountered.
Another approach can look like
int main(){
char p[2]= { 0 };
char* ptr=&p;
cout<<"This is the pointer: "<< ptr;
return 0;
}
This statement
cout<<"This is the pointer: "<< ptr;
outputs the string pointed to by ptr. A string is a sequence of characters terminated with zero character. So you should define a character array with at least two characters where the second character will be always set to 0.
Your pointer is pointing to a char which has a value of zero.
The pointer is perfectly valid.
cout is printing a zero length string.
This code was provided by my c++ instructor on a sample midterm. We covered argc and argv on a very basic level, so I understand what those expressions alone mean. However, any additions to those like the dereference operator and '++' confuse me and what I've googled hasn't been clear enough for me to apply it to this specific example. Also, when I try to compile, it provides this error:
In function 'int summer(int*, char**)':
Line 9: error: cannot convert 'char**' to 'const char*' for argument '1' to 'int atoi(const char*)'
compilation terminated due to -Wfatal-errors.
We haven't officially covered pointers, but I think I understand them well enough. char** means you're dereferencing twice, so the value of the pointer char, which is a pointer to something else, so the second * means we want the value of that. Is it constant because we are relying on something input in the command line and that can't be changed? I don't understand this.
#include <iostream>
using namespace std;
int summer(int *acc, char * ptr[])
{
register int n;
n = atoi(ptr);
*acc = *acc + n;
}
main(int argc, char * argv [])
{
int sum = 0;
while (--argc)
summer(&sum, *++argv);
cout << "sum is " << sum << endl;
}
Another question: When passing *++argv to summer(), does that mean the value of (argv[] + 1)? What would that even be? Adding the value one to the entire vector? I know that atoi(array) means changing the string into a numerical value, and then we are storing that in register int 'n', and then adding that to the sum which is directly changed in main. And that's about the only part of this code I really understand. Sorry if my questions/this post is kind of a mess.
To sum up what my questions are:
What does the compiling error message mean?
What does ++argv do?
Thank you.
Edited:
Okay, I've made the changes you guys have suggested (thank you!!):
#include <iostream>
using namespace std;
int summer(int *acc, char * ptr)
{
register int n;
n = atoi(ptr);
*acc = *acc + n;
return 0;
}
int main(int argc, char * argv[])
{
int sum = 0;
while (--argc)
summer(&sum, *++argv);
cout << "sum is " << sum << endl;
return 0;
}
I also added the returns because the compiler gave a new error due to no return value for the function type. On Codepad it compiles and prints "the sum is zero," however, it still does not compile on Dev C++ 5.7.1 which is what I am using. It doesn't display error messages (the ones I have been reading are from Codepad online compiler), or at least I can't find where to turn them on. It just highlights the lines it seems to have a problem with, and that is still the line with atoi(ptr).
*argv is equivalent to argv[0], so ++argv; would make *argv equivalent to what was originally argv[1]. So *++argv evaluates to the same thing as argv[1] (the first command line argument, after the name of the program itself), except it increments argv whereas argv[1] obviously does not.
For your error, you should change:
int summer(int *acc, char * ptr[])
{
to:
int summer(int *acc, char * ptr)
{
When you dereference a char **, which is the type of argv, you get a char *. char * is what atoi() is expecting.
Your program is essentially equivalent to this:
#include <iostream>
#include <cstdlib>
using namespace std;
void summer(int * acc, char * ptr)
{
*acc += atoi(ptr);
}
int main(int argc, char * argv [])
{
int sum = 0;
for ( int i = 1; i < argc; ++i ) {
summer(&sum, argv[i]);
}
cout << "sum is " << sum << endl;
}
except that your's doesn't check for troublesome values of argc.
The ++ is called the increment operator. It usually adds 1 to something.
The argv decays to a pointer that points to a container of arguments to your program.
The expression ++argv points to next parameter, if there is one.
Incrementing a pointer means to make it point to the next item in the list.
argv has type char ** (don't be distracted by the square brackets), meaning it points to a char * which is in a list of adjacent char *s. The argc parameter lets us know where to find the end of said list.
So, doing ++argv means that argv will now point to the next char * in the list. Applying * to that (and passing the result to a function) means that we send the value of the next char * in the list to that function.
The result of all this is that the function is called once for each argument, excluding the first one (since we ++'d before dereferencing the first time).
NB. This code actually has a bug; if argc == 0 it will go off into la-la land. It should check for this case before entering the loop.
Is it constant because we are relying on something input in the command line and that can't be changed?
No, the const char * bit refers to the type of argument that atoi() accepts. It is a pointer to a constant char. Note that char * is implicitly convertible to const char *, but not the opposite.
All this means is that atoi() accepts a pointer to a character, and it promises that it will not modify the target of the pointer.
My guess is that the ptr argument should have been char * ptr instead of char * ptr[]. If you change that, the code should compile.
I'm trying to understand how the parentheses affects the precedence in an expression:
int arr[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
auto b = arr;
std::cout << *(++b) << std::endl;
// output : 1
In this code I get the expected output but if I change it to:
std::cout << *(b++) << std::endl;
// output 0
I get 0 as output. Because of the parentheses I though b++ will be evaluated first and then de-referencing will occur. It seems I was wrong, then I removed the parentheses completely and test with *++b and *b++ and get the same results.Does that mean the parentheses don't affect the precedence on this kind of expressions ? And why are the results of this two expressions are equivelant:
*(b + 1)
*(++b)
But it's not the case with *(b++) ?
It does evaluate the b++ first. b++ increments b and returns the previous value of b, before the increment happened. The result of b++ and the value of b afterwards are different. Think of it as (using int instead of int * because a reference-to-pointer makes the signature ugly):
int postfix_increment(int &x) {
int result = x;
x = x + 1;
return result;
}
(Except that using the incremented value before the next sequence point is undefined behavior.)
If you introduce a temporary variable for the result of the parenthesis, to make sure it's evaluated first, it may be easier to see the difference:
int *tmp = b++;
// At this point, b == tmp + 1!
std::cout << *tmp << std::endl;
*(b++) is equivalent to storing the old pointer, incrementing the pointer and dereferencing the old pointer
int* post_increment(int* b)
{
int* old = b;
++b;
return old;
}
It is an instructive exercise to write a thin iterator wrapper around a plain pointer. When writing user-defined iterators, the above post_increment() function is usually written an overloaded operator++(int). The int argument is purely to distinguish it from the pre-increment operator operator++(). In addition, you'd need an overloaded operator*() to dereference an iterator.
*(b+1) works because you do math. Math takes parentheses into account. Only after Math is done, the expression gets evaluated.
*(++b) works because you increment before evaluation (prefix increment).
*(b++) doesn't work because you increment after evaluation (postfix increment).
Here is the code I'm running:
#include <iostream>
using namespace std;
int main()
{
int x = 5;
int *p;
p = &x;
*p++;
cout<<x<<endl;
return 0;
}
The output should be 6, because p is pointing at the address of x. However, I get 5.
But more interestingly, I couldn't understand why the output is 6 when I change *p++ with *p = *p+1. Why is this?
You are wrong. *p++ reads the value that p points to, then increases the pointer p. You probably wanted (*p)++.
*p = *p + 1 works because it is correct.
Postfix ++ has higher precedence than unary *, so *p++ is parsed as *(p++); IOW, you're incrementing the pointer, not the thing being pointed to.
Use (*p)++ to increment the thing being pointed to, or use ++*p.
Use brackets if you do not understand operator precedence.
*p++
is
*(p++)
and you want
(*p)++
The rule of thumb is:
multiplication and division go before addition and subtraction
for everything else, just use brackets
I have the following function which is part of the Trie structure implementation:
int alpha_char_strlen (const AlphaChar *str) {
const AlphaChar *p;
for (p = str; *p; p++) ;
return p - str;
}
Can any one help me and explain how does the condition for the for loop hold, and precisely what is the condition in this case?
Note: AlphaChar is simply a typedef with unsigned int type and the function counts the AlphaChar characters.
The condition *p is identical to *p != 0 (if *p is of a primitive type). That is, you keep incrementing the pointer p until it points to a zero. In other words, you treat str as the pointer to a zero-terminated array.
The condition is *p, which is short for *p!=0.
So it simply scans the AlphaChar array for an occurrence of 0.