Short answer: Yes, it is possible
Long answer: malloc(some_size)
allocates some_size
space and returns a pointer to the address of the start of the allocated chunk (or NULL
upon failure). When doing ret = (char*)malloc(sizeof(char) * length);
ret is assigned with said pointer that points to memory chunk of length
char
s (note that sizeof(char) == 1
so you can remove it).
The memory is yours until you free it, even after the function had returned, so, after the end of upperCase(...)
execution, that memory still belongs to you. The only problem is, the pointer ret
was allocated on the stack with (auto)
local storage, meaning it will "die" when it's scope (in your case - the upperCase(...)
function's scope), and thus, you will not know where that memory is, BUT since you return ret
from the function, the value it holds (which is the address to your allocated memory) will pass on to main
's ret
, which basically means you're good to go.
One last thing I think I should emphasize is, returning local variables is done all the time. For example int increment_by_one(int x){int y = x + 1; return y;}
. This is a very simple function that returns the value of local int y
. Since the value returned is all we need (i.e. the value of x+1
) it's ok that it (the value) was stored in a local variable. The same (sort of) goes for your case - since ret
inside upperCase
holds the address that was allocated ,it's ok for it to "die" after upperCase
ends, since the value it holds (the address) is passed on.
char * upperCase(const char* s)
{
char * ret = NULL; // local variable -> will die after upperCase ends
size_t length = strlen(s) + 1; // local variable -> will die after upperCase ends
ret = (char*)malloc(sizeof(char) * length); // ret assigned with address to memory
for (size_t i = 0; i < length; i++) { // local variable -> will die after it's scope (the for loop) ends
ret[i] = toupper(s[i]);
}
return ret; // said address is returned to main (local variable ret now dies peacefully after fulfilling its duty)
}
int main()
{
char* ret = NULL; // local variable -> will die after main ends
char* input = "HelloWorld"; // local variable -> will die after main ends
ret = upperCase(input); // ret gets the address allocated in upperCase
printf("value = %s", ret);
free(ret); // address is freed
}
2 notes:
- There is no need casting malloc return value, meaning
ret = (char*)malloc(sizeof(char) * length);
should be ret = malloc(sizeof(char) * length);
- no need for
sizeof(char)
since it's 1
, meaning you can shorten it further to ret = malloc(length);
malloc
can fail. In that case it will return NULL
so after every ret = malloc(...);
you should check the value like if(!ret){// handle error}
or if(ret != NULL){// do something}
and such