2

I'm attempting to swap chars in a string using xor bitwise operators instead of using a placeholder. However, it segfaults before doing the bitwise xor. Can anyone explain why is that the case? Is there something about chars that don't allow me to do bitwise operations?

void reverse(char *str) {
    if (str == NULL || str == '\0') {
        return;
    }

    //Obtain length of str
    int length = 0;
    for (char *ptr = str; *ptr != '\0'; ptr++) {
        length++;
    }

    //Swap
    for (int i = 0; i < (int)(length / 2); i++) {
        str[i] ^= str[length - 1 - i];
        str[length - 1 - i] ^= str[i];
        str[i] ^= str[length - 1 - i];
    }
}

int main() {
    char *str = "bananas";
    reverse(str);
    printf("%s\n", str);

    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • 5
    I'm afraid you cannot change a string literal in C. [Take a look at this answer](https://stackoverflow.com/questions/2245664/what-is-the-type-of-string-literals-in-c-and-c). – Margaret Bloom Jun 02 '19 at 20:13
  • so he need to cast it to bytes? – user8426627 Jun 02 '19 at 20:14
  • 1
    No he needs to have normal array – 0___________ Jun 02 '19 at 20:14
  • Not a direct answer, but in 2019, any decent C compiler is smart enough to optimize a swap of two variables down to a single instruction, eliding any temporary. Using the xor trick is "clever" but a decent peephole optimizer will actually *undo* that "optimization" to prevent an unnecessary store-load dependency on a modern pipelined CPU. – Daniel Pryden Jun 02 '19 at 20:15
  • lol is it doing const char * implicite? – user8426627 Jun 02 '19 at 20:17
  • also it is weird to see someone who does xor swap optimisation, but counts the length of string and calculates length - 1 - i multiple times – user8426627 Jun 02 '19 at 20:19

2 Answers2

4

String literals are read only in C. Well, not really, but in practice they are. So change

char* str = "bananas";

to

char str[] = "bananas"; // Store as an array and not a pointer

or

char* str = strdup("bananas"); // Dynamically allocate. Don't forget to free

This is one of the occasions where it becomes obvious that arrays are not pointers

The standard does not say that string literals are read only, but on the other hand it does not say the opposite either. And in practice, string literals ends up in a read only-area in most C implementations. Technically they do have the type char[] which implies that should me modifyable, but modifying (or attempting to modify) them is undefined behavior, so avoid that.

http://port70.net/~nsz/c/c11/n1570.html#6.4.5p7

If the program attempts to modify such an array, the behavior is undefined.

Three other comments about your code:

  1. The cast in (int)(length / 2) is completely unnecessary. Just write length / 2 since that's already an int.

  2. No need to write your own function to find the string length. Just write length = strlen(str).

  3. Skip return 0. Only use a return statement in main if you want to exit before the end or if you want return something different than 0. This has been ok since C99.

klutt
  • 30,332
  • 17
  • 55
  • 95
  • @Blastfurnace string literal is also the array :) – 0___________ Jun 02 '19 at 20:22
  • Quoting `C11`, chapter [§6.4.5p7](http://port70.net/~nsz/c/c11/n1570.html#6.4.5p7 ) > 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**. – Ajay Brahmakshatriya Jun 02 '19 at 20:26
  • Broman do not answer obvious dupes: https://stackoverflow.com/questions/1704407/what-is-the-difference-between-char-s-and-char-s https://stackoverflow.com/questions/3638851/why-does-writing-to-a-string-literal-in-this-c-program-segfault – 0___________ Jun 02 '19 at 20:48
  • @P__J__ Hmmm true, but if it was that obvious, you should have marked it as a dupe 25 minutes ago when you wrote the first comment. ;) – klutt Jun 02 '19 at 20:49
  • As you noticed I have commented another comment. This topic was to obviously a dupe – 0___________ Jun 02 '19 at 22:01
  • “String literals are read only in C. Well, not really, but in practice they are.” is confusing to a reader. It is worth taking time to structure an answer and think about its composition and presentation, so that the information is presented to the reader in a clear way. – Eric Postpischil Jun 02 '19 at 22:42
1

Instead of using a pointer, use an array

char str[] = "bananas';

You can't modify a string literal but you can modify an array.

cup
  • 7,589
  • 4
  • 19
  • 42
  • If you are going to teach other people about C, it is worth investing some time in learning the correct concepts. First, string literals in source code are arrays in the program (C 2018 6.4.5 6). You can index them like arrays (`"abc"[2]` is `'c'`). Second, you cannot always modify an array, such as one with `const` elements. – Eric Postpischil Jun 02 '19 at 22:38
  • Third, there is no actual rule in C that says you cannot modify a string literal. Rather, the actual rule is that, if you attempt to modify the array resulting from a string, the C standard does not define the behavior (6.4.5 7). The reason for this is largely historical, but it means that a C implementation is free to support modifiable string literals if it wants. – Eric Postpischil Jun 02 '19 at 22:38
  • So, a better answer would say it is improper to attempt to modify a string literal in portable C code, and that the C standard does not define result if you try. And it could go into more detail about how the statement shown creates an array that is modifiable and that is initialized to contain the desired string. – Eric Postpischil Jun 02 '19 at 22:41