Search code examples
cundefined-behaviorc-stringsstrcpy

Why strcpy(buffer +i, buffer + i +1) doesn't work in the same way as using a temporay array?


#include <stdio.h>
#include <string.h>

int main() {
    char buffer[200] = "This is a string";
    char buffer1[200];
    strcpy(buffer1, buffer);
    char vowels[] = "aeiouAEIOU";
    int i;

    for (i = 0; i < strlen(buffer); i++) {
        if (strchr(vowels, buffer[i]) != NULL) {
            char tmp[1000];
            strcpy(tmp, buffer + i + 1);
            strcpy(buffer + i, tmp);
            
            strcpy(buffer1 + i, buffer1 + i + 1);
            break;
        }
    }

    printf("buffer=%s\n", buffer); // prints "Ths is a string", which is OK
    printf("buffer1=%s\n", buffer1); // prints "Ths is asstring", which is not OK.
    return 0;
}

I'm trying to remove a character from a string.
In the code below I used to 2 ways to achieve this, with the variables buffer and buffer1. But, one of them, buffer1, prints a weird result.

What makes buffer and buffer1 contain different values?


Solution

  • Using strcpy for overlapping arrays invokes undefined behavior. In such a case you should use memmove.

    From the C Standard (7.23.2.3 The strcpy function)

    1. ... If copying takes place between objects that overlap, the behavior is undefined.

    Here is a demonstration program

    #include <stdio.h>
    #include <string.h>
    
    int main( void )
    {
        char buffer[200] = "This is a string";
        char vowels[] = "aeiouAEIOU";
    
        size_t n = strlen( buffer );
    
        size_t pos = strcspn( buffer, vowels );
    
        memmove( buffer + pos, buffer + pos + 1, n - pos );
    
        puts( buffer );
    }
    

    The program output is

    Ths is a string