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.
Related
This question already has answers here:
What is the difference between char s[] and char *s?
(14 answers)
Closed 5 years ago.
A string constant in C can be initialized in two ways: using array and a character pointer;
Both can access the string constant and can print it;
Coming to editing part, if I want to edit a string that is initialized using arrays, it is straight forward and we can edit using array individual characters.
If I want to edit a string that is initialized using character pointer, is it impossible to do?
Let us consider the following two programs:
Program #1:
#include<stdio.h>
void str_change(char *);
int main()
{
char str[] = "abcdefghijklm";
printf("%s\n", str);
str_change(str);
printf("%s\n", str);
return 0;
}
void str_change(char *temp)
{
int i = 0;
while (temp[i] != '\0') {
temp[i] = 'n' + temp[i] - 'a';
i++;
}
}
Program #2:
#include<stdio.h>
void str_change(char *);
int main()
{
char *str = "abcdefghijklm";
printf("%s\n", str);
str_change(str);
printf("%s\n", str);
return 0;
}
void str_change(char *temp)
{
int i = 0;
while (temp[i] != '\0') {
temp[i] = 'n' + temp[i] - 'a';
i++;
}
}
I tried the following version of function to program #2, but of no use
void str_change(char *temp)
{
while (*temp != '\0') {
*temp = 'n' + *temp - 'a';
temp++;
}
}
The first program is working pretty well,but segmentation fault for other, So, is it mandatory to pass only the string constants that are initialized using arrays between functions, if editing of string is required?
So it is mandatory to pass only the string constants that are initialized using arrays between functions, if editing of string is requiredc?
Basically, yes, though the real explanation is not these exact words. The following definition creates an array:
char str[] = "abc";
this is not a string literal. The "abc" token is a string literal syntax, not a string literal object. Here, that literal specifies the initial value for the str array. Array objects are modifiable.
char *str = "abc";
Here the "abc" syntax in the source code is an expression denoting a string literal object in the translated program image. It's also a kind of array, with static storage duration (regardless of the storage duration of str). The "abc" syntax evaluates to a pointer to the first character of this array, and the str pointer is initialized with that pointer value.
String literals are not required to support modification; the behavior of attempting to modify a string literal object is undefined behavior.
Even in systems where you don't get a predictable segmentation fault, strange things can happen. For instance:
char *a = "xabc";
char *b = "abc";
b[0] = 'b'; /* b changes to "bbc" */
Suppose the assignment works. It's possible that a will also be changed to "xbbc". A C compiler is allowed to merge the storage of identical literals, or literals which are suffixes of other literals.
It doesn't matter whether or not a and b are close together; this sneaky effect could occur even between distant declarations in different functions, perhaps even in different translation units.
String literals should be considered to be part of the program's image; a program which successfully modifies a string literal is effectively self-modifying code. The reason you get a "segmentation fault" in your environment is precisely because of a safeguard against self-modifying code: the "text" section of the compiled program (which contains the machine code) is located in write-protected pages of virtual memory. And the string literals are placed there together with the machine code (often interspersed among its functions). Attempts to modify a string literal result in write accesses to the text section, which are blocked by the permission bits on the pages.
In another kind of environment, C code might be used to produce a software image which goes into read-only memory: actual ROM chips. The string literals go into the ROM together with the code. Attempting to modify one adds up to attempting to modify ROM. The hardware might have no detection for that. For instance, the instruction might appear to execute, but when the location is read back, the original value is still there, not the new value. Like the segmentation fault, this is within the specification range of "undefined behavior": any behavior is!
String literals are stored in static duration storage which exist for program lifetime and could be read only. Changing content of this literal leads to undefined behavior.
Copy this literal to modificable array and pass it to function.
char array[5];
strcpy(array, "test");
If you are declaring pointer to string literal, make it const so compiler Will warn you if you try to modify it.
const char * ptr = " string literal";
I think, because if you use pointer, you can only read this array, you can't write anything to there with loop, because elements of your array don't situated nearly. (Sorry for my English)
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
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 7 years ago.
I am new to C and I want perform this task: declare and initialize a string and then reassign each string element to a new value.
Writing the code in this way:
char *str = "geeksforgeeks\0";
for (int i = 0; str[i] != '\0'; ++i) {
str[i] = 'a';
}
throws a segmentation fault.
But if I write the code in this manner:
char string[] = "geeksforgeeks\0";
char *str = string;
for (int i = 0; str[i] != '\0'; ++i) {
str[i] = 'a';
}
the program behaves correctly.
Also this code:
char str[] = "geeksforgeeks\0";
for (int i = 0; str[i] != '\0'; ++i) {
str[i] = 'a';
}
behaves correctly.
What is the difference between the two? Should't be equivalent?
char *str = "geeksforgeeks\0";
This string is allocated in readonly* memory and you can't modify it. Also the null terminator there is redundant.
Same is not the case with the array you defined, that is why it works. In the case with array the string literal is copied to memory where array resides - and you can modify contents of that array. So using this
char *str = string;
you point to the first element of the array - which as mentioned, is modifiable (as well as all elements of the array).
*It can be they are stored not in read only memory, depends on platform. But anyway you are not allowed to modify them.
If you have:
char *str = "geeksforgeeks\0";
the string is (usually) stored in read-only memory and you get a segmentation fault when you try to modify it. (The \0 is really not needed; you have two null bytes at the end of the string.)
The simplest fix is to use an array instead of a constant string (which is basically what you do in the second working case):
char str[] = "geeksforgeeks";
Note that you should really use this for the string since the string is not modifiable:
const char *str = "geeksforgeeks";
The reason is simple.
In first example, you have a pointer to an static string. that's why you get a segmentation fault.
char *str = "Test";
This is practically a constant string. But in 2nd example, it is a variable that you change.
// You have a variable here
char str_array[] = "Test";
// Now you have a pointer to str_array
char *str = str_array;
You’ve hit on a bit of ugly legacy baggage. When you write the literal "geeksforgeeks\0", the compiler turns that into a pointer to an array of characters. If you later use the string "geeksforgeeks\0" again, it’s allowed to point both references to the same array. This only works if you can’t modify the array; otherwise, fputs(stdout, "geeksforgeeks\0"); would be printing aeeksforgeeks. (Fortran can top this: on at least one compiler, you could pass the constant 1 by name to a function, set it equal to -1, and all your loops would then run backwards.) On the other hand, the C standard doesn’t say that modifying string literals won’t work, and there’s some old code that did. It’s undefined behavior.
When you allocate an array to hold the string, you’re creating a unique copy, and that can be modified without causing errors elsewhere.
So why aren’t string literals const char * instead of char *? Early versions of C didn’t have the const keyword, and the standards committee didn’t want to break that much old code. However, you can and should declare pointers to string literals as const char* s = "geeksforgeeks\0"; so the compiler will stop you from shooting yourself in the foot.
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
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.