Segmentation Fault related to Pointer in c [duplicate] - c

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.

Related

Queries on declaring & initialising string and also string memory region [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)
What is the difference between char s[] and char *s?
(14 answers)
Closed 3 years ago.
My question comes in three part.
char str[] = "hello!";
char *str1 = "heello!";
puts(str);
str1[1] = 1
puts(str1);
printf("%s\n", str1);
printf("%p\n", str1);
Ouput of code:
hello!
h1ello!
heello!
0x10735ef9b
1) I understand that when you're declaring a char * type, you're declaring a pointer that points to char type. And usually for pointer, since it contains the address of the variable its pointing to, when you print the pointer itself, you'll get the address stored in the pointer and only when you dereference the pointer, then you'll get the content stored in the variable the pointer is pointing to.
However for a char * type, why is it that it doesn't function like a regular pointer? You can print the content of the variable which the 'char *' pointer is pointing to without dereferencing it and also use it like a string variable(rather than a pointer) by changing the value of the str1[1] as shown above.
2) I was taught that you shouldn't declare a pointer variable as such in the topic of pointer:
char *str1 = "heello!";
because the pointer variable would be pointing to whatever address happens to be in the memory at that time, thus running a risk of changing the value in a memory location that you don't mean to and resulting in segfault.
Hence you should do the following:
char *str1;
char c;
str1 = &c;
*addr = "hello!"
By doing the above, you'll make sure that your pointer is pointing to the right location before dereferencing and writing to the location.
However in the notes on string, it says to declare and initialise as such:
char *str1 = "heello!";
I'm quite confused as to what I should follow now when declaring a char * pointer. Please help.
3) It says in my notes that the location of string is stored in a read only region of the memory called the text region.
Hence doing this:
char *str1 = "hello!";
str[1] = '.';
Will crash your program.
But when you do this:
char str2[7] = "hello!";
str2[1] = '.';
This is okay and will successfully change the second element in the string from 'e' to '.'
The explanation to this was that str1 points to a read only region in the memory, while str2 contains a copy of the string on the stack.
I do not understand how the above 2 different ways of declaring the string variable will make such a big difference when executing the code. Please help.
Thank you!
String literals like "heello!" are really read-only arrays of characters (including the string null-terminator).
With
char *str1 = "heello!";
you make str1 point to the first character of such an array.
And when you do str1[1] = 1 you attempt to modify the read-only array, which is forbidden and leads to undefined behavior (which can but doesn't have to lead to crashes).
That's why you either should use your own arrays for strings, or use const char * to point to literal strings.

Modify a string with pointer [duplicate]

This question already has answers here:
Increment the first byte of a string by one
(3 answers)
Closed 7 years ago.
This two codes have to change the char 2 in the character '4'
int main(int argc, char *argv[]){
char *s = "hello";
*(s+2)='4';
printf( "%s\n",s);
return 0;
}
When I run this I get segmentation fault while when I run this:
int main(int argc, char *argv[]){
char *s = argv[1];
*(s+2)='4';
printf( "%s\n",s);
return 0;
}
I know that there are other methods to do this. What is the difference between the 2 programs?
In your first case, you're facing undefined behaviour by attempting to modify a string literal. A segmentation fault is one of the common side-effects of UB.
In your code,
char *s = "hello";
essentially puts the starting address of the string literal "hello" into s. Now, is you want to modify the content of *s (or *(s+n), provided n does not go out of bounds), it will actually try to modify that string literal. As usually, the string literals are stored in the read-only memory, they are usually not allowed to be modified. Quoting from C11, chapter §6.4.5, String literals, (emphasis mine)
It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined.
However, in your second case, you're doing
char *s = argv[1];
which is putting the value of argv[1] into s. Now, s points to the string contanied by argv[1]. Here, the contents of argv[1] (or, argv[n], to be general) is not read-only, it can be modified. So, using *s (or *(s+n), provided n does not go out of bounds), you can modify the contents.
This case is defined behaviour, because as per §5.1.2.2.2, Program startup
The parameters argc and argv and the strings pointed to by the argv array shall be modifiable by the program, and retain their last-stored values between program startup and program termination.
So, the second case is a special case while using argv[n], which is by the C standard rules, modifiable.
As Sourav said, attempting to modify a string literal invokes undefined behavior. If you alternately did the following, it would work fine.
int main(int argc, char *argv[]){
char s[] = "hello";
*(s+2)='4';
printf( "%s\n",s);
return 0;
}
When you do
char *s = "hello";
you are assigning *s to point to the beginning of a string literal which is non-modifiable. Which means you can read what's there but you can't change it (which is why
*(s+2)='4';
is giving you a segmentation fault.
In your second case, you are not giving your pointer a string literal, so you can modify it.
In fact, in your second case, you are using argvwhich is specifically explained to be modifiable in the c standard.
the literal: 'hello' is in read only memory, so cannot be changed.
Trying to change it causes the seg fault event
Trying to change the array of strings from argv[] has the same problem. The values are readonly
Trying to change a command line argument causes the seg fault event.
You could use: ' char s[] = "hello"; ' as that will put the literal on the stack, where it can be changed.
You could copy 'strcpy()' after getting the length of the command line argument and performing a malloc() for that length+1

Segmentation fault with strcpy() [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 9 years ago.
This works:
int main()
{
char *t = "Hello";
t = "World";
printf("%s", t);
}
But this gives segmentation fault:
int main()
{
char *t = "Hello";
strcpy(t, "World"); // the only difference
printf("%s", t);
}
Why?
Strings that you define explicitly - e.g. "Hello" - are typically placed in an area of read-only memory. These strings cannot be changed.
In the first example, you are not changing the "Hello" string into the "World" string. You are re-assigning t so that it points to "World" instead of "Hello". The "Hello" string is still hanging around, untouched, in read-only memory.
Here's the initial state:
t -> "Hello"
"World"
Here's the second state:
"Hello"
t -> "World"
In the second example, you are trying to overwrite the "Hello" string. This cannot be done.
You should really change your declaration from char *t to const char *t. I think GCC can be configured to enforce this.
The first changes the value of t to point from the address of "Hello" to the address of "World". The second attempts to overwrite the data "Hello" itself.
In the first example the pointer t is made to point to a string constant "Hello", and then immediately afterwards to the string constant "World"; the latter value is then printed.
The code in the second example crashes with segfault, because string constants are not writeable. (strcpy tries to modify the memory that holds the text "Hello"). GCC places string constants into a read-only section, unless compiled with -fwriteable-strings.
The code
char *test = "Hello";
means that the compiler+linker place a string of bytes "Hello\0" in a read-only section, and the test points into the first character thereof. Any attempt to write through this pointer would be harshly punished by the operating system.
On the other hand
char test[] = "Hello";
declares an array of 6 characters, with initial value of ({ 'H', 'e', 'l', 'l', 'o', '\0' }).
Some old programs assumed that string constants are writeable; thus requiring GCC to support compiling those programs with the -fwriteable-strings command line switch.
The assignment t = "World" changes only the pointer, while the strcpy changes the memory to which t points. String literals may live in a read-only segment.
char* t is a pointer. In the first example, you are merely assigning the pointer from one string literal to another: first t pointed to "Hello", then to "World". This is perfectly legal.
However, the string literals themselves are literals--they cannot be changed. Typically they are in a read-only section of memory. In the second example, you are attempting to change what is in the memory allocated to the string literal "Hello" by overwriting it with "World". That is illegal and you will get a segmentation fault.
In char *t="Hello" t assign "Hello" in read only location. So writing to readonly location make segmentation fault.
There is the difference between assigning and copying.
First example you trying to assign the address of another string to t.
In second example you trying to write into readonly location.
use char t[] = "Hello". Here t can be overwrite
more explanation Here
"Hello" is a string constant. It's not meant to be written on, by the definition of constant.
In your first example, 't' is a pointer, and it can point(be assigned) either string constant.

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

Segmentation Fault ++operator on char * [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why does this Seg Fault?
I receive a segmentation fault when using ++ operator on a char *
#include<stdio.h>
int main()
{
char *s = "hello";
printf("%c ", ++(*s));
return 0;
}
But if I do the following:
#include<stdio.h>
int main()
{
char *s = "hello";
char c = *s;
printf("%c ", ++c);
return 0;
}
Then the code compiles perfectly, what is the problem with the above code?
The first code snippet is attempting to modify a character in a string literal as:
++(*s)
is attempting to increment the first character in s. String literals are (commonly) read-only and an attempt to modify will cause the segmentation fault (the C standard states If the program attempts to modify such an array, the behavior is undefined.).
The second snippet is modifying a char variable, which is not read-only as after:
char c = *s;
c is a copy of the first character in s and c can be safely incremented.
In the first case you modify a constant literal, and in the second you modify a variable.
This code:
printf("%c ", ++(*s));
tries to modify a string literal through a pointer to one of its characters. Modifying string literals is undefined behavior - the quite likely outcome is that string literals are often stored in read-only memory, so it's technically illegal to modify them and that's why it manifests itself as segmentation fault on your system.
char *s = "hello";
This implies that 's' is a const string.
If you need a non-const string, you should allocate it explicitly from heap.
You are trying to change a string literal in the first case which is not allowed. In the second case you create a new char from the first character of the string literal. You modify the copy of that character and that is why the second case works.
Your code does not have write permission for the segment where the string literal is stored.

Resources