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?
Related
#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.
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
I have a function taking two strings string_one and string_two both a pointer to a character.
I thought of a way to add them together:
while (*string_one){
string_one++;
}
*string_one = *string_two;
but I can't see the second string in the output!
How do I add two strings toghether? did I go any close?
When you write
*string_one = *string_two;
you are just copying one character since you are de-referencing a char pointer
to add two strings to one another you need to overwrite the \0 on the first string and then append the characters from the second string (provided you have space enough to do so).
so this
while (*string_one) {
string_one++;
}
*string_one = *string_two;
will only overwrite the \0 with the first character from string_two which will result in the first string will not be null terminated any longer.
instead you should so do something similar again like
while (*string_one) {
string_one++;
}
while (*string_two) {
*string_one++ = *string_two++;
}
*string_one = '\0';
again with the premise that string_one originally pointed to a character string large enough to hold both strings.
Did you try your code at all?
First, you need to make sure that there is enough space for both strings. Concatenating strings and not checking that there is enough space for both is probably the cause of 50% of all hacked computers in the world.
Second, a C string is an array of char with a zero byte as the last char. Your code overwrites the zero byte at the end of string_one with the first char of string_two.
Third, there is a function named strcat in the standard C library doing exactly what you want to do. It doesn't check whether there is enough space, you have to do that before the call.
I'm afraid, your code is not valid.
*string_one = *string_two;
will copy the first element of string_two to string_one. This never adds anything. Moreover, you need to append the complete string, not only one element.
What you need is strcat(). You can find more on that here.
The general description :
The strcat() function appends the src string to the dest string, overwriting the terminating null byte (\0) at the end of dest, and then adds a terminating null byte. The strings may not overlap, and the dest string must have enough space for the result. If dest is not large enough, program behavior is unpredictable.
I have a little problem here with memcpy()
When I write this
char ipA[15], ipB[15];
size_t b = 15;
memcpy(ipA,line+15,b);
It copies b bytes from array line starting at 15th element (fine, this is what i want)
memcpy(ipB,line+31,b);
This copies b bytes from line starting at 31st element, but it also attaches to it the result for previous command i.e ipA.
Why? ipB size is 15, so it shouldnt have enough space to copy anything else. whats happening here?
result for ipA is 192.168.123.123
result for ipB becomes 205.123.123.122 192.168.123.123
Where am I wrong? I dont actually know alot about memory allocation in C.
It looks like you're not null-terminating the string in ipA. The compiler has put the two variables next to one another in memory, so string operations assume that the first null terminator is sometime after the second array (whenever the next 0 occurs in memory).
Try:
char ipA[16], ipB[16];
size_t b = 15;
memcpy(ipA,line+15,b);
ipA[15] = '\0';
memcpy(ipB,line+31,b);
ipB[15] = '\0';
printf("ipA: %s\nipB: %s\n", ipA, ipB)
This should confirm whether this is the problem. Obviously you could make the code a bit more elegant than my test code above. As an alternative to manually terminating, you could use printf("%.*s\n", b, ipA); or similar to force printf to print the correct number of characters.
Are you checking the content of the arrays by doing printf("%s", ipA) ? If so, you'll end up with the described effect since your array is interpreted as a C string which is not null terminated. Do this instead: printf("%.*s", sizeof(ipA), ipA)
Character strings in C require a terminating mark. It is the char value 0.
As your two character strings are contiguous in memory, if you don't terminate the first character string, then when reading it, you will continue until memory contains the end-of-string character.
If I have a pointer that is pointing somewhere in a string, let's say it is pointing at the third letter (we do not know the letter position, basically we don't know it is the third letter), and we want it to point back to the first letter so we can make the string to be NULL how do we do that?
For example:
if we have ascii as a pointer
ascii is pointing now somewhere in the string, and i want it to point at the first char of the string how do i do that?
(Note:
I tried saying
int len = strlen(ascii);
ascii -= len;
ascii = '0';
but it is not working, it changes wherever the pointer is to 0 but not the first char to 0)
You cannot. C and C++ go by the "no hidden costs" rule, which means, among other things, noone else is going to secretly store pointers to beginnings of your strings for you. Another common thing is array sizes; you have to store them yourself as well.
First of all, in your code, if ascii is a pointer to char, that should be
*ascii = '\0';
not what you wrote. Your code sets the pointer itself to the character '0'. Which means it's pointing to a bad place!
Second of all, strlen returns the length of the string you are pointing to. Imagine the string is 10 characters long, and you are pointing at the third character. strlen will return 8 (since the first two characters have been removed from the calculation). Subtracting this from where you are pointing will point you to 6 characters before the start of the string. Draw a picture to help see this.
IMHO, without having some other information, it is not possible to achieve what you are wanting to do.
From what I said above, you should be able to work out what you need to do as long as you keep the original length of the string for example.
No. You, however, can make it point at the last character of the string, which is right before '\0' in every string (it's called zero-terminated string).
What you could do is instead of a char* you could use a pointer to a struct which contains the information you need and the string.
It's not guaranteed to work, but you might get away with backing up until you find a null character, and then moving forward one.
while(*ascii) ascii--;
ascii++;