Accessing local variable

B

bauran

#include<stdio.h>
char * fun()
{
char *p="happy";
return p;
}
int main()
{
char *c;
c=fun();
printf("%s",c);
}

In the above C program, I am returning a local pointer p from fun(),
so is it undefined behaviour?
 
B

Ben Bacarisse

bauran said:
#include<stdio.h>
char * fun()
{
char *p="happy";
return p;
}
int main()
{
char *c;
c=fun();
printf("%s",c);
}

In the above C program, I am returning a local pointer p from fun(),
so is it undefined behaviour?

No. No more than a program that returned a "local int" would be
undefined. Problems come from returning pointers *to* things that are
local (specifically local things that are about to disappear).
 
J

jameskuyper

bauran said:
#include<stdio.h>
char * fun()
{
char *p="happy";
return p;
}
int main()
{
char *c;
c=fun();
printf("%s",c);
}

In the above C program, I am returning a local pointer p from fun(),
so is it undefined behaviour?

No. The fact that a pointer object is local is not what matters. What
matters is the storage duration of the object that the value of the
pointer points at. The value of p points at the 'h' in "happy", which
is an unnamed 6-element array of char with static storage duration.
Therefore, it's perfectly safe to return the value of 'p'.

However, any attempt to modify the contents of that array has
undefined behaviour. I would therefore recommend that both 'p' and
'fun' be changed to 'const char*', for safety.
 
B

bauran

No.  No more than a program that returned a "local int" would be
undefined.  Problems come from returning pointers *to* things that are
local (specifically local things that are about to disappear).

--
Sorry I didn't get you.
If we write
char * fun()
{
char p[]="happy";
return p;
}

Then would it be undefined behaviour and why?
 
J

jameskuyper

bauran said:
....
If we write
char * fun()
{
char p[]="happy";
return p;
}

Then would it be undefined behaviour and why?

The behaviour of fun() would still be defined. However, that change
will cause main() to have undefined behaviour.

That is because in this case, the 'p' in your return statement is the
name of an array, which gets automatically converted to a pointer to
the first element of that array, and the array has automatic storage
duration. That array ceases to exist as soon as your function returns,
which means that when the pointer's value is actually dereferenced in
the call to printf(), the behavior will be undefined.

In your previous example, the value returned pointed at the first
element of an array with static storage duration, and that array
continued to exist even after the end of the call to fun(). As a
result, there was no problem.
 
B

bauran

bauran said:
#include<stdio.h>
char * fun()
{
 char *p="happy";
 return p;
}
int main()
{
 char *c;
 c=fun();
 printf("%s",c);
}
...
If we write
char * fun()
{
 char p[]="happy";
 return p;
}
Then would it be undefined behaviour and why?

The behaviour of fun() would still be defined. However, that change
will cause main() to have undefined behaviour.

That is because in this case, the 'p' in your return statement is the
name of an array, which gets automatically converted to a pointer to
the first element of that array, and the array has automatic storage
duration. That array ceases to exist as soon as your function returns,
which means that when the pointer's value is actually dereferenced in
the call to printf(), the behavior will be undefined.

In your previous example, the value returned pointed at the first
element of an array with static storage duration, and that array
continued to exist even after the end of the call to fun(). As a
result, there was no problem.- Hide quoted text -

- Show quoted text -

Thanks a lot.
 
S

Seebs

Sorry I didn't get you.

You should explain in more detail what you don't get.
If we write
char * fun()
{
char p[]="happy";
return p;
}

Then would it be undefined behaviour and why?

Yes. In that case, p is an automatic array, and the array's lifetime ends
at the end of the function.

In the previous example, p was an automatic pointer to a string literal,
and the lifetime of a string literal is the whole lifetime of the program,
so the pointer stays valid.

-s
 
U

user923005

No.  No more than a program that returned a "local int" would be
undefined.  Problems come from returning pointers *to* things that are
local (specifically local things that are about to disappear).

Sorry I didn't get you.
If we write
char * fun()
{
 char p[]="happy";
 return p;

}

Then would it be undefined behaviour and why?

Your question is found in the C-FAQ.

7.5a: I have a function that is supposed to return a string, but
when
it returns to its caller, the returned string is garbage.

A: Make sure that the pointed-to memory is properly allocated.
For example, make sure you have *not* done something like

char *itoa(int n)
{
char retbuf[20]; /* WRONG */
sprintf(retbuf, "%d", n);
return retbuf; /* WRONG */
}

One fix (which is imperfect, especially if the function in
question is called recursively, or if several of its return
values are needed simultaneously) would be to declare the
return
buffer as

static char retbuf[20];

See also questions 7.5b, 12.21, and 20.1.

References: ISO Sec. 6.1.2.4.

7.5b: So what's the right way to return a string or other aggregate?

A: The returned pointer should be to a statically-allocated
buffer
(as in the answer to question 7.5a), or to a buffer passed in
by
the caller, or to memory obtained with malloc(), but *not* to
a
local (automatic) array.

See also question 20.1.

P.S.
I think that the ISO reference should be 6.2.1.4 rather than 6.1.2.4

From WG14/N1256 Committee Draft — Septermber 7, 2007 ISO/IEC 9899:TC3,
pages 29, 30:
"6.2.1 Scopes of identifiers"
Item 4:
"4 Every other identifier has scope determined by the placement of its
declaration (in a declarator or type specifier). If the declarator or
type specifier that declares the identifier appears outside of any
block or list of parameters, the identifier has file scope, which
terminates at the end of the translation unit. If the declarator or
type specifier that declares the identifier appears inside a block or
within the list of parameter declarations in a function definition,
the identifier has block scope, which terminates at the end of the
associated block. If the declarator or type specifier that declares
the identifier appears within the list of parameter declarations in a
function prototype (not part of a function definition), the identifier
has function prototype scope, which terminates at the end of the
function declarator. If an identifier designates two different
entities in the same name space, the scopes might overlap. If so, the
scope of one entity (the inner scope) will be a strict subset of the
scope of the other entity (the outer scope). Within the inner scope,
the identifier designates the entity declared in the inner scope; the
entity declared in the outer scope is hidden (and not visible) within
the inner scope."
 
M

Michael Tsang

bauran said:
#include<stdio.h>
char * fun()
{
char *p="happy";
This is deprecated conversion. Better use "const char*" instead.
return p;
Because it's not static, the compiler is free to allocate it on the stack.
}
int main()
Non-prototype function declarations are deprecated. Better use "int
main(void)" instead.
{
char *c;
c=fun();
printf("%s",c);
On some systems, it is a problem not terminates the output with a new-line
character.
}

In the above C program, I am returning a local pointer p from fun(),
so is it undefined behaviour?
The line contains printf is undefined behaviour because printf dereferences
c.
 
N

Nick Keighley

bauran wrote:

This is deprecated conversion. Better use "const char*" instead.

Is that a C99 change? I'm pretty sure it's not deprecated in C89.
Hell, just a minute since when was a string literal of type
"const char*"? I wouldn't have thought even C99 would dare do that.

Could we have chapter and verse?

By the way, I have no argument that it would probably
be better to write the code as you suggest (even though I don't...)

 return p;

Because it's not static, the compiler is free to allocate it on the stack..

what's not static? p? Since it isn't static, yes, the implementation
allocates it in automatic store. Automatic store may be on some sort
of
stack. [please don't start The Stack argument again...].

But then of course the return statement copies the value held in
p. So it doesn't matter that p is an automatic variable.

Do you think this causes a problem?

int g(void)
{
int i;
i = 99;
return i;
}


}

Non-prototype function declarations are deprecated.
Better use "int main(void)" instead.



On some systems, it is a problem not terminates the output with a new-line
character.

}

no. You are not returning a local pointer. You are returning a copy
of the value of a local pointer. Which is fine.
The line contains printf is undefined behaviour because printf dereferences
c.

there is no problem with dereferencing c. The bit you missed was that
although p was local to fun(), the string literal "happy" was not.
String literals have lifetimes equal to the lifetime of the program.
 
J

James Kuyper

Nick said:
Is that a C99 change? I'm pretty sure it's not deprecated in C89.

It isn't.
Hell, just a minute since when was a string literal of type
"const char*"? I wouldn't have thought even C99 would dare do that.

No, but C++ did. It sounds like he's referring to C++ rules rather than
C rules.

However, I approve of the C++ rules, and the change he suggests makes
sense even when using C.
 
C

cognacc

no. You are not returning a local pointer. You are returning a copy
of the value of a local pointer. Which is fine.


there is no problem with dereferencing c. The bit you missed was that
although p was local to fun(), the string literal "happy" was not.
String literals have lifetimes equal to the lifetime of the program.

Is this guaranteed, isnt it just an "accident" of the way the
string literal is stored.
Or in another way is it a good(tm) thing to do
and use the string literal declared in function?
Any Gotcha's ?


mic
 
B

Ben Bacarisse

cognacc said:
Is this guaranteed, isnt it just an "accident" of the way the
string literal is stored.

Yes, it is guaranteed -- by which I mean the language definition says
that the arrays that result from a string literal have "static storage
duration".
Or in another way is it a good(tm) thing to do
and use the string literal declared in function?
Any Gotcha's ?

Your caller might try to change the contents (UB) so it helps to
return the pointer as a const char *.
 
R

Richard Bos

bauran said:
#include<stdio.h>
char * fun()
{
char *p="happy";
return p;
}
int main()
{
char *c;
c=fun();
printf("%s",c);
}

In the above C program, I am returning a local pointer p from fun(),
so is it undefined behaviour?

As a side note: this is a rather often-asked question, but unless I've
been reading sloppily, it is not found in the FAQ. Mr. Summit, if you're
still reading this newsgroup (poor man!): IMO, it should be.

Richard
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top