Why does *(str+i) = *(str +j) not work here?


void reverse(char *str){
    int i,j;
    char temp;
    for(i=0,j=strlen(str)-1; i<j; i++, j--){
     temp = *(str + i);
     *(str + i) = *(str + j);
     *(str + j) = temp;
     printf("%c",*(str + j));
    }
}



int main (int argc, char const *argv[])
{
    char *str = "Shiv";
    reverse(str);
    printf("%s",str);
    return 0;
}

When I use char *str = "Shiv" the lines in the swapping part of my reverse function i.e str[i]=str[j] dont seem to work, however if I declare str as char str[] = "Shiv", the swapping part works? What is the reason for this. I was a bit puzzled by the behavior, I kept getting the message "Bus error" when I tried to run the program.

13.10.2009 19:45:06
Meta question... Why are some otherwise valid answers on this topic voted down? They aren't as complete as the answer with the most votes, but they aren't necessarily wrong, either.
shoover 13.10.2009 20:05:16
8 ОТВЕТОВ
РЕШЕНИЕ

When you use char *str = "Shiv";, you don't own the memory pointed to, and you're not allowed to write to it. The actual bytes for the string could be a constant inside the program's code.

When you use char str[] = "Shiv";, the 4(+1) char bytes and the array itself are on your stack, and you're allowed to write to them as much as you please.

16
13.10.2009 19:47:48

The char *str = "Shiv" gets a pointer to a string constant, which may be loaded into a protected area of memory (e.g. part of the executable code) that is read only.

4
13.10.2009 19:48:28

char *str is a pointer / reference to a block of characters (the string). But its sitting somewhere in a block of memory so you cannot just assign it like that.

0
13.10.2009 19:49:26
char *str = "Shiv";

This should be :

const char *str = "Shiv";

And now you'll have an error ;)

4
13.10.2009 19:49:53

Try

int main (int argc, char const *argv[])
{
    char *str = malloc(5*sizeof(char)); //4 chars + '\0'
    strcpy(str,"Shiv");
    reverse(str);
    printf("%s",str);
    free(str); //Not needed for such a small example, but to illustrate
    return 0;
}

instead. That will get you read/write memory when using pointers. Using [] notation allocates space in the stack directly, but using const pointers doesn't.

1
13.10.2009 19:50:26

String literals are non-modifiable objects in both C and C++. An attempt to modify a string literal always results in undefined behavior. This is exactly what you observe when you get your "Bus error" with

char *str = "Shiv";

variant. In this case your 'reverse' function will make an attempt to modify a string literal. Thus, the behavior is undefined.

The

char str[] = "Shiv";

variant will create a copy of the string literal in a modifiable array 'str', and then 'reverse' will operate on that copy. This will work fine.

P.S. Don't create non-const-qualified pointers to string literals. You first variant should have been

const char *str = "Shiv";

(note the extra 'const').

1
13.10.2009 19:51:43

Interesting that I've never noticed this. I was able to replicate this condition in VS2008 C++.

Typically, it is a bad idea to do in-place modification of constants.

In any case, this post explains this situation pretty clearly.

The first (char[]) is local data you can edit (since the array is local data).

The second (char *) is a local pointer to global, static (constant) data. You are not allowed to modify constant data.

If you have GNU C, you can compile with -fwritable-strings to keep the global string from being made constant, but this is not recommended.

0
13.10.2009 20:08:21

String literals (your "Shiv") are not modifiable.
You assign to a pointer the address of such a string literal, then you try to change the contents of the string literal by dereferencing the pointer value. That's a big NO-NO.

Declare str as an array instead:

char str[] = "Shiv";

This creates str as an array of 5 characters and copies the characters 'S', 'h', 'i', 'v' and '\0' to str[0], str[1], ..., str[4]. The values in each element of str are modifiable.

When I want to use a pointer to a string literal, I usually declare it const. That way, the compiler can help me by issuing a message when my code wants to change the contents of a string literal

const char *str = "Shiv";

Imagine you could do the same with integers.

/* Just having fun, this is not C! */
int *ptr = &5;                      /* address of 5   */
*ptr = 42;                          /* change 5 to 42 */
printf("5 + 1 is %d\n", *(&5) + 1); /* 6? or 43?  :)  */

Quote from the Standard:

6.4.5 String literals
...
6 ... If the program attempts to modify such an array [a string literal], the behavior is undefined.

1
13.10.2009 20:05:46