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.