skip to Main Content

Usually I develop in PHP. But for a project I have to develop a small program in C (using Visual Studio on Windows)
To simplify my code I created a function that returns a string (the function is more complex than in the example).

Initially I had a warning C4172: returning address of local variable or temporary [duplicate]
I modified my function to no longer have this warning. And it works.
But is the code right…?

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

// Declaration Function
char* getMyString();

//----------------------------//
// Function getMyString()     //
//----------------------------//
char* getMyString()
{
  char* response = NULL;
  response = (char*)malloc(5 * sizeof(char)); if (response == NULL) exit(EXIT_FAILURE);

  strcpy(response, "EFGH");

  return response;
}



//--------------------------------------------------//
//                    Main Program                  //
//--------------------------------------------------//
int main(int nbArg, char** listeArg)
{
  // Initialization
  char* myStringFull = malloc(10 * sizeof(char)); if (myStringFull == NULL) return EXIT_FAILURE;
  char* myString = NULL;

  // Get String with Personnal Function
  myString = getMyString();

  // Finalization
  strcpy(myStringFull, "ABCD");
  strcat(myStringFull, myString);

  // Display
  printf("n%snn", myStringFull);

  // Free Memory
  free(myStringFull);
  free(myString);

  return(EXIT_SUCCESS);
}

And if above code is right, can I use the code below to further simplify my code…?
And if I can how it happens in memory because for this last code I can not free the memory used by the function

int main(int nbArg, char** listeArg)
{
  // Initialization
  char* myStringFull = malloc(10 * sizeof(char)); if (myStringFull == NULL) return EXIT_FAILURE;

  // Finalization
  strcpy(myStringFull, "ABCD");
  strcat(myStringFull, getMyString());

  // Display
  printf("n%snn", myStringFull);

  // Free Memory
  free(myStringFull);


  return(EXIT_SUCCESS);
}

Hope my question isn’t too silly but there is a big, huge, abyssal gap between PHP and C 🙂

3

Answers


  1. What you did is correct. However, you’ve noticed that it’s quite a bit of work, and you have to remember to free the allocated memory afterwards. If possible, I would use C++ so you can return a std::string without worries, much like you would do in PHP and many other languages.

    There are other functions that might help you create strings in C. For example, copying strings can be done by the POSIX function strdup(). You can also use asprintf() on GNU and BSD platforms.

    Instead of allocating memory, you could also print into a buffer. To do that from a function, you would pass a pointer to the buffer and its size to that function. For example:

    void getMyString(char *buf, size_t size) {
        snprintf(buf, size, "EFGH");
    }
    
    int main(int argc, char *argv[]) {
        char myStringFull[10];
        int pos = snprintf(myStringFull, sizeof myStringFull, "ABCD");
        getMyString(myStringFull + pos, sizeof myStrinfFull - pos);
        printf("%sn", myStringFull);
    }
    

    Note that the above is still missing error checking; the return value of snprintf() is the number of characters that would have been written if the buffer was large enough, or possibly a negative number indicating an error.

    Login or Signup to reply.
  2. There are three main ways to do what you want:

    1. You can just declare a static buffer with enough space to hold the data when the function is not in use
    char *func(...)
    {
        static char my_buffer[1000]; /* enough space for the biggest answer */
        /* do some calculations to fill my_buffer */
        return my_buffer;  /* return a pointer to the prepared data */
    }
    

    This solution has the drawback that it is not reentrant, so if two threads try to use it at the same time, bot executions will overwrite the buffer and the result will be trashed.

    1. You can allocate dynamic memory wit malloc(3), and return the pointer to the allocated memory. This has the drawback that the calling routine is responsible (and must know) of free(3)ing the memory once it’s not neede anymore.
    char *func(...)
    {
        char *ret_val = malloc(/* enough space to hold the data */);
        /* blah blah... */
        return ret_val;
    }
    

    This solution makes the calling code responsible or returning the memory and so, is error prone.

    1. You can pass a local, already allocated buffer from the calling code, and it’s size. You can use that buffer to hold the requested data, and then return a valid pointer to the place where your string starts (I neither has to be from the beginning of the buffer)
    char *func(char *buffer, size_t siz)
    {
        /* sample code */
        snprintf(buffer, siz, "Hello, worldn");
        return buffer;
    }
    /* ... */
    void calling_code()
    {
        char buffer[100];
        printf("the string is [%s]n", func(buffer, sizeof buffer));
    }
    

    This approach gives the caller the responsibility of allocating the space, and so, it doesn’t have to be dynamic, can be local space, as you pass the reference to it and its size.

    You can select the one best fits you, but from my point of view the more flexible is the last one. Just try them all.

    Login or Signup to reply.
  3. A string in C is just a sequence of characters in an array, but you can’t return an array from a function, so you can’t directly return a ‘string’.

    What C functions usually do is pass the array (and size) as an argument to the function and have the function put the string in the array to "return" it. Stdlib functions like fgets and snprintf work this way; their first and second arguments are a pointer to an array and the size of that array. In your case that would be something like:

    char* getMyString(char *buffer, size_t len) {
        snprintf(buffer, len, "%s", "EFGH");
        return buffer;
    } 
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search