-4

I don't understand why str1 is changing here. Please help.

#include<stdio.h>
#include<string.h>
int main (){
    char str1[]="stackoverflowwwwwww";//str1
    char str2[] = "stackoverflow";
    char str3[40];
    char str4[40];
    char str5[] = "asdfgh";
    strcpy(str2, str1);
    strcpy(str3, "successful");
    strcpy(str4, str5);
    printf("str1: %s\nstr2: %s\nstr3:%s\nstr4:%s\n", str1, str2, str3, str4);
    return 0;
}

output is:

str1: www
str2: stackoverflowwwwwww
str3: successful
str4: asdfgh

Why is str1 changing here?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
sudhi
  • 1
  • 6
    You're invoking *undefined behavior*. `strcpy(str2, str1);` How large is that target buffer? The answer to your question is the answer to *that* question. – WhozCraig Aug 19 '18 at 06:38
  • 1
    @Cplusminus_is_coming Can you support that expectation with a quote from its specification (e.g. https://en.cppreference.com/w/c/string/byte/strcpy) ? Or are you thinking of strncpy with appropriate parameters? – Yunnosch Aug 19 '18 at 06:45
  • 1
    Could you provide the value of the address difference str1-str2 in your environment? Either use a debugger or print the pointer values. – Yunnosch Aug 19 '18 at 06:48
  • 2
    If you're genuinely curious why this happens *in your specific circumstance*, use your debugger. There is no *defined* reason as far as the language is concerned. You left the safety of that reservation as soon as you invoked undefined behavior. – WhozCraig Aug 19 '18 at 06:53
  • @artm: If you remove the C++ tag, you should also edit the title. – Jonathan Leffler Aug 19 '18 at 06:57
  • [`strcpy` is not safe](https://stackoverflow.com/q/23317646/995714). Here you're writing beyond the destination buffer's size – phuclv Aug 19 '18 at 07:25
  • 1
    use `[40]` instead of `[]` .`strcpy` is safe enough – Алексей Неудачин Aug 19 '18 at 08:49

3 Answers3

2

Your program contains a buffer overflow. str2 is a buffer, its size is 14bytes (the length of "stackoverflow" + the terminating NULL character). When you execute strcpy(str2, str1) you are overflowing that buffer since str1 is longer than 14bytes. strcpy has no way of knowing the size of the buffer, so (by its definition) it blindly copies from one buffer to the other.

Buffer overflow on the stack

Now, why does this alter str1? Well, because when strcpy copies more chars than the destination buffer's size, these chars must go somewhere. Since both str2 and str1 are allocated on the stack, they are placed right next to each other. So, when strcpy copies onto str2 and overflows its size, it will move on to whatever's next to it in the memory - in your case that's str1.

So, the last characters strcpy is copying - the last few characters in str1 - are copied back onto the beginning of str1.

Neowizard
  • 2,981
  • 1
  • 21
  • 39
2

First of all, the destination str2 is shorter than string length str1 therefore this is an undefined behaviour.

But to understand why this happens, consider the following.

When I print out the memory addresses of the string, before any modification of your code in my system it is like this.

printf("str1: %p (%d)  \nstr2: %p (%d)\n", str1, strlen (str1),  str2, strlen (str2));

str1: 0x7ffd394e85d0 (19)  
str2: 0x7ffd394e85c2 (13)
str1: wwwww
str2: stackoverflowwwwwww
str3:successful
str4:asdfgh

Note the address of str1 and str2. str2 starts first (lower address) and 0x7ffd394e85d0 - 0x7ffd394e85c2 = e, which is 13 in decimal, the exact length of the string.

Therefore the initial layout is

Initial layout
0x7ffd394e85c2               0x7ffd394e85d0
str2                         str1
|                            | 
|                            |
V                            V
s t a c k o v e r f l o w \0 s t a c k o v e r f l o w w w w w w w \0

When the string is being copied from str1 to str2, strcpy will align and copy strings as follows. Here the end of str2 buffer gets violated.

When being copied
0x7ffd394e85c2               0x7ffd394e85d0
str2                         str1
|                            | 
|                            |
V                            V
s t a c k o v e r f l o w \0 s t a c k o v e r f l o w w w w w w w \0
s t a c k o v e r f l o w w  w w w w w \0

After copy the state is as follows

After copy
0x7ffd394e85c2              0x7ffd394e85d0
str2                        str1
|                           | 
|                           |
V                           V
s t a c k o v e r f l o w w w w w w w \0 v e r f l o w w w w w w w \0

Now str1 points to the beginning of the buffer starting with a 'w' and it has five consecutive 'w's until it reaches '\0'. Therefore the C string pointed by str1 now is "wwwww", as you see in your output.

Note that this is for my system where I get five consecutive 'w's. In other systems, the compiler may generate code which has a few blank bytes between the end of str2 and the beginning of str1, therefore they can have a varying number of 'w's. Also, note that, as this is an undefined behaviour, and the storage layout of the two strings are not defined, the output can be anything.

phoxis
  • 60,131
  • 14
  • 81
  • 117
0

The result of this program is unknown, maybe various,because: str3 and str4 are used without initialized, you had better initialize like this:

char str3[40] = {0};
char str4[40] = {0};

So, the borders which obey the size 40 will be under control of a programmer.

Obviously, the space of str2 cause problems if execute 'strcpy(str2, str1);'

asdf
  • 221
  • 1
  • 10