6

I'm trying to understand why the following string passing works for my error string. I have made this example from a much bigger source I have.

My question is; why don't I have to specifically allocate memory for the char array which contains my error message? I would have thought that I need to malloc some memory for the string and use the err pointer to indicate the start of this memory.

Is this to do with that fact that its a const char * or is is because I'm printing to stderr?

I'm possibly wording the question wrong which is why searches haven't helped me to understand this.

const char * my_function(int a)
{
     if (a != 1)
         return "a doesn't equal 1!"
     else
         return NULL;

}

int main(int a)
{
    const char *err;
    err = my_function(a);
    if (err)
         fprintf(stderr, "Message = %s\n",err);
         return 1;
    return 0;
}
Yu Hao
  • 119,891
  • 44
  • 235
  • 294
Markus
  • 589
  • 1
  • 6
  • 19
  • 2
    see: http://stackoverflow.com/questions/4836534/returning-a-pointer-to-a-literal-or-constant-character-array-string – flyx Sep 18 '13 at 06:15

6 Answers6

10

All string literals are allocated at compile time. They already reside in a read-only section of the program memory when your program is started; they aren't allocated in runtime. You can regard them as constant character arrays. And like any const variable, they remain valid throughout the whole execution of the program.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • "All string literals are allocated at compile time." - For me, this was the most helpful part of all the answers given. – Markus Sep 18 '13 at 06:27
  • 3
    "All string literals are allocated at compile time." Is this wording really correct? I believe nothing is allocated at compile time. If it's allocated at compile time when is it deallocated then? – Kolyunya Sep 18 '13 at 06:32
  • @Kolyunya Link time then, if you are picky. String literals are typically placed in a section of memory called `.rodata`. – Lundin Sep 18 '13 at 06:36
  • That is because the string in your sub routine is stored in the shared segment (read only), and it can be returned after the routine exits. If you define it as char str[]="your string", you will not be able to return the value because it's "allocated" on stack. The stack pointer will resume at the end of sub routine. So @Ludin's answer is only partial here. – TwoCode Sep 18 '13 at 06:45
3

String literals are allocated as const char arrays with static storage duration, so they live for the entire lifetime of the program. The scope they happen to be in is irrelevant -- they always have static storage duration.

That means you can take their address (which happen implicitly if you return a string literal or store it in a const char * variable anywhere) without having to worry about the lifetime of the resulting pointer. The storage for the string literal will never be used for something else.

Chris Dodd
  • 119,907
  • 13
  • 134
  • 226
2

You're returning string literal. It's being held in static memory, but has an address like any other string. So you can refer to that address at any time. Problem would be if you tried to change string literal, which I believe is an undefined behaviour.

zubergu
  • 3,646
  • 3
  • 25
  • 38
2

Please note that your main() will always return 1.

int main(int a)
{
    const char *err;
    err = my_function(a);
    if (err)
         fprintf(stderr, "Message = %s\n",err);
         return 1;
    return 0;
}

The return 1 is indented as if it's under the if (err), but it is not. What you really have is:

int main(int a)
{
    const char *err;
    err = my_function(a);
    if (err)
         fprintf(stderr, "Message = %s\n",err);
    return 1;
    return 0; # Never gets executed.
}

What you want is:

int main(int a)
{
    const char *err;
    err = my_function(a);
    if (err) {
         fprintf(stderr, "Message = %s\n",err);
         return 1;
    }
    return 0;
}

It's for this reason that I always use braces around my blocks, even when they are not strictly necessary.

Andy Lester
  • 91,102
  • 13
  • 100
  • 152
1

It is because the string is stored in the data section of your program. When you type "a doesn't equal 1!", memory is allocated and that value is written into it.

You function merely returns the pointer to that slice of memory and fprintf is happy to read from it.

Bart Friederichs
  • 33,050
  • 15
  • 95
  • 195
  • So how much memory is allocated? Just enough for my returned string? – Markus Sep 18 '13 at 06:19
  • What if I had another function which returned a const char * to the same address? but was longer? – Markus Sep 18 '13 at 06:20
  • Just enough for your string, check out the resulting assembly to find out how it works. – Bart Friederichs Sep 18 '13 at 06:22
  • I don't understand your second question, what do you mean with "but was longer" ? Another function returning the same pointer, would work without issue. You can use `%p` in `printf` functions to see the actual address of where the pointer points to. – Bart Friederichs Sep 18 '13 at 06:24
  • From Lundin's comment I understand now that all the string literals are allocated memory when the program runs. When I am passing back the pointer to a different string literal I'm not changing the memory at that address but returning a pointer for a different location in read-only memory. – Markus Sep 18 '13 at 06:33
  • 1
    @Markus String literals are "allocated" when the program **compiles** (when run, the OS will copy code and data into memory, basically allocating actual memory for them). They are stored inside the binary. You can use a tool like `strings` on Unix to view them. – Bart Friederichs Sep 18 '13 at 07:43
0

Don't be too optimistic. That is because the string in your sub routine is stored in the shared segment (read only), and it can be returned after the routine exits. If you define it as char str[]="your string", you will not be able to return the value because it's "allocated" on stack. The stack pointer will resume at the end of sub routine.

TwoCode
  • 127
  • 7