-1
char * concat(const char *s1, const char *s2) {
    char result[70];
    strcpy(result, s1);
    strcat(result, s2);
    return result;
}
int main() {
    char *s1 = "Hello";
    char *s2 = " World!";
    char *s3 = concat(s1, s2);
    printf("%s\n", s3);

    return 0;
}

This program just calls the concat function which returns a char * that is the concat of s1 and s2. However, upon compiling, I get the error address of stack memory associated with local variable 'result' returned.

So I understand that result is a local variable in the concat function, but not really why we have to malloc it. Why doesn't result just get returned with Hello World as it's value?

If you consider a program like this:

int ret() {

    int a = 4;
    return a;
}
int main() {
    int b = ret();
    printf("%d\n", b); // 4

    return 0;
}

there is no error. I don't have to malloc the int. a is local, but I still return it and it still works.

I want to know what's the main difference between concat and ret, and why concat must dynamically allocate memory. Thank you.

K Split X
  • 3,405
  • 7
  • 24
  • 49

4 Answers4

3

From the C Standard (6.2.4 Storage durations of objects)

1 An object has a storage duration that determines its lifetime. There are four storage durations: static, thread, automatic, and allocated. Allocated storage is described in 7.22.3.

2 The lifetime of an object is the portion of program execution during which storage is guaranteed to be reserved for it. An object exists, has a constant address,33) and retains its last-stored value throughout its lifetime.34) If an object is referred to outside of its lifetime, the behavior is undefined. The value of a pointer becomes indeterminate when the object it points to (or just past) reaches the end of its lifetime.

and

6 For such an object that does not have a variable length array type, its lifetime extends from entry into the block with which it is associated until execution of that block ends in any way...

In this function definition

char * concat(const char *s1, const char *s2) {
    char result[70];
    strcpy(result, s1);
    strcat(result, s2);
    return result;
}

the variable result has the automatic storage duration. Its lifetime is ended after exiting the function. So as it is written in the Standard

If an object is referred to outside of its lifetime, the behavior is undefined.

If to allocate the array dynamically then its lifetime will not end after exiting the function and a pointer that points to it will be valid. You can access the allocated memory outside the function where it was allocated.

As for this function definition

int ret() {

    int a = 4;
    return a;
}

then the function returns the object itself. If you returned the object indirectly through a pointer like this

int * ret() {

    int a = 4;
    return &a;
}

then you had the same problem as with the first program that is the program will have undefined behavior if you try to access the variable a using the returned pointer.

Take into account that functions can return an object of the type int but they can not return an array.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
0
char * concat(const char *s1, const char *s2) {
    char result[70];
    strcpy(result, s1);
    strcat(result, s2);
    return result;
}

In your function, the result array is freed after the function call, so char *s3 = concat(s1, s2); pointer s3 is pointing to an invalid address.

Kaizhe Huang
  • 990
  • 5
  • 11
0

There are ways to make this function work without dynamic memory allocations. For example, you can ditch all hopes if being multi-threading compatible and declare a static variable inside the function. Illustration:

char* concat() {
    static char result[70];
    // ... rest of the code
}
SergeyA
  • 61,605
  • 5
  • 78
  • 137
-1

Returning a primitive like an int and returning a string is fundamentally different in C. A string is not a primitive object and is actually a character array. Just like how you cannot declare an array in a function locally, then return that array, you cannot simply return the string. The compiler does not throw an error, but instead a warning, because usually, the stack frame where the contents of result is stored is not cleared when the function returns, so for a short time after exiting the function, you MIGHT be still able to the pointer returned, but don't count on it.

The fundamental difference here is that malloc will allocate space on the heap, which will not be overwritten unless explicitly told otherwise, whereas simply declaring an array in a function does not guarantee that the space the array occupies will still be accessible / readable after the exit of the function (hence a local variable).

Felix Guo
  • 2,700
  • 14
  • 20