LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

I do not know why my string return got problem?

I have function calls at main() as:
 
char * string_toUpper(char* str_src )
{
    // This function returns an upper case string of str_src
    char *str_ret;
 
    str_ret = ".......................................................................";
    strcpy(str_ret, str_src);
     StringUpperCase (str_ret);
 
     return str_ret;
}
void main (void)
{
      char *str1, *str2;
      str1 = string_toUpper("louuu");     //   str1 = "LOUUU"
      str2 = string_toUpper("gfffddd");  //    str1 = str2 = "GFFFDDD"     <===  ???????
}
 
Note:
 
1. If I define str_ret with calloc/malloc then it will work ... but then I should have to free it ( no memory leak)
2. I did define as static char str_ret[1000], but the result was the same
 
Does anyone know why and solve the problem (without require an extra argument in the function)?
 
Thanks to any help?
0 Kudos
Message 1 of 5
(3,455 Views)
In short, the reason str1 and str2 have the same value is that they point to the same memory.  Hard-coded strings in your source code (like "..............", "louuu", and "gfffddd") have a special place set aside for them in memory.  These locations never change over the course of your program.  In your string_toUpper function, you set str_ret to point to the memory block for the "..................." string, then you change the characters that are stored in that memory by calling strcpy and StringUpperCase, then you return that memory pointer.  The string stored in that memory changes each time the function is called, but string_toUpper still always returns the same memory pointer.  If you look at the numeric value of str1 and str2 in the debugger, you'll see that they are the same.

In a previous post, when I suggested using a static local variable and returning that each time, I noted that "
calling code must be done using the return string before the function is called again".  This is exactly why I made that point.  In your example code, you call string_toUpper a second time, but you presumably still need to use str1.  This can be solved by requiring that callers of string_toUpper copy the returned value to other storage if they need to keep the value around.  For example:

char *str1, *str2, *temp;

temp = string_toUpper("louuu");
str1 = malloc(strlen(temp) + 1);
strcpy(str1, temp);
temp = string_toUpper("gfffddd");
str2 = malloc(strlen(temp) + 1);
strcpy(str2, temp);
// do something with str1 and str2  (str1 == "LOUUU", str2 == "GFFFDDD")
...
free(str1);
free(str2);

I realize you are trying to make your function as simple as possible for clients.  At least this way, your clients are responsible for both allocating and freeing their own memory, which makes it easier to avoid memory leaks.

Mert A.
National Instruments
Message 2 of 5
(3,451 Views)
1. You guested right, I do want to minimize trouble for the callers. Before I posted the question, I actually did the following and it work:
 
void main(void)
{
      char *str1, *str2;
      strcpy(str1, string_toUpper("louuu"));     //   str1 = "LOUUU"
      strcpy(str2,string_toUpper("gfffddd");     //    str1 = "LOUUU"  and str2 = "GFFFDDD"    
}
 
However, it does not solve my problem, the caller have to add a strcpy to use my function ... what happen if he/she does not know/remember it (they do not have time to verify all my functions all the time)? The function should take care itself so that the callers can avoid unknown error! Now, I have to inform everyone to use the return value rightway and not re-use it later (or do strcpy to another memory)!
 
2. But you did help me a lot by explaining why the problem happen in my question as weird as I thought ... it will help me in the future!
 
Many thanks  for detail explaination Smiley Happy
0 Kudos
Message 3 of 5
(3,438 Views)
I just want to make a couple notes/suggestions.  The code you posted is likely to cause problems or create a fatal runtime error.  You declare two pointers to memory, but do not initialize them to memory addresses that are known to be allocated and part of your program's address space.  Leaving them uninitialized means they point to random memory addresses, which could hold other parts of your program, or could be illegal to use.  When you strcpy into those addresses, you are asking for trouble.

I think it would be well worth your time to read up on strings and memory management in an introductory C book or tutorial.  Pointers and memory management are the biggest initial hurdle most people face when learning C, and it's definitely worth getting a good understanding of it, or else those kinds of problems will continue to plague your code.

I also think many of the difficulties you're having in getting the simple function interface that you want come from the nature of the C language.  Memory management is part of C programming.  If your clients are writing C code, then it is natural to expect them to take on the responsibilities of memory management (i.e. passing in pre-allocated arrays, freeing a returned array, or copying the returned string into their own memory).  Aside from very unusually complex approaches, like writing your own memory manager and/or garbage collector, there is no real way to shield your clients from this burden.  The CVI developers do their best to make CVI libraries as simple to use as possible, and you'll notice that this still means most library functions that handle memory require the client to pass in a pre-allocated buffer.  As long as your library functions are documented well and clearly state the caller's responsibilities, you should not feel bad about leaving some memory management work to your clients.

Good luck.

Mert A.
National Instruments

Message Edited by Mert A. on 02-09-2007 11:20 AM

0 Kudos
Message 4 of 5
(3,421 Views)
Thanks again, I will keep in-mind & followcall your suggestions!
0 Kudos
Message 5 of 5
(3,407 Views)