Returning function string directly and with array

Asked

Viewed 1,249 times

7

What works:

void *teste();

int main () {
    printf("\nRESULTADO: %s\n", teste());
    return 0;
}

void *teste(){
    return "Ponteiro";
}

What goes wrong:

void *teste();

int main () {
    printf("\nRESULTADO: %s\n", teste());
    return 0;
}

void *teste(){
    char p[10]="Ponteiro";
    return p;
}

Why the right first and the wrong second? Return an allocated string in a variable?

2 answers

8


The first is returning a pointer to a static area of code that is always available. The text already exists within the executable.

The second is returning a pointer to an area of the stack, which may or may not be available when the function ends. At the end of it there is a pop-up, so all the content that was in the stack when the function was running can no longer be accessed, so an attempt to access this area is an error (although by coincidence it may be possible if the data has not yet been erased, but should not rely on it, never).

Note that even in the second example there is text in the static area to play in the variable p. When you run the line there the static area content is copied to the stack and p has the address of that area and not the static.

Arrays are types by value and therefore their value is in the storage area where it was declared. The local variable is its storage location.

You can only access an object outside a function where it was created if it is in the static area already present in the code or in the heap, where you are responsible for lifespan of the object.

Understand What are and where are the "stack" and "heap"?.

When you have to receive a text that comes from a function the correct is to allocate the memory in the function that will use and pass the address of this allocated location to the function that will generate the text, so this function has all the responsibility to allocate and free the memory. Always do so. All C’s philosophy is upon that.

There are those who think that a lot of code and allocation should go in the function that generates the text, but this is not appropriate. It works on simple systems, but starting to do bigger things is too risky to have to manage allocation and release in different places.

If you use the text only there and it is guaranteed that it is not absurdly large you can allocate in stack. So just declare the array and don’t need to release because what’s in stack is automatically managed.

But there is a problem, it requires you to make a copy of the text. If it is small all right, if it is large it is not efficient. The solution given in the other answer does not work in all situations and has compiler that even compiles.

So almost always the solution is to allocate heap.

I made an example of the wrong way that is to allocate memory in heap within the function that generates the text and let whoever calls that function worry about the release. But this gives room for the person to forget to do or do at the wrong time, creating serious problems. You are responsible for managing the lifetime of the object in the heap. So it’s always best to pair up malloc() and free().

How dynamic allocation in heap may fail you have to check if it worked before doing anything in this memory position.

I copied also because to work in any situation. So in this case also is not efficient.

So what’s the solution? The first example of the question is the best form in most cases, because it only takes text that is already in static area efficiently. It will only give problem if you need to change this value. You can not touch the static area, then just copying it. Most of the time do not need to move.

I would only change the type of returns to char *.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void teste(char texto[10]) {
    strcpy(texto, "Ponteiro"); //isto não é seguro, mas sabemos que funciona neste caso
}

char *teste2() {
    char *texto = malloc(10);
    if (texto != NULL) strcpy(texto, "Ponteiro"); //neste caso dá para eliminar isto, deixei porque o normal é fazer assim
    return texto;
}

int main () {
    char texto[10];
    teste(texto);
    printf("\nRESULTADO: %s\n", texto);
    //segunda forma não recomendada
    char *texto2 = teste2();
    if (texto2 != NULL) {
        printf("\nRESULTADO: %s\n", texto2);
        free(texto2); //tem que librar a memória que foi alocada por outra função
    }
}

Behold working in the ideone. And in the repl it.. Also put on the Github for future reference.

See more in:

  • So, how would I return a string allocated in a variable?

  • You cannot do it by copying, which is not efficient. So you have to allocate somewhere other than the variable, as I put it in the answer. I edited to put new ones links. This question of how to do has been answered before in other questions.

2

Why is the first right and the second wrong?

The first one works because when your program runs it first allocates a space for that constant string, and stores that value in that space. So when it runs return "Ponteiro"; he already knows the address of this constant string and returns that address.

The second does not work, because when the function void *teste() finished running, what has been allocated within its scope is out of focus (with the exception of what is allocated in the heap - malloc/calloc).


Return an allocated string in a variable?

I’ll give you two examples of how to do this, first the stack and the other using the heap (malloc/calloc)

Using the Stack

void *teste(char *p);

int main () {
    char p[10];
    printf("\nRESULTADO: %s\n", teste(&p));
    return 0;
}

void *teste(char *p){
    p ="Ponteiro";
    return p;
}

It is guaranteed that this will work because char p[10]; will only be displaced when the main() end, I mean, I will have done everything I wanted with the variable before it is displaced.

Using the Heap

void *teste(char *p);

int main () {
    char *p = (char *) malloc(sizeof(char)*10);

    if(p == NULL) {
        printf("Não foi possivel alocar 10bytes para o array p");
        return -1;
    }

    printf("\nRESULTADO: %s\n", teste(p));
    free(p);
    return 0;
}

void *teste(char *p){
    p ="Ponteiro";
    return p;
}

Note that any function one can allocate and dislocate using malloc/free, so that you can make your variable live longer than the end of a function X whichever.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.