I’m writing c code using wsl with gcc compiler.And I tried to delete a space in front of a c-string with strcpy and got a strange result.
The string I tried to modify is s = {‘ ‘,’e’,’h’,’c’,’o’ ,”};And I use a pointer temp to point at the "e"in the string and then I use strcpy(s,temp) to delete the space.BUT the result I get is ecoo,not echo.
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(){
char a[256];
a[0] = ' ';
a[1] = 'e';
a[2] = 'h';
a[3] = 'c';
a[4] = 'o';
a[5] = '';
char* temp = a;
temp ++ ;
printf("%sn",temp);
strcpy(a,temp);
printf("%sn",a);
}
I tried to debug in the program and temp is indeed "echo"but the result is ecoo.
The code went as expected in the windows system in visual studio and vscode.
And I also tried different string length and I found out the code went well when the length of the string is 3,7.
enter image description here
3
Answers
Your code is invalid. From https://en.cppreference.com/w/c/string/byte/strcpy :
temp
is equal toa + 1
– they overlap.strcpy(a, a + 1)
is not valid.The C standard says that using
strcpy()
to copy strings that overlap is undefined behaviour.When I compile your code (Clang on macOS, intel 64) I don’t see the same result as you, I see
which suggests it is using some built in function that detects the overlap, probably because the strings are very short.
What you see is an artefact of the way
strcpy
is implemented on your environment. At a guess, I would say it’s copying from the back and stopping when it thinks it has copied all oftemp
characters.Anyway, do not use
strcpy()
on arrays/buffers that overlap.As already mentioned,
strcpy
assumes that the two parameters don’t overlap. In case they do, you invoke undefined behavior. See for exampleman strcpy
.The solution is to use the
memmove
function instead, which is a specialized function to use for the very situation when you do have two memory areas that overlap. It uses an internal temporary buffer to fix that.Therefore replace your
strcpy
call withmemmove(a, temp, strlen(temp)+1);
. Sincememmove
is a general function it knows nothing of strings, therefore we have to add a +1 in the end to tell it to also copy the null terminator (so you get "echo" and not "ehcoo").