strcpy behaving differently when two pointers are assigned strings in different ways - c

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.

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.

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)
The line *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 about
str2 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.

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'

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.

Related

How does memory allocation work with char pointers(string literals, arrays)?

Currently reading K&R and just got stumbled across the char pointers. There's nothing about memory allocation when defining char pointers in the book rn, maybe it'll be explained later. But it just doesn't make sense so I'm seeking help :)
1
// No errors
char *name;
char *altname;
strcpy(altname,name);
2
// No errors, internals of *name have been successfully moved to *altname
char *name = "HI";
char *altname;
strcpy(altname, name);
3
// Segmentation fault, regardless of how I define *altname
char *name = "HI";
char *altname = "randomstring";
strcpy(altname, name);
4
// Segmentation fault, regardless of how I define *altname
char *name;
char *altname = " ";
strcpy(altname, name);
5
// copies internals of *name only if size of char s[] > 8???
char s[9];
char n[] = {'c', 'b'};
char *name = n;
char *altname = s;
strcpy(altname, name);
Why does the first example produce no error, even though there's no memory allocated?
Why does the second one successfully copy name to altname, even though there's no memory allocated for altname;
Why do the third and forth one core dump?
Why does the fifth one require size of s as >8?
I'm a bit surprised that the first two examples worked. strcpy takes the character array pointed to by the second argument and copies it to the character array pointed to by the first argument.
In your first example, the pointers name and altname aren't pointing to anything. They're uninitialized pointers. Now they have some value based on either whatever gunk was in memory when the main function was executed or just however the compiler decided to initialize them. That's why I'm surprised that your code isn't crashing.
Anyway, the reason why your third example is segfaulting is you've set both pointers to point to string literals (i.e., "HI" and "randomstring"). String literals are (most likely) stored in a read-only section of memory. So, when you run strcpy with the destination pointer set to altname, you're trying to write to read-only memory. That's an invalid use of memory and hence the crash. The same goes for your fourth example.
In the final example, your problem is that n is not null-terminated. strcpy keeps copying characters until it reaches a terminator (i.e., '\0'). You've put a 'c' and a 'b' in your array but no terminator. Therefore, strcpy is going to keep copying even after it's reached the end of n. The fact that it works when sizeof(s) is greater than 8 probably involves where a null byte happens to exist on your stack. That is, if you make s too small, you'll write past the end of it and corrupt the memory on your stack. It's possible you're overriding your return pointer and thus returning to some invalid memory address when your function is done executing.
What you need to do is, instead of using pointers, use arrays. This will give you the storage space you need in a writable section of memory. You also need to make sure that your arrays are null-terminated. This can be done automatically by initializing your arrays with string literals.
char name[] = "HI";
char altname[] = "randomstring";
strcpy(altname, name);
char s[3]; // Enough space to hold "cb" plus a null-terminator.
char n[] = "cb";
char *name = n;
char *altname = s;
strcpy(altname, name);
All code snippets are undefined behavior. There is no guarantee that you will get an error. As the term says, the behavior is undefined.
In 1 and 2, one or both pointers are uninitialized and may point to memory that may or may not be protected against the programmed access, so you may or may not get an error or program crash.
In 3 and 4 you may get a reproducible segmentation fault because altname points to a string literal "randomstring" or " " which can be read-only, so you are not allowed to overwrite the memory where altname points to. In 4, name is uninitialized, so this might also be the cause of the segmentation fault.
In 5, n is not a valid string that could be used for strcpy. The terminating '\0' is missing. strcpy will (try to) copy everything after the end of n until it finds a '\0'. To fix it use
char n[] = {'c', 'b', '\0'};
or
char n[] = "cb";

C string declaration

I am confused about some basics in C string declaration. I tried out the following code and I noticed some difference:
char* foo(){
char* str1="string";
char str2[7]="string";
char* str3=(char)malloc(sizeof(char)*7);
return str1;
/* OR: return str2; */
/* OR: return str3; */
}
void main() {
printf("%s",foo());
return 0;
}
I made foo() return str1/2/3 one at a time, and tried to print the result in the main. str2 returned something weird, but str1 and str3 returned the actual "string".
1.Now, what's the difference between the three declarations? I think the reason why str2 didn't work is because it is declared as a local variable, is that correct?
2.Then what about str1? If the result remains after the foo() ended, wouldn't that cause memory leak?
3.I'm simply trying to write a function that returns a string in C, and use the value returned by that function for other stuff, which str declaration above should I use?
Thanks in advance!
char* str1="string";
This makes str1 a pointer; it points to the first character of the string literal. You should define it as const, because you're not allowed to modify a string literal:
const char *str1 = "string";
...
char str2[7]="string";
This makes str2 an array of char (not a pointer), and copies the contents of the string literal into it. There's no need to define it as const; the array itself is writable. You can also omit the size and let it be determined by the initializer:
char str2[] = "string";
Then sizeof str2 == 7 (6 bytes for "string" plus 1 for the terminating '\0').
This:
char* str3=(char)malloc(sizeof(char)*7);
is written incorrectly, and it shouldn't even compile; at the very least, you should have gotten a warning from your compiler. You're casting the result of malloc() to type char. You should be converting it to char*:
char *str3 = (char*)malloc(sizeof(char) * 7);
But the cast is unnecessary, and can mask errors in some cases; see question 7.7 and following in the comp.lang.c FAQ:
char *str3 = malloc(sizeof(char) * 7);
But sizeof(char) is 1 by definition, so you can just write:
char *str3 = malloc(7);
malloc() allocates memory, but it doesn't initialize it, so if you try to print the string that str3 points to, you'll get garbage -- or even a run-time crash if the allocated space doesn't happen to contain a terminating null character '\0'. You can initialize it with strcpy(), for example:
char *str3 = malloc(7);
if (str3 == NULL) {
fprintf(stderr, "malloc failed\n");
exit(EXIT_FAILURE);
}
strcpy(str3, "string");
You have to be very careful that the data you're copying is no bigger than the allocated space. (No, `strncpy() is not the answer to this problem.)
void main() is incorrect; it should be int main(void). If your textbook told you to use void main() find a better textbook; its author doesn't know C very well.
And you need appropriate #include directives for any library functions you're using: <stdio.h> for printf(), <stdlib.h> for exit() and malloc(), and <string.h> for strcpy(). The documentation for each function should tell you which header to include.
I know this is a lot to absorb; don't expect to understand it all right away.
I mentioned the comp.lang.c FAQ; it's an excellent resource, particularly section 6, which discusses arrays and pointers and the often confusing relationship between them.
As for your question 3, how to return a string from a C function, that turns out to be surprisingly complicated because of the way C does memory allocation (basically it leaves to to manage it yourself). You can't safely return a pointer to a local variable, because the variable ceases to exist when the function returns, leaving the caller with a dangling pointer, so returning your str2 is dangerous. Returning a string literal is ok, since that corresponds to an anonymous array that exists for the entire execution of your program. You can declare an array with static and return a pointer to it, or you can use malloc() (which is the most flexible approach, but it means the caller needs to free() the memory), or you can require the caller to pass in a pointer to a buffer into which your function will copy the result.
Some languages let you build a string value and simply return it from a function. C, as you're now discovering, is not one of those languages.
char* str1="string";
This creates a pointer to a literal string that will be located on either .data or .text segments and is accessible at all times. Whenever you do something like that, be sure to declare it const, because if you try to modify it, nasty things might happen.
char str2[7]="string";
This creates a local buffer on the stack with a copy of the literal string. It becomes unavailable once the function returns. That explains the weird result you're getting.
char* str3=(char)malloc(sizeof(char)*7);
This creates a buffer on the heap (uninitialized) that will be available until you free it. And free it you must, or you will get a memory leak.
The string literal "string" is stored as a 7-element array of char with static extent, meaning that the memory for it is allocated at program startup and held until the program terminates.
The declaration
char *str1 = "string";
assigns the address of the string literal to str1. Even though the variable str1 ceases to exist when the function exits, its value (the address of the literal "string") is still valid outside of the function.
The declaration
char str2[7] = "string";
declares str2 as an array of char, and copies the contents of the string literal to it. When the function exits, str2 ceases to exist, and its contents are no longer meaningful.
The declaration
char *str3 = (char*) malloc(sizeof(char) * 7);
which can be simplified to
char *str3 = malloc(sizeof *str3 * 7);
allocates an uninitialized 7-byte block of memory and copies its address to str3. When the function exits, the variable str3 ceases to exist, but the memory it points to is still allocated. As written, this is a memory leak, because you don't preserve the value of the pointer in the calling code. Note that, since you don't copy anything to this block, the output in main will be random.
Also, unless your compiler documentation explicitly lists void main() as a legal signature for the main function, use int main(void) instead.

Initializing a string in C [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Difference between char *str=“STRING” and char str[] = “STRING”?
I wrote the following code:
int main()
{
char *str = "hello";
str[0] = 'H';
printf("%s\n", str);
}
This gives me a segmentation fault, I cant understand why.
str is pointer to char not const char. Even if that's the case shouldn't it give a compile error like the following program:
int main()
{
const char *str = "hello";
str[0] = 'H';
printf("%s\n", str);
}
It gives an error: assignment of read-only location *str.
EDIT
If my code places the pointer to a read only location, shouldn't I get a compilation error?
You assign a pointer to a constant string (which comes as a part of your text and is thus not writable memory).
Fix with char str[] = "hello"; this will create a r/w copy of the constant string on your stack.
What you do is a perfectly valid pointer assignment. What the compiler does not know is that in a standard system constant strings are placed in read-only memory. On embedded (or other weird) systems this may be different.
Depending on your system you could come with an mprotect and change the VM flags on your pointer destination to writable. So the compiler allows for this code, your OS does not though.
When you initialize a char * using a literal string, then you shouldn't try to modify it's contents: the variable is pointing to memory that doesn't belong to you.
You can use:
char str[] = "hello";
str[0] = 'H';
With this code you've declared an array which is initialized with a copy of the literal string's contents, and now you can modify the array.
Your code has undefined behavior in runtime. You are attempting to write to a literal string, which is not allowed. Such writes may trigger an error or have undefined behavior. Your specific C compiler has str point to read-only memory, and attempting to write to that memory leads to a segmentation fault. Even though it's not const, the write is still not allowed.
char *str = "hello";
When you declare str as above, it is not guaranteed which part of memory it will be stored. str might be read-only depending on implementation. So trying to change it will cause segmentation fault.
In order to avoid segmentation faullt, declare str as an array of characters instead.
char *str = "hello";
here the string hello is a literal.
string literals are always stored in read only memory.
this is the reason you are getting a segmentation fault when you are trying to change the value at read only memory.
Declaring str as char* reserves memory for the pointer, but not for the string.
The compiler can put the memory for "hello" anywhere he likes.
You have no guarantee that str[i] is writable, so that's why in some compilers this results in a seg fault.
If you want to make sure that the string is in writable memory, then you have to allocate memory using alloc() or you can use
char str[] = "hello";

string manipulations in C

Following are some basic questions that I have with respect to strings in C.
If string literals are stored in read-only data segment and cannot be changed after initialisation, then what is the difference between the following two initialisations.
char *string = "Hello world";
const char *string = "Hello world";
When we dynamically allocate memory for strings, I see the following allocation is capable enough to hold a string of arbitary length.Though this allocation work, I undersand/beleive that it is always good practice to allocate the actual size of actual string rather than the size of data type.Please guide on proper usage of dynamic allocation for strings.
char *str = (char *)malloc(sizeof(char));
scanf("%s",str);
printf("%s\n",str);
1.what is the difference between the following two initialisations.
The difference is the compilation and runtime checking of the error as others already told about this.
char *string = "Hello world";--->stored in read only data segment and
can't be changed,but if you change the value then compiler won't give
any error it only comes at runtime.
const char *string = "Hello world";--->This is also stored in the read
only data segment with a compile time checking as it is declared as
const so if you are changing the value of string then you will get an
error at compile time ,which is far better than a failure at run time.
2.Please guide on proper usage of dynamic allocation for strings.
char *str = (char *)malloc(sizeof(char));
scanf("%s",str);
printf("%s\n",str);
This code may work some time but not always.The problem comes at run-time when you will get a segmentation fault,as you are accessing the area of memory which is not own by your program.You should always very careful in this dynamic memory allocation as it will leads to very dangerous error at run time.
You should always allocate the amount of memory you need correctly.
The most error comes during the use of string.You should always keep in mind that there is a '\0' character present at last of the string and during the allocation its your responsibility to allocate memory for this.
Hope this helps.
what is the difference between the following two initialisations.
String literals have type char* for legacy reasons. It's good practice to only point to them via const char*, because it's not allowed to modify them.
I see the following allocation is capable enough to hold a string of arbitary length.
Wrong. This allocation only allocates memory for one character. If you tried to write more than one byte into string, you'd have a buffer overflow.
The proper way to dynamically allocate memory is simply:
char *string = malloc(your_desired_max_length);
Explicit cast is redundant here and sizeof(char) is 1 by definition.
Also: Remember that the string terminator (0) has to fit into the string too.
In the first case, you're explicitly casting the char* to a const one, meaning you're disallowing changes, at the compiler level, to the characters behind it. In C, it's actually undefined behaviour (at runtime) to try and modify those characters regardless of their const-ness, but a string literal is a char *, not a const char *.
In the second case, I see two problems.
The first is that you should never cast the return value from malloc since it can mask certain errors (especially on systems where pointers and integers are different sizes). Specifically, unless there is an active malloc prototype in place, a compiler may assume that it returns an int rather than the correct void *.
So, if you forget to include stdlib.h, you may experience some funny behaviour that the compiler couldn't warn you about, because you told it with an explicit cast that you knew what you were doing.
C is perfectly capable of implicit casting between the void * returned from malloc and any other pointer type.
The second problem is that it only allocates space for one character, which will be the terminating null for a string.
It would be better written as:
char *string = malloc (max_str_size + 1);
(and don't ever multiply by sizeof(char), that's a waste of time - it's always 1).
The difference between the two declarations is that the compiler will produce an error (which is much preferable to a runtime failure) if an attempt to modify the string literal is made via the const char* declared pointer. The following code:
const char* s = "hello"; /* 's' is a pointer to 'const char'. */
*s = 'a';
results in the VC2010 emitted the following error:
error C2166: l-value specifies const object
An attempt to modify the string literal made via the char* declared pointer won't be detected until runtime (VC2010 emits no error), the behaviour of which is undefined.
When malloc()ing memory for storing of strings you must remember to allocate one extra char for storing the null terminator as all (or nearly all) C string handling functions require the null terminator. For example, to allocate a buffer for storing "hello":
char* p = malloc(6); /* 5 for "hello" and 1 for null terminator. */
sizeof(char) is guaranteed to be 1 so is unrequired and it is not necessary to cast the return value of malloc(). When p is no longer required remember to free() the allocated memory:
free(p);
Difference between the following two initialisations.
first, char *string = "Hello world";
- "Hello world" stored in stack segment as constant string and its address is assigned to pointer'string' variable.
"Hello world" is constant. And you can't do string[5]='g', and doing this will cause a segmentation fault.
Where as 'string' variable itself is not constant. And you can change its binding:
string= "Some other string"; //this is correct, no segmentation fault
const char *string = "Hello world";
Again "Hello world" stored in stack segment as constant string and its address is assigned to 'string' variable.
And string[5]='g', and this cause segmentation fault.
No use of const keyword here!
Now,
char *string = (char *)malloc(sizeof(char));
Above declaration same as first one but this time you are assignment is dynamic from Heap segment (not from stack)
The code:
char *string = (char *)malloc(sizeof(char));
Will not hold a string of arbitrary length. It will allocate a single character and return a pointer to char character. Note that a pointer to a character and a pointer to what you call a string are the same thing.
To allocate space for a string you must do something like this:
char *data="Hello, world";
char *copy=(char*)malloc(strlen(data)+1);
strcpy(copy,data);
You need to tell malloc exactly how many bytes to allocate. The +1 is for the null terminator that needs to go onto the end.
As for literal string being stored in a read-only segment, this is an implementation issue, although is pretty much always the case. Most C compilers are pretty relaxed about const'ing access to these strings, but attempting to modify them is asking for trouble, so you should always declare them const char * to avoid any issues.
That particular allocation may appear to work as there's probably plenty of space in the program heap, but it doesn't. You can verify it by allocating two "arbitrary" strings with the proposed method and memcpy:ing some long enough string to the corresponding addresses. In the best case you see garbage, in the worst case you'll have segmentation fault or assert from malloc or free.

Why does strcpy fail with char *s but not with char s[1024]?

Why does the following happen:
char s[2] = "a";
strcpy(s,"b");
printf("%s",s);
--> executed without problem
char *s = "a";
strcpy(s,"b");
printf("%s",s);
--> segfault
Shouldn't the second variation also allocate 2 bytes of memory for s and thus have enough memory to copy "b" there?
char *s = "a";
The pointer s is pointing to the string literal "a". Trying to write to this has undefined behaviour, as on many systems string literals live in a read-only part of the program.
It is an accident of history that string literals are of type char[N] rather than const char[N] which would make it much clearer.
Shouldn't the second variation also allocate 2 bytes of memory for s and thus have enough memory to copy "b" there?
No, char *s is pointing to a static memory address containing the string "a" (writing to that location results in the segfault you are experiencing) whereas char s[2]; itself provides the space required for the string.
If you want to manually allocate the space for your string you can use dynamic allocation:
char *s = strdup("a"); /* or malloc(sizeof(char)*2); */
strcpy(s,"b");
printf("%s",s); /* should work fine */
Don't forget to free() your string afterwards.
Altogather a different way/answer : I think the mistake is that you are not creating a variable the pointer has to point to and hence the seg fault.
A rule which I follow : Declaring a pointer variable will not create the type of variable, it points at. It creates a pointer variable. So in case you are pointing to a string buffer you need to specify the character array and a buffer pointer and point to the address of the character array.

Resources