Filip Ekberg
Filip Ekberg

Reputation: 36287

Using strcat in C

Okay so I have the following Code which appends a string to another in C#, note that this is Just an example, so giving alternative string concatination methods in C# is not nessesary, this is just to simplify the example.

string Data = "";
Data +="\n\nHTTP/1.1 " + Status_code;
Data += "\nContent-Type: " + Content_Type;
Data += "\nServer: PT06";
Data += "\nContent-Length: " + Content_Lengt;
Data += "\nDate: " + Date;
Data += "\n" + HTML;

Now I'd like to do the exact same thing in C and I'm trying to do this the following way

time_t rawtime;

time ( &rawtime );

char *message = "\n\nHTTP/1.1 ";
message = strcat(message, Status_code);
message = strcat(message, "\nContent-Type: ");
message = strcat(message, Content_Type);
message = strcat(message, "\nServer: PT06");
message = strcat(message, "\nContent-Length: ");
message = strcat(message, Content_Lengt);
message = strcat(message,  "\nDate: ");
message = strcat(message, ctime(&rawtime));
message = strcat(message, "\n");
message = strcat(message, HTML);

Now, this gives me a Segment fault, I know why, I access and read on memory that i shouldn't. But the question is, how do i solve it? Could I use string.h and just do it the same way that I did in C#?

Upvotes: 13

Views: 49146

Answers (7)

SmacL
SmacL

Reputation: 22922

Change

char *message = "\n\nHTTP/1.1 ";

to

char message[1024];  
strcpy(message,"\n\nHTTP/1.1 ");

and you should be ok, up to a total message length of 1023.

Edit: (as per mjy's comment). Using strcat in this fashion is a great way of getting buffer overflows. You could readily write a small function that checks the size of the buffer and length of incoming string addition to overcome this, or use realloc on a dynamic buffer. IMO, the onus is on the programmer to check correct buffer sizes where they are used, as with sprintfs and other C strings functions. I assume that C is being used over C++ for performance reasons, and hence STL is not an option.

Edit: As per request from Filip's comment, a simple strcat implementation based on a fixed size char buffer:

char buffer[MAXSIZE] = "";

int mystrcat(char *addition)
{
   if (strlen(buffer) + strlen(addition) + sizeof(char)  >= MaxSize)
     return(FAILED);
   strcat(buffer,addition);
   return(OK);
}

Using dynamic allocation:

char *buffer = NULL;

int mystrcat(char *addition)
{
   buffer = realloc(buffer, strlen(buffer) + strlen(addition) + sizeof(char));
   if (!buffer)
     return(FAIL);
   strcat(buffer, addition);
   return(OK);
}

In this case you have to free your buffer manually when you are finished with it. (Handled by destructors in C++ equivalents)

Addendum (Pax):

Okay, since you didn't actually explain why you had to create message[1024], here it is.

With char *x = "hello", the actual bytes ('h','e','l','l','o',0) (null on the end) are stored in an area of memory separate from the variables (and quite possibly read-only) and the variable x is set to point to it. After the null, there's probably something else very important. So you can't append to that at all.

With char x[1024]; strcpy(x,"hello");, you first allocate 1K om memory which is totally dedicated to x. Then you copy "hello" into it, and still leave quite a bit of space at the end for appending more strings. You won't get into trouble until you append more than the 1K-odd allowed.

End addendum (Pax):

Upvotes: 20

erisu
erisu

Reputation: 483

Have not seen any mention of the strlcpy, strlcat function, which is similar to the 'n' functions except also takes into account the trailing 0. Both take a third argument indicating the maximum length of the output buffer and are found in string.h.

example:

char blah[]="blah";
char buffer[1024];
strlcpy(buffer,"herro!!!",sizeof(buffer));
strlcat(buffer,blah,sizeof(buffer));
printf("%s\n",buffer);

Will output "herro!!!blah"

char blah[]="blah";
char buffer[10];
strlcpy(buffer,"herro!!!",sizeof(buffer));
strlcat(buffer,blah,sizeof(buffer));
printf("%s\n",buffer);

will output "herro!!!b" due to the limited size of buffer[], with no segfaulting. ^^

Only problem is not all platforms seem to include it in their libc (such as linux ._.), most all BSD varients DO seem to have it.

In that case, code for both functions can be found here and easily added: strlcpy, strlcat, the rest of string.h

Upvotes: 1

Christoph
Christoph

Reputation: 169583

I wonder why no one mentioned snprintf() from stdio.h yet. That's the C way to output multiple values and you won't even have to convert your primitives to strings beforehand.

The following example uses a stack allocated fixed-sized buffer. Otherwise, you have to malloc() the buffer (and store its size), which would make it possible to realloc() on overflow...

char buffer[1024];
int len = snprintf(buffer, sizeof(buffer), "%s %i", "a string", 5);
if(len < 0 || len >= sizeof(buffer))
{
    // buffer too small or error
}

Edit: You might also consider using the asprintf() function. It's a widely available GNU extension and part of TR 24731-2 (which means it might make it into the next C standard). The example from above would read

char * buffer;
if(asprintf(&buffer, "%s %i", "a string", 5) < 0)
{
    // (allocation?) error
}

Remember to free() the buffer when done using it!

Upvotes: 8

mjy
mjy

Reputation: 2767

The safe way to do this in classic C style is:

 char *strconcat(char *s1, char *s2)
 {
    size_t old_size;
    char *t;

    old_size = strlen(s1);

    /* cannot use realloc() on initial const char* */
    t = malloc(old_size + strlen(s2) + 1);
    strcpy(t, s1);
    strcpy(t + old_size, s2);
    return t;
  }

  ...

  char *message = "\n\nHTTP/1.1 ";
  message = strconcat (message, Status_code);
  message = strconcat (message, "\nContent-Type: ");

Now you can say a lot of bad things about it: it's inefficient, it fragments your memory, it's ugly ... but it's more or less what any language with a string concatenation operator and C type (zero-terminated) strings will do (except that most of these languages will have garbage collection built-in).

Upvotes: -2

Jeff M
Jeff M

Reputation: 710

As said previously, you have to write to a sufficiently large buffer. Unfortunately, doing so is a lot of extra work. Most C applications that deal with strings use a dynamically resizable string buffer for doing concatenations.

glib includes an implementation of this, glib strings, which I recommend using for any application that uses strings heavily. It makes managing the memory easier, and prevents buffer overflows.

Upvotes: 1

kgiannakakis
kgiannakakis

Reputation: 104178

Start from using the safer strncat function. In general always use the safer 'n' functions that will not overflow if the size of a string is bigger than a specific size.

In C you need to take care of string sizes yourself. So you need to know how big the resulting string will be and accommodate for it. If you know the sizes of all the strings at the left side, you should create a buffer big enough to hold the resulting string.

Upvotes: 6

MSalters
MSalters

Reputation: 179819

message points to a char const[] that you can't write to, yet that's exactly where strcat is writing. You need to malloc() a sufficiently large buffer.

Upvotes: 2

Related Questions