Post increment with pointers in while loop in C - c

I am writing the strcat function
/*appends source string to destination string*/
#include <stdio.h>
int main()
{
char srcstr[100], deststr[100];
char *psrcstr, *pdeststr;
printf("\n Enter source string: ");
gets(srcstr);
printf("\n Enter destination string: ");
gets(deststr);
pdeststr = deststr;
psrcstr = srcstr;
while(*pdeststr++)
;
while(*pdeststr++ = *psrcstr++)
;
printf("%s", deststr);
return 0;
}
For srcstr = " world" and deststr = "hello" I get hello, when I expect to see hello world, which is what I see if I change the first while so
while(*pdeststr);
pdeststr++;
why can't I write all in one line in the first while, just like in the second while?

Your one line loop
while(*pdeststr++);
Is equivalent to
while(*pdeststr)
pdeststr++;
pdeststr++;
Because the postincrement operator is executed before the condition is tested, but after the value for the test is determined.
So you could cater for this with
while(*pdeststr++);
pdeststr--;

Mandatory introduction: do not use gets(), use fgets()!.
Your problem is here:
while(*pdeststr++)
;
The side effect of incrementing is carried out in your last iteration step (when pdeststr points to the NUL terminator), so after this loop, pdeststr points one after your NUL terminator. Write it like this instead:
while(*pdeststr) ++pdeststr;

The boolean value for the while condition is computed before the ++ post-increment.
So when your while loop exits, the post-increment operator is executed one last time, hence pdeststr is pointing right after the null terminator char that follows the word "hello".
Then the rest of the program appends more data after that null char. You end up with the string "hello\0world\0". The print function thinks the string ends at the first null char it encounters.

You have an extra incrementation that point you after the NULL char, and so finally you could print only the first string.

By precedence the postfix increment operator (ptr++) is higher than the indirection (dereference) operator (*ptr). Therefore the
while(*pdeststr++);
will always increment the pdeststr first then evaluate the previously pointed value. As an outcome, when the result of evaluation is 0 the pdeststr actually points to the next element, so there will be a null-terminator character ('\0') between your concatenated words.
As a one-liner solution with while loop you can use the short-circuit evaluation as follows:
while(*pdeststr && pdeststr++);
The code snippet above will stop when *foo results 0 and won't evaluate the foo++ part.

My conclusion is that at the end, deststr = "hello\0 world\0" and because of that printf("%s", deststr); find the first \0 and gives as output hello

Related

Is this undefined behaviour ( working with string literal)

#include<stdio.h>
int main()
{
char *s = "Abc";
while(*s)
printf("%c", *s++);
return 0;
}
I have seen this (on a site) as a correct code but I feel this is undefined behavior.
My reasoning:
Here s stores the address of the string literal Abc. So while traversing through the while loop :
Iteration - 1:
Here *(s++) increments the address stored in s by 1 and returns the non-incremented address (i.e the previous/original value of s). So, no problem everything works fine and Abc is printed.
Iteration - 2:
Now s points to a completely different address (which may be either valid or not). Now when trying to perform while(*s) isn't it undefined behavior ?
Any help would be really appreciated!
No. There's no undefined behaviour here.
*s++ is evaluated as *(s++) due to higher precedence of postfix increment operator than the dereference operator. So the loop simply iterates over the string and prints the bytes and stop when it sees the null byte.
Now s points to a completely different address (which may be either valid or not). Now when trying to perform while(*s) isn't it undefined behavior ?
No. In the first iteration s points to the address at the char A and at b in the next and at c in the next. And the loop terminates when s reaches the null byte at end of the string (i.e. *s is 0).
Basically, there's no modification of the string literal. The loop is functionally equivalent to:
while(*s) {
printf("%c", *s);
s++;
}
Iteration - 1:
Here *(s++) increments the address stored in s by 1 and returns the non-incremented address (i.e the previous/original value of s). So, no problem everything works fine and Abc is printed.
No, “Abc” is not printed. %c tells printf to expect a character value and print that. It prints a single character, not a string. Initially, s points to the first character of "Abc". s++ increments it to point to the next character.
Iteration - 2:
Now s points to a completely different address (which may be either valid or not). Now when trying to perform while(*s) isn't it undefined behavior ?
In iteration 2, s is pointing to “b”.
You may have been thinking of some char **p for which *p had been set to a pointer to "abc". In that case, incrementing p would change it to point to a different pointer (or to uncontrolled memory), and there would be a problem. That is not the case; for char *s, s points to a single character, and incrementing it adjusts it to point to the next character.
Now s points to a completely different address
Indeed, it is a completely different but well defined address. s referenced the next char of the string literal. So it just adds 1 to the pointer.
Because string literal is nul (zero) terminated the while loop will stop when s will reference it.
There is no UB.

How to understand strings with pointers

I have been studying the C language for the last few months. I'm using a book and I have this exercise:
char vector[N_STRINGS][20] = {"ola", "antonio", "susana"};
char (*ptr)[20] = vector;
char *p;
while(ptr-vector<N_STRINGS)
{
p = *ptr;
while(*p)
putchar(*p++);
putchar('\n');
ptr++;
}
I understand everything expect the while(*p)! I can't figure out what the while(*p) is doing.
The variable p in your code is defined as a pointer to a char. The get the actual char value that p points to, you need to dereference the pointer, using the * operator.
So, the expression in your while loop, *p evaluates - at the beginning of each loop - to the char variable that p is currently pointing to. Inside the loop, the putchar call also uses this dereference operator but then increments the pointer's value so, after sending that character to the output, the pointer is incremented (the ++ operator) and it then points to the next character in the string.
Conventionally (in fact, virtually always), character strings in C are NUL-terminated, meaning that the end of the string is signalled by having a character with the value of zero at the end of the string.
When the while loop in your code reaches this NUL terminator, the value of the expression *p will thus be ZERO. And, as ZERO is equivalent to a logical "false" in C (any non-zero value is considered "true"), the while loop will end.
Feel free to ask for further clarification and/or explanation.
From the C Standard (6.8.5 Iteration statements)
4 An iteration statement causes a statement called the loop body to be
executed repeatedly until the controlling expression compares equal to
0.
In this part of the program
p = *ptr;
while(*p)
//…
the pointer p points to the first character of a current string. String in C is a sequence of characters terminated by the zero character '\0'.
So let's for example the pointer initially points to the first character of the string "ola". The string is represented in the corresponding character array like
{ 'o', 'l', 'a', '\0' }
The condition in the loop
while(*p)
may be rewritten like
while(*p != 0 )
So the loop will be executed for all characters of the string except the last zero-terminated character and there will be outputted the first three characters of the string.
Pay attention to that (6.5.9 Equality operators)
3 The == (equal to) and != (not equal to) operators are analogous to
the relational operators except for their lower precedence.108) Each
of the operators yields 1 if the specified relation is true and 0 if it
is false. The result has type int. For any pair of operands, exactly
one of the relations is true.

String Concatenation in C with Pointers

So this is the standard string concatenation code in C:
char *stringcat(char *dest, const char *src){
char *save=dest;
while(*save !='\0'){
save++;
}
while(*src!='\0'){
*save=*src;
save++;
src++;
}
*save='\0';
return dest;
}
My question is why when we replace the first while loop with the following:
while(*save++){};
It does not work, but, when replaced with:
while(*++save){};
It does work. In the first two instances, save points to the null terminator at the end of dest at the end, which is then overwritten by the first character in src. However, in the third instance, it seems like save will be pointing to the character after the null terminator, which is weird.
If you make it while (*save++) {}, the operation you are repeating is: load byte, increment pointer, check whether byte was zero. Therefore, what will happen at the end of the string is: load null byte, increment pointer, check whether byte was zero, see it was, exit loop. So save will be pointing just after the null byte. But you want to start copying the second string on top of that null byte, not after it.
(Is it possible that you have the meanings of ++save and save++ interchanged in your head? If so, here's a useful mnemonic: ++save means increment, then load the value; save++ means load the value, then increment. So the order in which the variable name and the ++ appear corresponds to the order of operations.)
while(*save++)
First dereference save and compare that value to 0, then increment save.
while(*save !='\0'){
save++;
}
First dereference save, compare to 0 and only increment if non-zero.
See the difference?

Why can't I access the next element in a string when I increment the pointer by one?

I'm trying to increment a pointer to a string by hand using the dereference operator like I've seen it work in the while loop I have bellow. It works for the first character, but when I try to increment the pointer by hand like it is in the while loop, it doesn't work and I get back garbage. Could someone please tell me what I'm not understanding? This code works the way I expect it.
char *pointToString = "some string or something";
printf("%c\n", *pointToString); // this returns the letter 's'
while(*pointToString != '\0'){
printf("%c", *pointToString);
*pointToString++;
}
This works and prints out 's' and then the string "some string or something", but why can't I access the second element of the string if I increment it by hand? When I do this, I get back garbage.
printf("%c\n", *pointToString+1);
This returns something other than the letter 'o'. I also tried this, but still got garbage:
printf("%c\n", *pointToString+sizeof(char));
I'm not sure if that's correct but I figured that I'm incrementing a pointer like I did in the while loop:
*pointToString++;
So why couldn't I do that by itself?
You cannot access the next element using the expression
printf("%c\n", *pointToString+1);
because the unary operator * has higher precedence than binary +. First, the current character is accessed; then, 1 is added to it. Proper use of parentheses will fix this problem:
printf("%c\n", *(pointToString+1));
Reference: Operator precedence table in C.
From my understanding, this should be your fix:
*(pointToString++); // Iterates first, and then has the pointer point to the correct value
This is what's happening in your one line:
*pointToString++; // Points to the value first and then iterates.
Hope this helps.

How does this example from K and R work [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How does “while(*s++ = *t++)” work?
I was trying to understand the following example. I am a little confused how this would actually work.
void strcpy(char *s, char *t)
{
while (*s++ = *t++)
;
}
Any help is great. Thanks!
Remember that a string in C is just a pointer to a list of chars, terminated with a \0.
Also remember that \0 (the null byte) is falsy, that is, if it's in a condition, that condition will be false.
This function gets a pointer to the start of the source string and one to the start of the destination string.
It then loops over each character in the source string, copying the character to the destination string. When the condition is evaluated, the post-increment ++ will advance the pointer forward a byte.
This implementation also has an issue, as far as I can tell. If the source string isn't the exact same length, it won't have a null terminator at the end. For safety's sake, you should tack a \0 at the end of the destination string.
The value of *s++ = *t++ is the value of the right side of the assignment, *t. So the loop will terminate when *t is 0, i.e., at the end of the string pointed by t. The condition also increments the value of t (and s), after assigning the character pointed by t to the char pointed by s. There is nothing in the loop body, the condition by itself does the copy.

Resources