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?

5
  • 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. Commented Aug 8, 2013 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. Commented Aug 8, 2013 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. Commented Aug 9, 2013 at 0:03
  • Your second declaration of an array of characters does not have a null terminator. Commented Aug 9, 2013 at 4: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?. Commented Aug 9, 2013 at 6:23

4 Answers 4

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.

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

5 Comments

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"?
@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).
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.
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?
@DennisMeng: I changed it to "may or may not segfault", but still, the behavior is equally undefined in both cases.
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.

Comments

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;
}

1 Comment

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.
0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.