9

I am trying reverse a string.

This is the code I tried:

#include<stdio.h>
#include<string.h>

int main(){
    char *c="I am a good boy";
    printf("\n The input string is : %s\n",c);
    printf("\n The length of the string is : %d\n",strlen(c));
    int i,j;
    char temp;
    int len=strlen(c);
    for(i=0,j=len-1;i<=j;i++,j--)
    {
            temp=c[i];
            c[i]=c[j];
            c[j]=temp;
    //printf("%c\t%c\n",*(c+i),*(c+(len-i-1)));
    }
    printf("\n reversed string is : %s\n\n",c);
}

The code outputs a Bus error : 10.

But if I rewrite the same code as:

int main(void)
{
    char *str;
    str="I am a good boy";
    int i,j;
    char temp;
    int len=strlen(str);
    char *ptr=NULL;
    ptr=malloc(sizeof(char)*(len));
    ptr=strcpy(ptr,str);
    for (i=0, j=len-1; i<=j; i++, j--)
    {
        temp=ptr[i];
        ptr[i]=ptr[j];
        ptr[j]=temp;
    }
    printf("The reverse of the string is : %s\n",ptr);
}

It works perfectly fine.

Why is the first code throwing bus error or segmentation fault?

Jeff Mercado
  • 129,526
  • 32
  • 251
  • 272
sethu
  • 1,691
  • 4
  • 22
  • 34
  • I tried formatting as much as possible, but i really dont know how to have them aligned. – sethu Sep 18 '11 at 01:07
  • 1
    Please format your code by indenting it all with four spaces. – SLaks Sep 18 '11 at 01:08
  • 1
    In the future, highlight all your code, then click the `{}` icon. – Matthew Flaschen Sep 18 '11 at 01:14
  • 1
    @sethu: Be sure to look at the [source](http://stackoverflow.com/revisions/beb61415-bf10-41ca-9dad-5849dc604837/view-source) of the question as it is now to see how you should format your code for the site. All it takes is pasting your code in, selecting it and pressing `Ctrl + K` to indent it all with 4 spaces. That alone should be sufficient. – Jeff Mercado Sep 18 '11 at 01:14

5 Answers5

16

The bus error occurs because in many (if not most or all modern) C compilers, string literals are allocated in read-only memory.

You are reversing the string in place. In your first code snippet you are trying to write into a string literal. Not a good idea.

In the second case, you malloc'd a string which put it on the heap. It is now safe to reverse that string in place.

ADDENDUM

To the commenter who asked about segfaults versus bus errors, that is a great question. I have seen both. Here is a bus error on a mac:

$ cat bus.c 
char* s = "abc"; int main() {s[0]='d'; return 0;}

$ gcc --version bus.c && ./a.out
i686-apple-darwin10-gcc-4.2.1 (GCC) 4.2.1 (Apple Inc. build 5659)
Copyright (C) 2007 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Bus error

On other operating systems/compilers you may indeed get a segfault.

Ray Toal
  • 86,166
  • 18
  • 182
  • 232
  • I thought trying to write read-only memory would cause a segfault, not a bus error? Or is that OS-specific? – cHao Sep 18 '11 at 01:15
  • You must be doing some wacky stuff over there. :) Only time i've ever seen a bus error, the motherboard was bad. – cHao Sep 18 '11 at 01:18
  • 1
    @cHao, writing to a string literal is undefined (see my [previous answer](http://stackoverflow.com/questions/3638851/why-does-this-seg-fault/3638867#3638867) on this), so a segfault, bus error, and far weirder things are all allowed. – Matthew Flaschen Sep 18 '11 at 01:19
  • +1 @Matthew for pointing out what the standard says. Perfect description of _why_ both are possible. – Ray Toal Sep 18 '11 at 01:29
  • Many C++ compilers warn about assigning a string literal to a non-const char* for just this reason. – emsr Sep 24 '11 at 02:31
6

Copying it to the heap is one option. However, if you just want to allocate a local (stack) array, you can do:

char str[] = "I am a good boy";

Then, the constant string will be copied to the stack.

Matthew Flaschen
  • 278,309
  • 50
  • 514
  • 539
1

Character arrays specified in form of "I am a good boy" are usually constant - you can't modify them. That's why your first variant crashes. The second doesn't, as you make a copy of data and then modify it.

dragonroot
  • 5,653
  • 3
  • 38
  • 63
0

char *str = "I am a good boy"; Treated as literal and trying to modify it will result in bus error. It is equivalent to const char *str = "I am a good boy", i.e. pointer to a constant string and trying to modify a constant string is not allowed.

EDIT : The moment you malloc() and copy you are playing with a copy of the original string and ptr is not of 'const char *' type, instead it is 'char *ptr' and does not complain.

Anoop Menon
  • 619
  • 1
  • 4
  • 12
0

Compiling with c++ (g++) shows the deprecation of assigning a string literal to a non-const char* which is designed to prevent this error:

ed@bad-horse:~/udlit_debug$ g++ ../buserr.cpp 
../buserr.cpp: In function ‘int main()’:
../buserr.cpp:5:13: warning: deprecated conversion from string constant to ‘char*’
../buserr.cpp:7:61: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘size_t’

The relevant warning is on line 5.

Changing the declaration to const char * as indicated prevents the assignments into the literal string.

This is also a lesson on why you should not ignore warnings.

emsr
  • 15,539
  • 6
  • 49
  • 62