Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

return a string from a function 5

Status
Not open for further replies.

robUK2

Programmer
Mar 10, 2008
57
TH
Hello,

I have a short example of a C library that I have coded below along with the header. I am calling this function from a C++ client app.

Some of the warning I get are as follows. This normally gives me a segmentation stack run time error. So I guess some about memory not been allocated being assigned to null address.

warning: return from incompatible pointer type
warning: function returns address of local variable

I have tried many different ways to do this. As you can see from my commenting out pieces of code.

However, I can return pointer without any problems. However, my code needs to return a string array. i.e. char msgTest[] = "Hello how are you";

Can any one offer any advice on this?

Many thanks for any suggestions.

Code:
//C library code
//Header cHeader.h
#ifdef __cplusplus 
extern "C"
{
#endif
	char* returnMessage(char *message);
#ifdef __cplusplus
}
#endif

//Implementation cDriver.c
char* returnMessage(char *message)
{
	printf("Message: %s\n", message);
	
	char *msg = NULL;
// 	//msg = message;
// 	printf("msg = message: %s\n", msg);
// 	//strcpy(msg, message);
// 	printf("strcpy(msg, message): %s\n", msg);
	
	char msgTest[] = "Hello how are you";
	strcpy(msg, msgTest);
	return &msgTest;
}

And the C++ code for calling the above function.
Code:
int main(int argc, char** argv)
{
	char *ptrTest = NULL;
	char test[] = "Hello";
	ptrTest = test;
	char *ptrRtn = NULL;

	ptrRtn = returnMessage(ptrTest);
	cout << "PtrRtn: " << ptrRtn << endl;

        return 0;
}
 
Code:
char msgTest[] = "Hello how are you";
This is a local variable allocated on the stack, so if you return a pointer to it, you're returning a pointer to a variable that no longer exists and could be overwritten at any moment.
If you want to return a string from a function, you either need to make the variable static which means it doesn't get deleted once the function ends (although then your function isn't thread-safe); or you need to allocate memory for the new string (using malloc() ) and copy the string into it (using strcpy() or strncpy() ).
If you return a pointer to memory you allocated in a function, you need to remember to free that memory later, so it might be better to pass a pointer into the function along with the size it can store, then you don't have to allocate the memory inside the function.

Code:
#include <stdio.h>
#include <string.h>
#define STR_SIZE 80

void GetString( char* strOut, unsigned int strSize )
{
   strncpy( strOut, "Hello World", strSize );
}

int main()
{
   char buf[STR_SIZE + 1];

   GetString( buf, STR_SIZE );
   printf( "%s", buf );
   return 0;
}
 
Hello,

thanks for the reply,

i have used malloc, which worked. Howerver, At which point do I free the memory? As I can't do it after I have returned, or after I have copied the contents?

Code:
char* returnMessage(char *message)
{
	printf("Message: %s\n", message);
	
	char *msg = (char *) malloc(sizeof(char));
	
	char msgTest[] = "Hello how are you";
	
	strncpy(msg, msgTest, sizeof(msgTest));
	
        //when to free the memory that has been allocated.
	return msg;
}

I have noticed I get a stack dump.

Many thanks,
 
Minor bug in your memory allocation.
Code:
char* returnMessage(char *message)
{
    printf("Message: %s\n", message);
    char msgTest[] = "Hello how are you";
    
    // Allocate the space required: not 1 character
    char *msg = (char *) malloc(strlen (msgTest) + 1);
        
    strncpy(msg, msgTest, sizeof(msgTest));
    
        //when to free the memory that has been allocated.
    return msg;
}
You could also use strdup
Code:
char* returnMessage(char *message)
{
    printf("Message: %s\n", message);
    char msgTest[] = "Hello how are you";
    
        //when to free the memory that has been allocated.
    return strdup (msgTest);
}
You free it when you no longer need it.

Warning about using sizeof and strlen. Sizeof is compile time, strlen is runtime. If you are using pointers, sizeof will always return the same result. If you're passing strings into routines, it is better to use strlen.
Code:
char str1[] = "seven";
char* str2  = "seven";
printf ("sizeof str1=%d str2=%d\n", sizeof(str1), sizeof(str2));
printf ("strlen str1=%d str2=%d\n", strlen(str1), strlen(str2));
 
Hello,

Thanks for your help. I have used the code below:
Code:
char* returnMessage(char *message)
{
	printf("Message: %s\n", message);
	
	char msgTest[] = "Hello how are you";

	char *msg = (char *) malloc(strlen(msgTest) + 1);

	strncpy(msg, msgTest, sizeof(msgTest));
	
	return msg;
}

What is the purpose of adding 1 to the string length. Is this for safety?

Why would having a static variable be not thread safe?

Just a final question about freeing memory that has been allocated. As the function returnMessage allocated memory, how can I free that in the calling function, as it will not have scope?

Many thanks,

 
Hello,

When freeing memory I have freed the memory in the calling function. As below.
Code:
int main(int argc, char** argv)
{
	char *ptrTest = NULL;
	char test[] = "Hello";
	ptrTest = test;
	char *ptrRtn = NULL;

	ptrRtn = returnMessage(ptrTest);
	cout << "PtrRtn: " << ptrRtn << endl;
        
        free(ptrRtn); //Freeing the memory that was allocated in the returnMessage function.
        return 0;
}
Any corrections please advise,

Thanks,
 
rokUK2 said:
What is the purpose of adding 1 to the string length. Is this for safety?

Why would having a static variable be not thread safe?
All valid C strings end with a NUL character (i.e. '\0'), which isn't included in the length reported by strlen()... Without the NUL character, there's no way for something like puts() or printf() to know where the string ends. So you need to add 1 character for the '\0'.

As for static variables not being thread-safe, consider the gmtime() function which converts a time_t value into a tm* struct. Since the tm* pointer it returns points to a static tm struct inside the function, that data gets overwritten the next time the function is called. And static data is shared between threads.
So thread1 calls gmtime() and starts reading the tm* struct it returns, then thread2 calls gmtime() and gets a tm* struct which has changed some of the data in that struct. So now when thread1 continues reading its tm* struct, it's reading the data that thread2 changed.
 
As far I know you allready got an solution.
But I do not like to allocate memory where someone has to free somewhere!
Remember, in ANSI C a function can return against normal data types (like int, chr ...) also return abstract data type (what means a structur and typedef). An that works so easy. You may define a structur fill it out and return it. The structure will be put to sthe stack an copied to the assigned structure.
Look at my code snipe:


/* Code */
struct a { char str[200]; int i };

struct a func1() {
struct a func_a;
strcpy(func_a.str,"my string return");
func_a.i = 99;
return func_a;
};

main() {
struct a main_a;
strcpy(main_a.str,"my string return");
main_a.i = 99;
printf("before func1 call str=%s i=%d\n",
main_a.str,main_a.i);
main_a = func1();
printf("after func1 call str=%s i=%d\n",
main_a.str,main_a.i);
exit(0);
};
 
Two remarks on your code :
1) It only works when the length of the strings are less than 200, when you don't know the length it may be risky...
2) It takes a long time when copying all the bytes at the return of the function, it is preferable to copy only an address, and we get back to the code of xwb.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top