tags:

views:

264

answers:

7

In a book I am reading there is a piece of code :

string x;
size_t h=0;
for(const char* s=x.c_str();*s;++s)
    h=(h*17)^*s;

Regarding this code, I have two questions:

  1. how can *s be a condition? what does it mean?

  2. what does "h=(h*17)^*s" mean?

Thanks for help!

+3  A: 
  • *s detects the string termination character '\0'
  • (h*17)^*s is what it says: h multiplied by 17 and xor-ed with the content of the character pointed by s. Seems a simple hashing funciton.
baol
It's both C and C++
Ken Bloom
since when do we have `string` in C?
IVlad
@http://stackoverflow.com/users/197788/ken-bloom Sorry, I've edited just before the comment ;)
baol
What does "C mixed with C++" even mean? You could say that about most C++ programs.
IVlad
Lots of zealots here :-). 3 comments in a few seconds. The question is about C, the "string", I agree *might* be C++ (or a C structure containing a pointer to a function) ;)
baol
Removed the controversial phrase. Anyway C mixed with C++ means (to me) a C++ program that doesn't take full advantage of C++, but stands back to C syntax.
baol
+16  A: 
  1. how can *s be a condition? what does it mean?

It means "while the value pointed to by s is not zero." C strings are null-terminated, so the last character in the string returned by c_str() will be the null character (\0, represented by all bits zero).

  1. what does "h=(h*17)^*s" mean?

It multiplies h by 17 then xors it with the value pointed to by s.

James McNellis
The code as given may have a subtle bug. The null character is a valid character in std::strings. The function as given won't completely process a string if this is true of its input.
stonemetal
+1  A: 
  1. *s is the character that s currently points to, so it's a character. The for loop goes on until it becomes \0, meaning until the string ends.
  2. h is assigned the value of h * 17 xored with the (ascii value of) character *s.

Here's a good tutorial about pointers.

IVlad
+3  A: 

1) *s in the condition checks whether *s!=NUL

2) h=(h*17)^*s implies multiply h by 17 and perform exclusive-OR operation with the value pointed to by s.

Prasoon Saurav
+1  A: 

In C and C++, true and false are the same as non-zero, and zero. So code under if (1){ will always execute, as will code under if (-1237830){, but if (0){ is always false.

Likewise, if the value of the pointer is ever 0, the condition is the same as false, i.e. you will exit the loop.

Chris Cooper
+3  A: 

In C (or C++) any value can be used as a "boolean". A numeric value of 0, or a NULL pointer, means "false". Anything else means "true".

Here, *s is "the character value currently pointed to by s". The loop stops if that character is a 0 (not the "0" digit, with ASCII encoding 48, but the byte with ASCII encoding 0). This is conventionally the "end-of-string" marker, so the loop stops when it reaches the end of the string.

"^" is the bitwise XOR operator. The left "*" is a plain multiplication, while the other "*" is the pointer dereference operator (i.e. the thing which takes the pointer s and looks at the value to which this pointer points). "=" is assignment. In brief, the value of h is multiplied by 17, then XORed with the character pointed to by s, and the result becomes the new value of h.

Thomas Pornin
+3  A: 

As other answers have explained, the basic answer is that any expression that evaluates to 0 gets interpreted as a 'false' condition in C or C++, and *s will evaluate to 0 when the s pointer reaches the null termination character of the string ('\0').

You could equivalently use the expression *s != 0, and some developers might argue that this is what should be used, giving the opinion that the 'fuller' expression is more clear. Whether or not you agree with that opinion, you need to be able to understand the use of the terse alternative, since it's very commonly used in C/C++ code. You'll come across these expressions a lot, even if you prefer to use the more explicit comparision.

The more rigorous explanation from the standard (for some reason I feel compelled to bring this into the discussion, even though it doesn't really change or clarify anything. In fact, it probably will muddle things unnecessarily for some people - if you don't care to get into this level of trivia, you'll miss absolutely nothing by clicking the back button right now...):

In C, the *s expression is in what the standard calls 'expression-2' of the for statement, and this particular for statement example is just taking advantage of the standard's definition of the for statement. The for statement is classified as an 'iteration statement', and among the semantics of any iteration statement are (6.8.5/4 "Iteration statements"):

An iteration statement causes a statement called the loop body to be executed repeatedly until the controlling expression compares equal to 0.

Since the 'expression-2' part of the for statement is the controlling expression, this means that the for loop will execute repeatedly until *s compares equal to 0.

The C++ standard defines things a little differently (but with the same result). In C++, the for statement is defined in terms of the while statement, and the condition part of the while statement controls the the iteration (6.5.1/1 "The while statement"):

until the value of the condition becomes false

Earlier in the C++ standard, the following describes how expressions are converted to bool (4.12 "boolean conversions"):

An rvalue of arithmetic, enumeration, pointer, or pointer to member type can be converted to an rvalue of type bool. A zero value, null pointer value, or null member pointer value is converted to false; any other value is converted to true

Similar wording in the standard (in both languages) apply to the controlling expression/condition of all selection or iteration statements. All this language-lawyerese boils down to the fact that if an expression evaluates to 0 it's the same as evaluating to false (in the English sense of the word, since C doesn't have a built-in false keyword).

And that's the long, confusing explanation of the simple concept.

Michael Burr