Initializing a string in C [duplicate] - c

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";

Related

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

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.

Segmentation Fault while using tolower() on dynamic arrays [duplicate]

This question already has answers here:
Why do I get a segmentation fault when writing to a "char *s" initialized with a string literal, but not "char s[]"?
(19 answers)
Closed 8 years ago.
I put this code on my C compiler (Dev Cpp).
char *str = "SomeTHing";
for(int i = 0; str[i]; i++){
str[i] = tolower(str[i]);
}
This gives a segmentation fault whereas if i use a static array,
char str[10] = "SomeTHing";
the loop works fine. Can anyone tell why is this happening?
char *str = "SomeTHing"; allocates read-only memory to the pointer str. To change its contents in any way is undefined behaviour. On your system that is manifesting itself as a crash. It's a pity that (i) your compiler is not warning you about your assigning this to a char* rather than a const char* or (ii) you're ignoring the warning.
char str[10] = "SomeTHing"; allocates the buffer on the stack, including the null terminator. Changing its contents is defined, although you need to keep a null terminator intact if you want to use some of the string library functions like strlen that rely on it.
char *str = "SomeTHing";
will place SomeTHing in the read-only parts of the memory and making str a pointer to that, making any writing operation on this memory illegal. Any try to modification this cause Undefined Behaviour.
Now following case
char str[10] = "SomeTHing";
this is working because puts the literal string in read-only memory and copies the string to newly allocated memory on the stack. it will probably be stored within an "initialized data segment" that is loaded from the executable file into write able memory when the program is run.

Segmentation Fault related to Pointer in c [duplicate]

This question already has answers here:
Segmentation fault with strcpy() [duplicate]
(7 answers)
Closed 9 years ago.
int main()
{
char *s="Hello";
*s="World";
printf("%s\n",s);
}
Why does the above program result in a segmentation fault?
int main()
{
char *s="Hello"; // makes 's' point to a constant
*s="World"; // modifies what 's' points to
printf("%s\n",s);
}
The first line of code makes s point to a constant. The second line tries to modify what s points to. So you are trying to modify a constant, which you can't do because a constant is ... well ... constant.
because *s is a char not a char*(string)
char *s="Hello";
declares a pointer to a string literal "Hello". This may exist in read-only memory so the line
*s="World";
is results in undefined behaviour. A crash is a valid (and useful) form of undefined behaviour.
Either of the following alternatives would work
const char* s = "Hello";
s="World";
printf("%s\n",s);
char s[16] = "Hello";
strcpy(s, "World";)
printf("%s\n",s);
s points to static (global) memory when it is created. You cannot reassign to that memory at run-time, hence, the crash.
*s is the first char of the string, so assigning string to character makes error.
If you want to assing string use s = "world"
int main()
{
char *s="Hello";
s="World";
printf("%s\n",s);
}
now try it will work.
char *s="hello"; Here s is in readonly location. So we can assign another string, but cannot rewrite new string.
s = "hello"; //work
strcpy(s, "hello"); //segmentation fault
There are two problems here.
The statement
*s = "World";
dereferences s, which gives you the first character of the string "Hello", or 'H'. So you're trying to assign a pointer value (the address of the string "World") to a single char object (the first character of the "Hello" string literal).
But...
On some systems (such as yours, apparently), string literals are stored in a read-only data segment, and attempting to modify read-only memory will lead to a runtime error on some systems. Hence the crash.
To change s to point to the "World" string literal, simply drop the dereference:
s = "World";
*s is the same as s[0]. s[0] has room to store a single character; in this case a 'W'.
There's not room to store the location of "World" in that character.
That's why you're getting a segmentation fault.

Pointers and Strings causing segmentation fault [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What is the difference between char a[] = “string”; and char *p = “string”;
char *str = "Hello";
printf("%c",++*str);
This gives segmentation fault on linux with gcc.
The moment the first statement is changes to as
char str[10] = "Hello";
It works. What may be the reason?
It is undefined behaviour to attempt to modify a string literal.
The compiler is free to place it in read-only memory (as it probably does in your case). Attempting to modify read-only memory is what's probably triggering the segfault.
This statement char *str = "Hello"; stores the string "Hello" in RO-section and assigns the address of the area of RO-section(in which "Hello"is stored) to str. The data stored in RO-section cannot be modified thus you are getting a segfault.
char str[10] = "Hello";
is also wrong. You should instead write
char str[10];
strncpy(str,"Hello",sizeof(str));

Static C string allocation question

Consider the following code:
char* str = "Hello World";
memcpy(str, "Copy\0", 5);
A segmentation fault occurs during the memcpy. However, using this code:
char str[12];
memcpy(str, "Hello World\0", 12);
memcpy(str, "Copy\0", 5);
The program does not produce a segmentation fault.
Does the problem arise from allocating the memory on the stack versus the data section?
When you use a string literal in gcc the value is placed in read-only memory and cannot be modified. Trying to modify it leads to undefined behaviour. Usually you will get a segmentation fault on Linux when you try to do this.
The second example works because you aren't modifying the string literal, you are modifying a copy of it that is stored in variable that is not read-only.
char* str = "Hello World";
and
char str[12];
are two very different things. One allocates a pointer on the stack and an array in read-only "code segment". The pointer then points at the array. The other allocates the entire array on the stack, and there is no pointer.

Resources