RHLK
RHLK

Reputation: 347

Returning array from a function back to main

I have a local character array in a function that is manipulated according to the logic in the function. The function return the pointer to the array as follows

char * fn(void)
{
   char str[20] = "Hello";
   cout << str; // This prints the string Hello perfectly
   // Some operations on string
   return str;
}

int main()
{
   char *ptr;
   ptr=fn();
   cout << ptr; // This prints only the first character of the string i.e H
}

How can I pass an array from a function back to main.

I know I should not pass address of a local variable back to main as that stack of the program is modified. But still if I use cout << *ptr then the output is just the first character "H". I solved the problem by using a dynamically allocated memory for the array using "new". But I would like to know the reason behind this behavious (Does this have to do something with Stack ?? )

Upvotes: 0

Views: 124

Answers (5)

Felix
Felix

Reputation: 7146

If you don't want to use std::string oder std::array, just basic C, change the function fn:

void fn(char *target, size_t target_size)
{
   if(target_size < 6)//I used 6 here because thats the size of the string you want write into the array
      return; //If the targets size is to small, the function is cancled
   strycpy(target, "Hello");
   cout << target;
}

int main()
{
   char str[20];
   fn(str, 20);
   std::cout << str;
}

But it generall its better to use std::string as shown above, because this method is unsafe ( Your program will crash if you make target_size bigger then the real size of the array, beause strcpy will write over the arrays limit). Some compilers won't even allow to use this, because of "strcpy".

Another (uncommon) possibility would be to make the array static:

char * fn(void)
{
   static char str[20] = "Hello";
   cout << str;
   return str;
}

Upvotes: 0

Christian Hackl
Christian Hackl

Reputation: 27538

Using std::string will solve all your problems. It's particularly strange that you use C++ streams but C-style strings. Why?

Here's what your code would look like:

#include <string>
#include <iostream>

std::string fn()
{
   std::string str = "Hello";
   std::cout << str; // This prints the string Hello perfectly
   // Some operations on string
   return str;
}

int main()
{
   std::string str = fn();
   std::cout << str;
}

This makes your code cleaner, more robust, exception-safe, easier to read and write and possibly faster. Why in the world wouldn't you do it? (To be fair, there are situations where std::string isn't appropriate, but first, beginners rarely encounter them, and second, such situations typically also outrule C++ streams.)

As for your original solution...

I know I should not pass address of a local variable back to main as that stack of the program is modified.

Great :) But then why do you do it anyway?

But still if I use cout << *ptr then the output is just the first character "H"

Besides the undefined behaviour resulting from returning a pointer to something that doesn't exist anymore, this sort of thing would happen even with a valid char*. After all, dereferencing a char* is not different from dereferencing an int* or a double*. It simply yields a char, and printing a char prints, well, a character.

int *i = new int(123);
std::cout << *i; // prints 123

double *d = new double(0.5);
std::cout << *d; // prints 0.5

char *c = new char('x');
std::cout << *c; // prints x

The fact that there may be more characters stored in memory right after that one dereferenced char is irrelevant. You deliver a char to std::cout, nothing more. If you deliver a char*, everything is different, because std::cout then knows that it must "look for more characters".

Again, using std::string, you don't need to care for these things.

I solved the problem by using a dynamically allocated memory for the array using "new".

Not a good solution, because then you have the issue of who deletes the string. Without a delete[] somewhere at the right location in your code, the memory occupied by the string will never be released until your program terminates, which can lead to memory leaks and your end users wondering why YourProgram.exe suddenly takes 800 MB in the Windows Task Manager :)

Again, use std::string. It frees the allocated memory automatically when it's no longer needed.

Upvotes: 1

Yuvika
Yuvika

Reputation: 6132

Yes by returning str, you are returning an address of the stack memory that no longer exists. The correct way of doing it is to allocate memory, pass it to fn, and then free it so that the same function is allocating and deallocating memory.

Upvotes: 2

John Zwinck
John Zwinck

Reputation: 249462

Yes, it has to do with the "stack." Specifically the "lifetime" of the function-local variable is only until the function ends. And returning the pointer copies only the pointer and not what it points to, so you end up with a dangling pointer and undefined behavior.

This is C++ after all, so the easiest thing to do here is simply make your function return std::string. That way it's a "value" rather than a pointer and returning it will make a copy (n.b. an optimizing compiler can elide the copy, but the functionality will remain the same).

Upvotes: 2

Uzaku
Uzaku

Reputation: 541

if you create the array in the function how you did it, it is in deed created on the stack, and will be destroyed, when you leave the function. A usual way to manipulate arrays through functions would be, to pass the pointer to an already existing array as a function parameter. When you modify it in the function then, it will also be modified outside of the function.

Upvotes: 2

Related Questions