2

In C, why is it that this does not work:

#include <stdio.h>
int main(void)
{
    char * strA = "Hello ";
    strcat(strA, "World!");
    printf("%s", strA);
    return 0;
}

But this does:

#include <stdio.h>
int main(void)
{
    char strA[6] = "Hello ";
    strcat(strA, "World!");
    printf("%s", strA);
    return 0;
}

I would have put the error, but alas I am using Xcode, which does not like to give me anything usable when it fails, just giving me BAD_ACCESS_EXC(code =2...) which according to the a quick Google search, just has something do do with memory allocation errors.

I thought that you were allocating the same amount of memory for strA in both cases. Could someone please enlighten me?

onetwopunch
  • 3,279
  • 2
  • 29
  • 44
  • 3
    `"Hello "` is a string literal and string literals are not modifiable. `char str[6] = "Hello ";` is an array intialized with a string literal, you can modify it. But still `6` bytes won't be enough to store the string and a fortiori to concatenate another string. – ouah Aug 08 '13 at 23:30
  • 1
    Also keep in mind that `strcat` assumes that the destination string has enough memory to hold the concatenated result; which is not true in this case. – Dennis Meng Aug 08 '13 at 23:30
  • 1
    And.. the second example doesn't compile (`str` != `strA`). I assume you meant the latter, but reviewers prefer code that compiles out of the gate without having to fix it. – WhozCraig Aug 09 '13 at 00:03
  • Your second declaration of an array of characters does not have a null terminator. – Jacob Pollack Aug 09 '13 at 04:44
  • 1
    Ah yes, the daily "copy stuff into an address where no allocated memory exists" question. Possible duplicate of [Why do I get a segmentation fault when writing to a string?](http://stackoverflow.com/questions/164194/why-do-i-get-a-segmentation-fault-when-writing-to-a-string). – Lundin Aug 09 '13 at 06:23

4 Answers4

2

In the first case, you are declaring strA as a char *, pointing to static memory containing the string "Hello ".

In the second case, you are creating an array of 6 characters, initialised with the string "Hello ".

strcat in the first case thus tries to write to this static segment of memory, causing an error immediately.

The second code, which is still invalid (as strA is not a large enough array to store "Hello World"), may or may not segfault as you aren't attempting to append to a string literal.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
sapi
  • 9,944
  • 8
  • 41
  • 71
  • 1
    Am I the only one who read "may not segfault" as "the code is not allowed to segfault" and not "the code might not segfault when run"? – Dennis Meng Aug 08 '13 at 23:35
  • @DennisMeng no, you're not the only one. Equally one would say the code is valid (it does, after all, compile); its the **behavior** that is undefined (in a potentially catastrophic way). – WhozCraig Aug 09 '13 at 00:10
  • 2
    In the second case `strA` is stored on the stack, so using `strcat` to write past `strA`'s bounds might corrupt other information on the stack. – markgz Aug 09 '13 at 00:15
  • So the reason the second case happened to work is that the "World!"-sized chunk of memory after "Hello " is on the stack and is writeable, but in the first case it is on the heap, which is not? – onetwopunch Aug 09 '13 at 00:37
  • @DennisMeng: I changed it to "may or may not segfault", but still, the behavior is equally undefined in both cases. – Keith Thompson Aug 09 '13 at 00:55
0
char * strcat ( char * destination, const char * source );

see Here

The function will write the final string to the first param.In that case you can't pass a read only memory to it.

Lidong Guo
  • 2,817
  • 2
  • 19
  • 31
0

There is actually a lot going on here. Let's step through it one by one. Consider the following two declarations of the string "Hello ".

char *strA = "Hello "; // #1
char strB[ 7 ] = "Hello "; // #2

The first expression is declaring a character pointer called strA that points to a location in the read-only section of memory where "Hello " (alternatively { 'h', 'e', 'l', 'l', 'o', ' ', '\0' }) is stored. The first declaration is more commonly known as a string literal.

The second expression is declaring an array of characters called strB that consists of seven characters and it is declared on the stack. It's important to note that the convention for strings in C is to have a null terminator (0 character) at the end of a string (an array of characters) -- you are missing this. The initialization syntax (the double quotes) automatically fills the trailing entries with 0s regardless of where it is declared.

Now, to directly answer your question. You cannot overwrite read-only memory and hence if you attempt to modify any memory that strA points to (a string literal) then it will result in an error. You can modify the block of memory that strB points to, however you would want to initialize a larger array to properly accommodate the characters 'w', 'o', 'r', 'l', 'd' and '!'. Compilers will let you write to memory you do not have access to, however there is no guarantee that it will not be allocated to other variables on the same stack frame or another program.

This would be the proper snippet of code:

#include <stdio.h>

int main( void ) {
  // Declares an array of characters, strA with a length of 13.
  char strA[ 13 ] = "Hello ";

  // Concatenates the characters 'w', 'o', 'l', 'r', 'd' and '!' to strA.
  strcat( strA, "World!" );

  // Outputs to stdout.
  printf( "%s", strA ); // => "Hello World!"

  return 0;
}
Jacob Pollack
  • 3,703
  • 1
  • 17
  • 39
  • Where string literals are stored is an implementation detail. The standard does not dictate that they must be in read-only storage, it simply states that attempts to modify the contents of a string literal results in undefined behaviour. On some systems it may actually work. – dreamlax Aug 09 '13 at 04:52
0

I am surprised the second code works. For it to work without any runtime errors, you might want to use dynamic memory allocation.