'\0' related issue - c++

Looking at this loop that copies one c-string to another:
void strcpyr(char *s, char *t)
{
while(*s++=*t++)// Why does this work?
;
}
Why do we not check for the '\0' character in the while loop, like this?
while((*s++=*r++)!='\0')..
How does the first loop terminate?

The statement *s++=*t++ not only assigns the next character from t to s but also returns the current value of *t as the result of the expression. The while loop terminates on any false value, including '\0'.
Think of it this way. If you did:
char c = *s++ = *t++;
in addition to copying a char from *t to *s and incrementing both, it would also set c to the current value of *t.

When we hit the '\0' in the string initially pointed to by t, the *s++=*t++, which does the assignment, also returns the value that's assigned to the position pointed to by s, or '\0', which evaluates to false and terminates the loop.
In your second example, you explicitly rely on the fact that the assignment returns the assigned character, while the first example implicitly uses this fact (and the fact that the 0 character (also written '\0') is considered to be false, while all other characters evaluate to true, so the expression c != '\0' will yield the same result as c.

The loop is going to terminate because '\0' is effectively 0, and the what the "while" is evaluating is not a the result of an equality test (==), but the right-value of the assignment expression.

The reason we are not explicitly checking for zero is that in C 0 is false.
Therefore the loop
while(*s++=*t++)
;
will terminate when the character pointed to by t is 0.
-Adam

I think you mean to write this:
void strcpyr(char *s, char *t) {
while (*s++ = *t++);
}
The loop terminates when the value pointed to by "t" is zero. For C (and C++) loops and conditionals, any integer that is non-zero is true.

The while loop is testing the result of the assignment.
The result of an assignment is the value assigned into the left-hand side of the statement. On the last iteration, when *t == '\0', the '\0' is assigned into s, which becomes the value the while loop considers before deciding it is time to quit.

In C, a=b is actually an expression which is evaluated as 'b'. It is easier to write:
if(a=b) {
//some block
}
then:
a=b;
if(a!=0) {
//some block
}
In C language within if, while, for statement the check that is made is: is expression not zero?

Related

Explanation of the Function that Defines strlen

I'm learning about pointers in c++.
I have researched and found the manual function that defines strlen to be something like this.
int strlen(const char *a){
const char *b;
for (b=a;*b;++b);
return b-a;
}
Would anyone be able to explain this block of code in plain english? In particular, why is *b set as the terminating condition in the for loop?
This is not an answer to homework. It's just a question that arose while I was researching. Thanks.
This is a particularly terse piece of C code, with a for loop that does not have a body.
The idea is to set pointer b to the beginning of the string a, and keep advancing it until you hit character '\0', which indicates the end of the stirng (i.e. serves as null terminator). Nothing else needs to be done in that loop, hence its body is empty.
Once the loop is over, subtracting a from b yields the number of characters between the initial character of the string and its null terminator, i.e. the length of the string.
Here is a more readable way to write the same loop:
for (b=a ; *b != '\0' ; ++b) // Use explicit comparison to zero
; // Put semicolon on a separate line
When C expression is used in a statement that requires a logical expression, an implicit comparison to zero is applied. Hence, *b != '\0' is the same as *b.
In both C and C++ strings are really called null terminated byte strings. That null terminator is equal to zero. And in both C and C++ the value zero is equivalent to false.
What the loop does is to iterate until the "current character" (pointed to by b) becomes equal to the terminator.

pointers and increment operator

I have the following simple code:
#include<iostream>
const char str[]={'C','+','+'};
int main()
{
const char *cp=str;
std::cout<<*str<<std::endl;
while (*cp++>0)
std::cout<<*cp;
}
can't understand why it prints
C
++
Shouldn't the postfix increment operator evaluate the expression but return the value unchanged? (I double checked precedence of increment, dereference and relational operators and it should work)
This line prints: C and the carriage return.
std::cout<<*str<<std::endl;
Then you are looping on following characters but there is no ending character (c.f. buffer overflow)
Here's the code fixed up.
#include <iostream>
const char str[]={'C','+','+', '\0'};
int main()
{
const char* cp = str;
std::cout<< *str << std::endl;
while (*cp++ > 0)
std::cout << *cp;
return 0;
}
This code is even simpler if you want to display "C++"
#include <iostream>
const char str[]={'C','+','+', '\0'};
int main()
{
const char* cp = str;
while (*cp > 0)
std::cout << *cp++;
std::cout << std::endl;
return 0;
}
Your problem is here:
while (*cp++>0)
std::cout<<*cp;
The postfix operator increments the value after the expression it was used in is evaluated. There are two different expressions referring to cp in this while statement though: the first one tests and increments, but the second one prints. Since the second one is a separate statement, the increment has already happened by then.
i.e. you currently test against 'C', then increment regardless of the result, then print '+' through the now-incremented pointer. If it were iterating a string literal, this code would also increment once after reaching the 0, although you don't see a result of that because it skips the print (because it iterates over a hand-created array with no null terminator, what it actually does here is fall off the end and exhibit undefined behaviour; this is a big error in itself, you can't rely on there being a zero at the end if one wasn't put there).
shouldn't the postfix increment operator evaluate the expression but return the value unchanged?
No, postfix operator returns the value of operand first then, only it is increased by 1.
here,
while (*cp++>0)
std::cout<<*cp;
by the time it reaches std::cout<<*cp; the value of cp is incremented, and hence the result ++.
In the line
while(*cp++>0)
The post increment operator is executed, after the evaluation happens.
i.e. cp points to C during the first evaluation of the while condition.
So,
*cp => 'C' which is greater than 0.
Before moving to the next line (Inside the loop), the post increment operator gets executed, making cp point to the first +
After + is printed, the while condition is executed again, this time *cp returns '+'. since '+' > 0, the control enters the loop for the second time.
Before entering the loop, the post increment operator executes again, making cp point to the second '+', which is printed.
Now, while condition is executed for the third time. Here, *cp returns +. Thus, control enters the loop again.
Before entering the loop, post increment executes again. This time, it makes cp point to the next character, which is \0.
The \0 is printed, which makes no difference in this code. Then, when the while condition executes again, *cp returns \0, which is not > 0. So, the condition fails.
Edit: Saw in the comments that you wanted to print the entire String in the same line. Change the loop to:
while(*cp > 0)
std:cout<<*cp++;

Str[i] auto boolean check in the for loop

printArrayWithoutLength(char str [])
{
for(int i=0;str[i];i++)
cout<< str[i]<< endl;
}
Why does the above work? I am not using a boolean check on the length.
In C, any condition that isn't a direct boolean expression (that is, some other type than boolean and doesn't involve a comparison operator [>, <, ==, !=, etc]) will automatically compare as a not equal to zero, so you could rewrite your code as:
for(int i=0;str[i] != 0;i++)
or
for(int i=0;str[i] != '\0';i++)
or
for(int i=0; 0 != str[i]; i++)
with exactly the same result and exactly the same code being generated. Just a bit more or less typing, and depending on the familiarity with C or C++, you may find that it's more or less easy to read one over another.
Of course, this only works for traditional C-style strings that are terminated with a nul-character (character with the value zero). There are other ways to store strings, and this code, in whichever form would naturally not work if the string is not actually terminated with a zero character.
Writing str[i] as a conditional expression of for is equivalent to str[i] != '\0' (your string should be null terminated). When str[i] becomes \0, loop will terminate.
Whether this function (without return type)
printArrayWithoutLength(char str [])
{
for(int i=0;str[i];i++)
cout<< str[i]<< endl;
}
will or will not work depends on what the array used as the argument contains. If it contains a string that is a sequence of characters terminated by zero then this function will work because inside the loop there is condition
str[i]
that will be equal to false if the value of str[i] contains zero for some i.
According to the C++ Standard (4.12 Boolean conversions [conv.bool])
1 A prvalue of arithmetic, unscoped enumeration, pointer, or pointer
to member type can be converted to a prvalue 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.
Otherwise if the array does not contain a string the behaviour of the function is undefined.

C++ interview function [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How does “while(*s++ = *t++)” work?
I had the following question during an interview. Can someone please explain it to me?
void question( char *s, char *t)
{
while (*s++ = *t++);
}
It introduces a massive security vulnerability into your program. Do not write, or use, code like this under any circumstances.
If we break the code down, we get:
*t++ reads the character pointed to by t, and increments t; the expression's value is the character that was read.
*s++ = expression writes that character to where s points, and increments s; the expression's value is the character that was written.
while (expression); keeps looping as long as the expression's value is non-zero; in this case, until we wrote a character with the value zero.
So the function keeps copying characters from t to s until it reaches a zero-valued character. There is no way to tell whether s points to a large enough array to hold these, so in general it will write beyond the end of the array and cause undefined behaviour; anything from subtle behaviour with no unwanted effects, to a crash, to the execution of malicious code.
You can only call this function if you know in advance (an upper bound for) how many characters will be copied; if you know that, then there are (usually) more efficient ways to copy the data than to check the value of each. Therefore, you should (almost) never use this function, or the C library function (strcpy) that it approximates.
This use of a zero-valued character to terminate a string is a common idiom in C; in C++ it is usually more convenient to use the std::string class to represent strings instead. In that case, the equivalent code would be simply s = t, which would manage the strings' memory safely.
Copies the string, pointer by t to the memory, pointed by s.
operator= will return the assigned value. t is supposed to point to a NULL-terminated string and s should point to memory, large enough to store that string.
So, the while loop will stop when \0 is hit, which is the end of the string, pointed by t. During this while loop, all chars (different from \0) in t will be copied into s.
Expanded a little, it's the same as:
while( *t != '\0' ) // while the current char is not NULL
{
*s = *t; // copy it into s
++s; // increment s, to point to the next byte
++t; // increment t, to point to the next char, that will be copied
}
*s = *t; // copy the last char of t - the '\0'
It copies null-terminated string t into s. Semantics as strcpy.

Testing conditions using Character pointers

int main()
{
char *p,c;
for(p="Hello World";c=*p;++p)
{
printf("%c",c);
}
}
In the above code,i know that ++p will make pointer 'p' point to next character in the "Hello World".And i also know that there is no boundary checking performed on arrays in C or C++.The output of the program is 'Hello World'. How am i able to test conditions using
c=*p;
What does 'c=*p' return.As far as my understanding goes, when '++p' reaches the end of the 'hello world', pointer 'p' should point to some garbage value and the loop should print some garbage values.
c=*p; doesn't return anything, it's an expression. The for loop evaluates the value of c after the assignment.
when '++p' reaches the end of the 'hello world', pointer 'p' should point to some garbage value
Not really. Before reaching the end, it reaches the null terminating character - '\0'. Which is 0. Which is assigned to c and evaluates the break condition to false. So the loop finishes before it goes out of bounds.
C strings are by definition terminated by a NULL character '\0', if it is a string then it has to end it in a NULL. therefore c = *p will point to a NULL character when the string ends, which is in your case the immediately next character of 'd'. And the NULL character in the ASCII table has an integer value 0, which evaluates to false and gets out of the for loop.
Note that if a C string does not end in a NULL character (then at first it is not a C string), then basically there is no way of detecting that it is a string, as it will be stores as a sequence of bytes. In that case it will be simply a byte array or a string, will depend on how we interpret.
Also not that c = *p does not return anything, it is an expression and it is evaluated. e = *p transfers the value pointed by the current value of p into the var c, the value of which is the final evaluation of the expression.
Strings are terminated by a null character (aka with \0), so then at the end p should point to the null character that terminates the string, thus c would be \0 which is considered a false condition.