2

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?

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
joumvaer92
  • 252
  • 3
  • 14

4 Answers4

6

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.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • This answer is to professional for for person who ask this kind of question. – Marek R Jul 15 '15 at 14:57
  • @MarekR Sorry, I did not get you. – Sourav Ghosh Jul 15 '15 at 14:58
  • 2
    For newbie this answer is to hard to understand. – Marek R Jul 15 '15 at 14:59
  • @MarekR Actually I like to quote directly from the standard so that there is no chance for misconception / misunderstanding. English is not my strong point (not my native language). Would you like to propose any addition to this answer to make it easy? I'll be thankful. :-) – Sourav Ghosh Jul 15 '15 at 15:02
  • 1
    much better. I'm impressed that you give such big attention to this kind of question. – Marek R Jul 15 '15 at 17:33
4

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;     
}
dbush
  • 205,898
  • 23
  • 218
  • 273
3

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.

Olivier Poulin
  • 1,778
  • 8
  • 15
0

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

user3629249
  • 16,402
  • 1
  • 16
  • 17