1

I have a device that can either be a "Router" or a "Switch". I use the below function, passing it an enum that returns me the string. My question is that the memory for whoami is allocated on the stack. When this function devicetype_string finishes, the stack is destroyed. Would this not cause an issue when i use a pointer thats pointing to a memory allocated on the stack?

The current code works. I just want to understand why it works. I would presume that a cleaner and a portable solution would be to malloc memory to hold whoami (so that it goes to the heap) and the calling function should free that memory.

This is the current program:

char *devicetype_string (FwdrType devicetype)
{
    char *whoami;

    switch (devicetype)
    {
        case FWDR_TYPE__ROUTER:
            whoami = "Router";
            break;

        case FWDR_TYPE__SWITCH:
            whoami = "Switch";
            break;

        default:
            whoami = "Fwder Type UNKNOWN";
    }

    return whoami;
}

foo()
{
    . . .
    FwderType abc = FWDR_TYPE__ROUTER;

    printf ("%s", devicetype_string(abc));
}
trincot
  • 317,000
  • 35
  • 244
  • 286
Toms
  • 102
  • 1
  • 6
  • You don't see a problem with assigning strings?? `whoami = "Switch";` Enter the world of Undefined Behavior. – David C. Rankin Sep 09 '14 at 05:54
  • @DavidCRankin can you elaborate on that? – M.M Sep 09 '14 at 06:00
  • 2
    You should really be using `const char*` rather than `char*`; you'll get undefined behaviour if you try use this non-const pointer to modify the string literal it points to. – Mike Seymour Sep 09 '14 at 06:00

2 Answers2

7

It's not memory leak, and it's not undefined behavior.

In the function devicetype_string, whoami points to a string literal in all paths. String literals have static storage duration, they don't need to be freed.

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
  • Thanks. Assume that i was not using a string literal. In that case i should use a malloc inside devicetype_string() a pointer to which is returned to the calling function. Its that function then who should free the memory pointed to by the pointer. We need to use malloc so that its placed in the heap which is available to other functions outside the one in which the memory was allocated. If i use a local variable inside devicetype_string then it will be placed on the stack and i would lose that once the function finishes. Is my understanding correct? – Toms Sep 09 '14 at 10:08
2

It works because you're returning a pointer to a static string, which isn't created on the stack - they instead have static storage duration, meaning they will be valid for the duration of your program.

See this question

Something else to note:

String literals are typically stored in the read-only-data section. Attempting to assign a writeable char* to a string literal, which is probably read only (probably because where literals are stored is actually platform specific) and then modify the contents will trigger undefined behaviour, often a segmentation fault (attempting to modify the read-only-data section).

GCC will fail to compile, not allowing assigning a writeable char* to a string literal.

A better implementation would not be to assign your char* pointer, but just to return the address of the string literal as a const char*

const char *devicetype_string (FwdrType devicetype)
{
    switch (devicetype)
    {
        case FWDR_TYPE__ROUTER: return "Router";
        case FWDR_TYPE__SWITCH: return "Switch";
        default: break;
    }
    return "Fwder Type UNKNOWN";
}
Community
  • 1
  • 1
Steve Lorimer
  • 27,059
  • 17
  • 118
  • 213
  • It is not UB to assign a string literal to a `char *`. A problem only arises if you actually try to write to the contents of the string literal. If a compiler fails to compile this (for that reason), the compiler is broken. – M.M Sep 09 '14 at 05:59
  • @MattMcNabb I think it's a limitation in the beginning of the identifier. – BLUEPIXY Sep 09 '14 at 06:06
  • @BLUEPIXY that's not quite correct. The rules prohibit identifiers containing adjacent underscores. See [here](http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier) – Steve Lorimer Sep 09 '14 at 06:09
  • @SteveLorimer 7.1.3 Reserved identifiers write _All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use. All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces._ – BLUEPIXY Sep 09 '14 at 06:19
  • 2
    @BLUEPIXY you are correct - C++ 17.4.3.2.1 reserves double underscores in an identifier. Since this question is tagged as C not C++, that does not apply. – Steve Lorimer Sep 09 '14 at 06:24
  • @SteveLorimer yes. It seems there is no such restriction in the standard C. – BLUEPIXY Sep 09 '14 at 06:26