0

I want to have a function that receives a string as a parameter and change symbols of the string

char *strChanger(char *str).

I tried to implement it like this:

char *strChanger(char *str) {
    if(str[0] != '\0') {
        str[0] = 'a';
    }
    return str;
}

In the program it should look like char *newstr = strChanger("hi");

But when I try to change a character in the string, a program chrashes.

I did some experiments and find that:

// Works fine
char str[] = "hi";
str[0] = 'a';

// Crashes
char *str = "hi";
str[0] = 'a';

I dont understand the difference. Why the second block of code doesn't work?

  • 1
    https://stackoverflow.com/questions/4493139/are-string-literals-const – kfx Feb 04 '18 at 19:17
  • 1
    `char* str = "hi"` sets str to point to read-only memory. – AndersK Feb 04 '18 at 19:21
  • @BoPersson and @Anders K. both makes good points. `char str[]` is on the stack (hence you can modify each character), while `char *str` if you think about is just a pointer that might or might not point to a modifiable memory region. In your case it was a non modifiable memory region (read-only as @Anders K. pointed out). – Seoul Feb 04 '18 at 19:27
  • @AndersK. Detail: C does not require any "read-only" memory. C does say that attempting to modify a _string literal_ is UB. – chux - Reinstate Monica Feb 04 '18 at 19:37
  • @chux a literal may not be altered i.e. read-only – AndersK Feb 05 '18 at 19:30
  • @AndersK. In C, attempting to alter a _string literal_ is UB - it should not be attempted. It might work it might not. C does not require a _string literal_ to be read-only. "If the program attempts to modify such an array, the behavior is undefined." §6.4.5 7. OTOH, Attempting to change a _compound literal_ is not a problem. – chux - Reinstate Monica Feb 05 '18 at 20:15
  • @chux *treating* it as read-only should solve the problem – AndersK Feb 05 '18 at 20:19

1 Answers1

3

Because modifying string literal is undefined behavior - in your case leading to crash of your program.

In the second example, you are passing the string literal direclty and tried to make changes to it. Speaking in terms of char *newstr = strChanger("hi").

In fact char *str = "hi"; is basically making str point to the string literal. More specifically string literal is an array which is converted into pointer to the first element and which is then assigned to str. Then you tried to modify it - which is undefined behavior.

In the first case a copy of it is made which is modifiable and you can make changes to it which is then passed and it worked. You are declaring a char array and initializing it with the content of the string literal.

If you have POSIX defined "strdup" then you can do this

char *newstr = strChanger(strdup("hi"));

But again then inside strChanger you need to check the passed value - strdup may return NULL in case it fails to allocate memory and provide you with the copied string. At some point after using like this you will have to free the memory - free(newstr).

From standard 6.4.5p7 under string literal

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.

From 6.7.9p14 under initialization

An array of character type may be initialized by a character string literal or UTF-8 string literal, optionally enclosed in braces. Successive bytes of the string literal (including the terminating null character if there is room or if the array is of unknown size) initialize the elements of the array.

user2736738
  • 30,591
  • 5
  • 42
  • 56