4

I was running this simple program, the output i get is a "bus error". using some debugging statements i found the point at which it occurs was at the strcat() call.

#include<stdio.h>
#include<string.h>
main()
{
char *s = "this is ";
char *s1 = "me";  
strcat(s,s1); 
printf("%s",s);
return 0;
}

I run it using a gcc compiler on a MAC, 64-bit OS. Please let me know if i need to provide any more specification.

Thanks!

Maverickgugu
  • 767
  • 4
  • 13
  • 26

3 Answers3

11

A little background:

The expressions "this is " and "me" are string literals; they are 9- and 3-element arrays of char (const char in C++) respectively with static extent (meaning the memory for them is allocated at program startup and held until the program exits). That memory may or may not be writable, depending on the platform, so attempting to modify a string literal results in undefined behavior (meaning the compiler can literally do anything it wants to). In short, you cannot write to a string literal.

When you write strcat(s, s1);, you're running into two problems: first, the target array is a string literal, which as I mentioned above is not writable. Secondly, it's not large enough to hold the additional characters; it's sized to hold 9 characters (including the 0 terminator), but you're attempting to store 11 characters to it. This is a buffer overflow, which can lead to Bad Things if you clobber something important.

You'll have to allocate a target buffer that is writable. You have several choices:

  1. You can declare an array that's big enough to hold the resulting string, although in general you're not going to know how big "big enough" is at compile time:

    
    char *s = "this is ";
    char *s1 = "me";
    char target[11];
    strcpy(target, s);
    strcat(target, s1);
    // alternately, sprintf(target, "%s%s", s, s1);
    
  2. In C99, you can declare a variable-length array (VLA) whose size isn't known until runtime:

    
    char *s = "this is ";
    char *s1 = "me";
    char target[strlen(s) + strlen(s1) + 1];
    strcpy(target, s);
    strcat(target, s1);
    // alternately, sprintf(target, "%s%s", s, s1);
    
  3. You can dynamically allocate a target buffer using malloc or calloc (this is actually the preferred method, since the buffer can be resized as necessary, unlike a VLA):

    
    char *s = "this is ";
    char *s1 = "me";
    char *target = malloc(strlen(s) + strlen(s1) + 1);
    strcpy(target, s);
    strcat(target, s1); 
    // or sprintf(target, "%s%s", s, s1);
    ...
    free(target); // when you're finished with the buffer
    
John Bode
  • 119,563
  • 19
  • 122
  • 198
8

"this is " and "me" are string literals which may reside in a read-only part of your address space. You should not attempt to modify these.

char s[] = "this is ";
char s1[] = "me";  

This will ensure the literals are copied to stack - which is writable. Then your following strcat will overflow the stack buffers, which is just as bad.

The below will work - even though using strcat and not strncat is in general bad practice.

#include <stdio.h>
#include <string.h>
int main()
{
  char s[100] = "this is ";
  char *s1 = "me";  
  strcat(s,s1); 
  printf("%s",s);
  return 0;
}
Erik
  • 88,732
  • 13
  • 198
  • 189
  • 3
    `strcat` is only bad practice to those that don't know how to use it properly. These people should stick with BASIC :-) But +1 since you nailed it. – paxdiablo Apr 19 '11 at 13:38
  • 1
    @paxdiablo: Yep, thus "in general" ;) – Erik Apr 19 '11 at 13:38
  • Wow, made me remember a nasty bug that happened to me a long time back. I was getting seg-faults and then realized this the hard way. – BiGYaN Apr 19 '11 at 13:41
  • It must really difficult to keep track of the size of the strings when the program becomes complex. Thanks for pointing out the warning.. Will be aware! – Maverickgugu Apr 19 '11 at 14:47
2

You need to read up more on how strings work in C, and the difference between character arrays and string literals.

To make this work, rewrite it for instance as follows:

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

int main(void)
{
  char s[100] = "this is ";
  char *s1 = "me";  

  strcat(s, s1); 

  printf("%s", s);

  return EXIT_SUCCESS;
}

A few more points:

  1. main() returns int.
  2. The symbol EXIT_SUCCESS (from <stdlib.h> is clearer than 0).
  3. A function taking no arguments should be declared as void in C. For main(), empty parenthesis is not valid.
unwind
  • 391,730
  • 64
  • 469
  • 606
  • 5
    I don't find `EXIT_SUCCESS` clearer than zero; it's just clutter. Same goes for macros like `FALSE`. – R.. GitHub STOP HELPING ICE Apr 19 '11 at 13:42
  • Thanks for the detailed description. i guess I should start adopting a more formal style of programming. But I am not able to understand how EXIT_SUCCESS can help in a better debugging process? – Maverickgugu Apr 19 '11 at 13:47