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!

0

3 Answers 3

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
    

Sign up to request clarification or add additional context in comments.

2 Comments

The various possibilities of performing the operation is nice to follow. Thanks!
"static extent"? - I think the phrase you're looking for is "static storage duration". Other than that, a fine answer.
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;
}

4 Comments

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: Yep, thus "in general" ;)
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.
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!
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.

2 Comments

I don't find EXIT_SUCCESS clearer than zero; it's just clutter. Same goes for macros like FALSE.
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?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.