4
char* test() {
    char* returnValue = "test";
    return returnValue;
}  
char* test=test();
printf("%s",test);

is it safe to use? is it the same, as

char* test {
    char* returnValue=strdup("test");
    return returnValue;
}
char* test=test();
printf("%s",test);

if yes, then should I free it later on? they are both seem to work correctly.

alk
  • 69,737
  • 10
  • 105
  • 255
Art Em
  • 141
  • 1
  • 7
  • 2
    Each call to `malloc` (`strdup` uses `malloc`) wants a call to `free`, and yes, the first snippet is safe but `test` is not modifiable. – David Ranieri Jan 06 '18 at 09:49
  • why is it not modifiable? if i have an access to this variable outside of the function, then it means, that it's located on the heap? otherwise, it would be destroyed as soon as the function finishes? – Art Em Jan 06 '18 at 09:55
  • Because string literals are tipically stored in read only areas (`.rodata`), those areas persist even when we exit from the function. – David Ranieri Jan 06 '18 at 09:57
  • And even if you were able to modify the resulting string from the first example, that change would be permanent and subsequent calls to `test()` would return the address of that same changed string. That's definitely not what you want. – cmaster - reinstate monica Jan 06 '18 at 10:05

4 Answers4

3

is it the same

No, it isn't.


char * test1() {
  char * returnValue = "test";
  return returnValue;
}  

The above code returns the fixed address to the constant literal "test". This will be the same address each time the function is called.

It is not a dynamical allocation of memory.

Doing

printf("%d\n", test1() == test1());

will print

1

meaning "true", the two addresses returned are the same.

On "constness"

To better reflect the constness of the result of test1() it should better be defined as follows:

const char * test1() {
  const char * returnValue = "test";
  return returnValue;
}  

char * test2 {
  char * returnValue = strdup("test");
  return returnValue;
}

The above code returns the address to a freshly allocated area of memory having been copied "test" into. This will be a different*1 address each time the function is called.

*1: "different" at least, as long as the result of any previous call to test2() had not been free() ed already

This is a dynamical allocation of memory. It therefore requires a call to free() passing in the address returned by strdup() (which internally calls malloc()) to deallocated the memory, if not needed any more.

Doing

printf("%d\n", test2() == test2()); /* leaks memory: 2 times 4+1 char */

will print

0

meaning "false", the two addresses returned are different.

For completeness: To avoid the leak as per the above snippet do

char * p, * q;
printf("%d\n", (p = test2()) == (q = test2()));
free(p);
free(q);

is it saft to use

Formally the code of both snippets is correct.

Which one to use and if the use if "safe" completely depends on the use case, on the the context.

alk
  • 69,737
  • 10
  • 105
  • 255
2
char* test() {
    char* returnValue = "test";
    return returnValue;
}  

is it safe to use?

Yes, as long as you are not trying to modify the returnValue which is a string literal. The string literals have static storage duration, so they are alive throughout the lifetime of the program but attempt to modify the content of string literal is undefined behavior.

is it the same, as

char* test {
    char* returnValue=strdup("test");
    return returnValue;
}

Answer is - No

strdup()

Returns a pointer to a null-terminated byte string, which is a duplicate of the string pointed to by str1. The returned pointer must be passed to free to avoid a memory leak.

The strdup() uses malloc() to obtain memory for the new string, here the new string is "test". It stays allocated until it is explicitly deallocated or until the program ends. So, it should be freed using free() once you are done with it. Also, you can modify the content of string returned by strdup() but make sure to not to access beyond the allocated memory chunk.

H.S.
  • 11,654
  • 2
  • 15
  • 32
1

is it safe to use?

Yes, unless you try to change the string. There is no allocation in fact, so each time your function will return exactly the same pointer to the same location in memory.

is it the same, as

No, the strdup() makes an allocation and returns new allocated memory.

if yes, then should I free it later on?

It is no, but still you need to free the memory after strdup() later on.

they are both seem to work correctly

For printf() it is fine, unless you try to change those strings... You will not be able to change the char* returnValue = "test" string, but you will be able to change the string after strdup()

Andriy Berestovskyy
  • 8,059
  • 3
  • 17
  • 33
0

In both cases, "test" is allocated in the Stack as a read-only portion of memory (const char).

In the first block, you return a pointer to "test". As said before, this will be always the same value across calls to the function. Due to its read-only property, trying to free or modify it, will raise an execution error (munmap_chunk(): invalid pointer when trying to free, Segmentation fault when trying to modify).

In the second block, you return a pointer to a dynamically allocated portion of memory in the Heap. It's your responsibility to free this portion of memory using free() or equivalent. You are free to modify this variable, or even reallocate this portion of memory.

You can always do your own tests:

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

char* test1() {
    char* returnValue = "test";
    return returnValue;
}  
char* test2() {
    char* returnValue = strdup("test");
    return returnValue;
}

int main(void)
{
   char* vtest1 = test1();
   printf("%s => %p\n", vtest1, &vtest1);
   char* vtest2 = test2();
   printf("%s => %p\n", vtest2, &vtest2);

   printf("Freeing 2nd test...\n");
   free(vtest2);

   printf("Trying to modify 1st test...\n");
   vtest1[0] = 'p';
   printf("Freeing 1st test...\n");
   free(vtest1);

   return 0;
}
emi
  • 2,786
  • 1
  • 16
  • 24
  • _as a read-only portion of memory (const char)_, this is confusing as none of them are `const` – David Ranieri Jan 06 '18 at 10:15
  • `"test"` is implicitly `const char`. All strings defined inside the code (using quotes) are `const char`. – emi Jan 06 '18 at 10:36
  • "*In both cases, "test" is allocated in the Stack ....*" C does not even know a "stack". Where the literals go is completely implementation defined. – alk Jan 06 '18 at 10:38
  • 1
    @emi: nops, they are of type `char *` (but not modifiable): https://stackoverflow.com/questions/4493139/are-string-literals-const – David Ranieri Jan 06 '18 at 10:38
  • @KeineLust : nops, it is `returnValue` which is `char *`. In the case of `"test"` are literals, which are of type `const char *`. – emi Jan 06 '18 at 10:44
  • "*... literals, which are of type `*const char`*" This might be the case in C++, in C they are "just" `char*`. [See the C11 Standard somewhere under 6.4.5](http://port70.net/~nsz/c/c11/n1570.html#6.4.5). – alk Jan 06 '18 at 10:47
  • @emi: you are wrong, there is no `const` involved in the OPs code, question is tagged C not C++ – David Ranieri Jan 06 '18 at 10:48