Reputation: 101
I am sorry, I might me asking a dumb question but I want to understand is there any difference in the below assignments? strcpy works in the first case but not in the second case.
char *str1;
*str1 = "Hello";
char *str2 = "World";
strcpy(str1,str2); //Works as expected
char *str1 = "Hello";
char *str2 = "World";
strcpy(str1,str2); //SEGMENTATION FAULT
How does compiler understand each assignment?Please Clarify.
Upvotes: 1
Views: 864
Reputation: 144695
There seems to be some confusion here. Both fragments invoke undefined behaviour. Let me explain why:
char *str1;
defines a pointer to characters, but it is uninitialized. It this definition occurs in the body of a function, its value is invalid. If this definition occurs at the global level, it is initialized to NULL
.
*str1 = "Hello";
is an error: you are assigning a string pointer to the character pointed to by str1
. str1
is uninitialized, so it does not point to anything valid, and you channot assign a pointer to a character. You should have written str1 = "Hello";
. Furthermore, the string "Hello"
is constant, so the definition of str1
really should be const char *str1;
.
char *str2 = "World";
Here you define a pointer to a constant string "World"
. This statement is correct, but it would be better to define str2
as const char *str2 = "World";
for the same reason as above.strcpy(str1,str2); //Works as expected
NO it does not work at all! str1
does not point to a char
array large enough to hold a copy of the string "World" including the final '\0'
. Given the circumstances, this code invokes undefined behaviour, which may or may not cause a crash.You mention the code works as expected: it only does no in appearance: what really happens is this: str1
is uninitialized, if it pointed to an area of memory that cannot be written, writing to it would likely have crashed the program with a segmentation fault; but if it happens to point to an area of memory where you can write, and the next statement *str1 = "Hello";
will modify the first byte of this area, then strcpy(str1, "World");
will modify the first 6 bytes at that place. The string pointed to by str1
will then be "World", as expected, but you have overwritten some area of memory that may be used for other purposes your program may consequently crash later in unexpected ways, a very hard to find bug! This is definitely undefined behaviour.
The second fragment invokes undefined behaviour for a different reason:
char *str1 = "Hello";
No problem, but should be const
.char *str2 = "World";
OK too, but should also be const
.strcpy(str1,str2); //SEGMENTATION FAULT
of course it is invalid: you are trying to overwrite the constant character string "Hello"
with the characters from the string "World"
. It would work if the string constant was stored in modifiable memory, and would cause even greater confusion later in the program as the value of the string constant was changed. Luckily, most modern environemnts prevent this by storing string constants in a read only memory. Trying to modify said memory causes a segment violation, ie: you are accessing the data segment of memory in a faulty way.You should use strcpy()
only to copy strings to character arrays you define as char buffer[SOME_SIZE];
or allocate as char *buffer = malloc(SOME_SIZE);
with SOME_SIZE
large enough to hold what you are trying to copy plus the final '\0'
Upvotes: 2
Reputation: 54031
Sorry, both examples are very wrong and lead to undefined behaviour, that might or might not crash. Let me try to explain why:
str1
is a dangling pointer. That means str1
points to somewhere in your memory, writing to str1
can have arbitrary consequences. For example a crash or overriding some data in memory (eg. other local variables, variables in other functions, everything is possible)*str1 = "Hello";
is also wrong (even if str1
were a valid pointer) as *str1
has type char
(not char *
) and is the first character of str1
which is dangling. However, you assign it a pointer ("Hello"
, type char *
) which is a type error that your compiler will tell you aboutstr2
is a valid pointer but presumably points to read-only memory (hence the crash). Normally, constant strings are stored in read-only data in the binary, you cannot write to them, but that's exactly what you do in strcpy(str1,str2);
.A more correct example of what you want to achieve might be (with an array on the stack):
#define STR1_LEN 128
char str1[STR1_LEN] = "Hello"; /* array with space for 128 characters */
char *str2 = "World";
strncpy(str1, str2, STR1_LEN);
str1[STR1_LEN - 1] = 0; /* be sure to terminate str1 */
Other option (with dynamically managed memory):
#define STR1_LEN 128
char *str1 = malloc(STR1_LEN); /* allocate dynamic memory for str1 */
char *str2 = "World";
/* we should check here that str1 is not NULL, which would mean 'out of memory' */
strncpy(str1, str2, STR1_LEN);
str1[STR1_LEN - 1] = 0; /* be sure to terminate str1 */
free(str1); /* free the memory for str1 */
str1 = NULL;
EDIT: @chqrlie requested in the comments that the #define
should be named STR1_SIZE
not STR1_LEN
. Presumably to reduce confusion because it's not the length in characters of the "string" but the length/size of the buffer allocated. Furthermore, @chqrlie requested not to give examples with the strncpy
function. That wasn't really my choice as the OP used strcpy
which is very dangerous so I picked the closest function that can be used correctly. But yes, I should probably have added, that the use of strcpy
, strncpy
, and similar functions is not recommended.
Upvotes: 3
Reputation: 781
Both code are wrong, even if "it works" in your first case. Hopefully this is only an academic question! :)
First let's look at *str1
which you are trying to modify.
char *str1;
This declares a dangling pointer, that is a pointer with the value of some unspecified address in the memory. Here the program is simple there is no important stuff, but you could have modified very critical data here!
char *str = "Hello";
This declares a pointer which will point to a protected section of the memory that even the program itself cannot change during execution, this is what a segmentation fault means.
To use strcpy(), the first parameter should be a char array dynamically allocated with malloc(). If fact, don't use strcpy(), learn to use strncpy() instead because it is safer.
Upvotes: 1
Reputation: 5550
Edit: In the first snippet you wrote *str1 = "Hello"
which is equivalent to assigning to str[0]
, which is obviously wrong, because str1
is uninitialized and therefore is an invalid pointer. If we assume that you meant str1 = "Hello"
, then you are still wrong:
According to C specs, Attempting to modify a string literal results in undefined behavior: they may be stored in read-only storage (such as .rodata) or combined with other string literals so both snippets that you provided will yield undefined behavior.
I can only guess that in the second snippet the compiler is storing the string in some read-only storage, while in the first one it doesn't, so it works, but it's not guaranteed.
Upvotes: 3