Returning local data from functions in C and C++ v

2019-01-02 16:19发布

I have argument with my friend. He says that I can return a pointer to local data from a function. This is not what I have learned but I can't find a counterargument for him to prove my knowledge.

Here is illustrated case:

char *name() {
    char n[10] = "bodacydo!";
    return n;
}

And it's used as:

int main() {
    char *n = name();
    printf("%s\n", n);
}

He says this is perfectly OK because after a program calls name, it returns a pointer to n, and right after that it just prints it. Nothing else happens in the program meanwhile, because it's single threaded and execution is serial.

I can't find a counter-argument. I would never write code like that, but he's stubborn and says this is completely ok. If I was his boss, I would fire him for being a stubborn idiot, but I can't find a counter argument.

Another example:

int *number() {
    int n = 5;
    return &n;
}

int main() {
    int *a = number();
    int b = 9;
    int c = *a * b;
    printf("%d\n", c);
}

I will send him this link after I get some good answers, so he at least learns something.

13条回答
无与为乐者.
2楼-- · 2019-01-02 16:37

You're right, your friend is wrong. Here's a simple counterexample:

char *n = name();
printf("(%d): %s\n", 1, n);
查看更多
旧时光的记忆
3楼-- · 2019-01-02 16:39

The way I see it you have three main options because this one is dangerous and utilizes undefined behavior:

replace: char n[10] = "bodacydo!"

with: static char n[10] = "bodacydo!"

This will give undesirable results if you use the same function more than once in row while trying to maintain the values contained therein.

replace:
char n[10] = "bodacydo!"

with:
char *n = new char[10]; *n = "bodacydo!"

With will fix the aforementioned problem, but you will then need to delete the heap memory or start incurring memory leaks.

Or finally:

replace: char n[10] = "bodacydo!";

with: shared_ptr<char> n(new char[10]) = "bodacydo!";

Which relieves you from having to delete the heap memory, but you will then have change the return type and the char *n in main to a shared_prt as well in order to hand off the management of the pointer. If you don't hand it off, the scope of the shared_ptr will end and the value stored in the pointer gets set to NULL.

查看更多
何处买醉
4楼-- · 2019-01-02 16:41

As soon as the scope of the function ends i.e after the closing brace } of function, memory allocated(on stack) for all the local variables will be left. So, returning pointer to some memory which is no longer valid invokes undefined behavior. Also you can say that local variable lifetime is ended when the function finished execution.

Also more details you can read HERE.

查看更多
萌妹纸的霸气范
5楼-- · 2019-01-02 16:43

you will get a problem, when you call another function between name() and printf(), which itself uses the stack

char *fun(char *what) {
   char res[10];
   strncpy(res, what, 9);
   return res;
}

main() {
  char *r1 = fun("bla");
  char *r2 = fun("blubber");
  printf("'%s' is bla and '%s' is blubber", r1, r2);
}
查看更多
公子世无双
6楼-- · 2019-01-02 16:50

It's undefined behavior and the value could easily be destroyed before it is actually printed. printf(), which is just a normal function, could use some local variables or call other functions before the string is actually printed. Since these actions use the stack they could easily corrupt the value.

If the code happens to print the correct value depends on the implementation of printf() and how function calls work on the compiler/platform you are using (which parameters/addresses/variables are put where on the stack,...). Even if the code happens to "work" on your machine with certain compiler settings it's far from sure that it will work anywhere else or under slightly different border conditions.

查看更多
梦寄多情
7楼-- · 2019-01-02 16:53

As the others have already pointed out it is not illegal to do this, but a bad idea because the returned data resides on the non-used part of the stack and may get overridden at any time by other function calls.

Here is a counter-example that crashes on my system if compiled with optimizations turned on:

char * name ()
{
  char n[] = "Hello World";
  return n;
}

void test (char * arg)
{
  // msg and arg will reside roughly at the same memory location.
  // so changing msg will change arg as well:
  char msg[100];

  // this will override whatever arg points to.
  strcpy (msg, "Logging: ");

  // here we access the overridden data. A bad idea!
  strcat (msg, arg);

  strcat (msg, "\n");
  printf (msg);
}

int main ()
{
  char * n =  name();
  test (n);
  return 0;
}
查看更多
登录 后发表回答