#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
char * upperCase(const char* s)
{
char * ret = NULL;
size_t length = strlen(s) + 1;
ret = (char*)malloc(sizeof(char) * length);
for (size_t i = 0; i < length; i++) {
ret[i] = toupper(s[i]);
}
return ret;
}
int main()
{
char* ret = NULL;
char* input = "HelloWorld";
ret = upperCase(input);
printf("value = %s", ret);
free(ret);
}
The above code takes a string as a parameter and copies the string. It then converts each element of the copied string to uppercase and returns it.
Compiler = GCC 6.2
If you use the malloc function, is it possible to return a local variable to terminate the function and release the memory? I do not have enough understanding of the scope that still has memory.
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:
ret = (char*)malloc(sizeof(char) * length);
should be ret = malloc(sizeof(char) * length);
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 suchYes, you can.
The malloc
memory is on the heap, so it won't release when upperCase
end.
But variable char *ret
is on the stack, it will be popped out when upperCase
end. But the value of ret
in upperCase()
is copied via ret = upperCase(input)
in main()
. That is to say, you still obtain the address of the allocated memory, which is still on the heap. You can call free(ret)
when finished the use of this memory.
Check What and where are the stack and heap? for details about stack & heap.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With