This question already has answers here:
Returning an array using C
(8 answers)
Closed 5 years ago.
Basically what I'm doing is making a base program that I can build other programs off of, and I have a function (called input) that returns the characters collected from a user input. Right now, there's a 2 errors saying "return makes integer without a cast", and "function returns address of local variable". What I want it to be able to do is return a character array.
Here is the code:
#import <stdio.h>
void cls() {
system(cls);
}
char input() {
char X[0];
int Y = 0;
char Z;
while (1 == 1) {
Y = Y + 1; //increment step
Z = getch(); //get character input
if (Z == ';') {
break;
} //break if stop character is pushed
char Q[Y];
int a;
for (a = 0; a < Y; a = a + 1) {
Q[a] = X[a];
} //pass the items of X to the larger Q array
Q[Y] = Z; //add new value to Q at end of array
char X[Y];
int b;
for (b = 0; b < Y + 1; b = b + 1) {
X[a] = Q[a];
} //pass the items of Q back to a larger X
printf(X);
}
return X;
}
int main() {
while (1 == 1) {
//stuff will go here later
}
return 0;
}
Arrays are not first-class types in C, so you can't return them from functions, nor pass them as arguments to a function. You need to pass/return pointers instead. But as the pointers must point to something (to be useful), you need to keep track of who "owns" what the pointers point at -- who is responsible for allocation and freeing the memeory involved.
So that said, there are several ways you can manage passing and returning (pointers to) arrays.
You can have the caller allocate an array (either on the stack or the heap), and pass a pointer (and size) to that array to a function that will fill it in. The called function in this case doesn't have to worry about allocating and freeing the array, but does need to worry about not overflowing it.
You can have the callee allocate an array on the heap and return a pointer to the caller. You can't do this with callee stack allocated memory, as the all callee stack allocated memory is freed when the callee returns, so if you try to return a pointer to it, the pointer will be dangling. A heap allocated array avoids that problem, but means that the caller will need to free it, and has the additional difficulty that the caller doesn't know how large the allocated array is, unless you return a struct containing that info along with th pointer, or somehow communicate that info back to the caller.
You should do following:
errors saying "return makes integer without a cast"
Change return type of function input from char to char *.
errors saying "function returns address of local variable"
The memory returned my variable X should be allocated dynamically i.e. using calloc or malloc function. Because in provided code the memory hold my variable X is local and present in stack. So when function call returns from
Related
This question already has answers here:
Return a pointer that points to a local variable [duplicate]
(3 answers)
Closed 2 years ago.
I have a function that returns char* when I print it with printf("%c", *(k+i)); on the main it prints;
0' 10101001 Q -> Q
but if I print with printf(" %c", *(k+i)); there are less problem.
If I print inside the tobinary function, output comes perfect like this;
1010.011010011011101001011110001101010011111101111100111 -> 111011
What Am I doing wrong? here is the code.
char *tobinary(double num) {
int length = 62;
char bin[length];
int intpart = (int)num;
double decpart = 1000*(num - intpart);
int i = 0;
while (intpart!=0) {
if(intpart%2 == 1) bin[3-i] = '1';
else bin[3-i] = '0';
intpart /= 2;
i++;
}
bin[i++] = '.';
while (i <= length) {
decpart *= 2;
if (decpart >= 1000) {
bin[i] = '1';
decpart -= 1000;
}
else bin[i] = '0';
i++;
}
char *k = bin;
return k;
}
int main(int argc, char **argv) {
char *k = tobinary(10.413);
for(int i = 0; i <= 62; ++i) {
printf("%c", *(k+i));
if (i==56) printf(" -> ");
}
}
When you declare a local variable in a function, like this
char *tobinary(double num) {
int length = 62;
char bin[length];
/* ... */
}
it is stored in a special memory area called stack. Whenever a function func() is called, the CPU saves there some useful data such as the address of the calling function where the execution will be restored after func() returns, along with the parameters of func() and, as I wrote above, any local variable declared in it.
All this data is stacked with a LIFO criteria (Last In, First Out), so that when function returns a special pointer (stack pointer) is changed to point back to the data regarding the calling function. func()'s data is still there, but it can be overwritten whenever another function is called or other local variables are declared by caller(). Please note that it is compliant with the fact that local variables have a lifetime limited to the function in which they are declared.
That's what happen in your scenario. Since the execution goes on, your bin[] array is not guaranted to stay "safe":
int i is declared in the for-loop section
printf() is called
This is what corrupts "your" data (I used double quotes because it is not yours anymore).
Whenever you need to return data manipulated by a function, you have three options:
Declare the array outside it and pass it to the function after changing its prototype: int tobinary(char *arr, unsigned int arrsize, double num);. In this way the function can modify the data passed by the caller (changing at most arrsize characters). The return value can become an error code; something like 0 on success and -1 on failure.
Dynamically allocate the array inside your function using malloc(). In this case freeing the memory (with free()) is responsability of the caller function.
Declare the array in your function as static. This qualifier, in fact, tells the compiler that the lifetime of the variable is the whole life of the program, and a different specific memory area is used to store it instead of the stack. Be aware that in this case your function won't be thread safe anymore (different thread accessing the same memory area would lead to bizarre results).
bin is character array inside your function.
It is not static, so when you return a pointer to it, it is not guaranteed to keep the same value.
Either change it to static or return a memory you allocate and the caller will need to free that memory.
This question already has answers here:
Returning string from C function
(8 answers)
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 3 years ago.
Recentely I've been taking the CS50 2020 course from Harvard University as an introduction to C programming. I'm not very experienced with the language or with coding as a whole, so I'm struggling a bit to figure out what is wrong with my code.
I wrote this little function which is suposed to take in a string and, by calling another function, encrypt the text using a Caesar cypher, then return it as a string. Problem is, I can't figure out how to return the character array as a string. I tried adding a NUL char at the end of the array after reading a bit about the problem, and it compiled alright, but when I ran the program I got the following error message:
error: address of stack memory associated with local variable 'result' returned [-Werror,-Wreturn-stack-address]
return result;
^~~~~~
My code:
string encypher(string text)
{
int length = strlen(text);
char result[length];
for(int i = 0; i < length; i++)
{
int letter_c = test_char(text[i]);
result[i] = (char)letter_c;
}
result[length + 1] = '\0';
return result;
}
The problem here is that result, being an array, decays to a pointer to its first element when used in an expression, and that is what is being returned from the function. And because the lifetime of the array ends when the function returns, that pointer now points to an invalid memory location, and attempting to use it invokes undefined behavior.
Instead of creating a local array, use the malloc function to dynamically allocate memory. That memory is valid for the life of the program, or until the returned pointer is passed to free:
string result = malloc(length + 1);
Also, note that you need to set aside one extra byte for the null byte that is used to terminate a string.
In the line
return result;
the array decays to a pointer to the first element of the array, so it is effectively the following:
return &result[0];
This array is allocated on the stack in the function encypher, so it will no longer exist when the function returns. Therefore, the returned pointer is a dangling pointer, which means that it is pointing to memory which is no longer allocated and may be overwritten by something else. For this reason, such a pointer should not be used.
In order to allocate memory that will still exist after the function returns, you can either:
Use dynamic memory allocation, such as malloc.
Allocate the memory on the stack of the function calling encypher (instead of in the function encypher itself) and change the parameters of the function encypher to accept a pointer to that array.
In my opinion, the second solution is the cleaner solution, as it allows the caller to decide where and how the memory is allocated. Using that solution, your code would look like this:
void encypher( char *cyphertext, const char *plaintext )
{
int length = strlen(plaintext);
//removed: char result[length];
for(int i = 0; i < length; i++)
{
int letter_c = test_char(plaintext[i]);
cyphertext[i] = (char)letter_c;
}
cyphertext[length + 1] = '\0';
}
The function could now be called like this:
int main( void )
{
char plaintext[23] = "This is the plaintext.";
char cyphertext[23]; //make sure the buffer is large enough to store the cyphertext including the terminating null character
encypher( cyphertext, plaintext );
return 0;
}
I'm currently studying variable length array and automatic storage.
I have the following code that allocate memory for an variable length array myArray inside function vla, and return a pointer to the variable length array from the function.
#include <stdio.h>
int * vla(int n){
int myArray[n];
myArray[0] = 10;
myArray[1] = 11;
int * pointerToInt = myArray;
return pointerToInt;
}
int main(void){
int * pointerToInt = vla(10);
printf("%d, %d", pointerToInt[0], pointerToInt[1]); // prints 10, 11
return 0;
}
I thought that variable length array belong to the automatic storage class (i.e. the memory for the variable length array will be allocated when we enter the function containing the variable length array, and the memory is automatically deallocated after the function exit)
So according to this logic, the memory allocated to myArray variable length array is deallocated after we return from vla method, but how come I can still correctly access the first and second element of the variable length array?
Is this behavior defined? or it is undefined behaviour that just happen to work?
myArray is a stack/auto variable created on the stack memory. Remember memory always exists. It is just owned by different pointers based on allocation and deallocation. The reason why you can still access same values is that the same piece of memory has not been assigned to another pointer and not been overwritten.
To evaluate it. Create another function that allocates same amount from stack but puts different values. Or add arguments in the same function and call it twice with different values. You will then see the difference.
#include <stdio.h>
int * vla(int n, int a, int b){
int myArray[n];
myArray[0] = a;
myArray[1] = b;
int * pointerToInt = myArray;
return pointerToInt;
}
int main(void){
int * pointerToInt = vla(10, 10, 11);
vla(10, 20, 21); // over write stack
printf("%d, %d", pointerToInt[0], pointerToInt[1]); // prints 20, 21
return 0;
}
By the way returning stack memory from vla is not a good idea. Dynamic memory is allocated from heap using malloc family of functions.
You can still correctly access the first and second element of the variable length array because you are assigning base address of the myArray to pointerToInt. Auto variables have a life inside the block only, but in this program we are using pointer to access the data in the memory, as long as that part of stack is not allocated to any other program, we can access that part of stack. If that part of stack is allocated to some other process we will get segmentation fault as we are trying to access unauthorized memory
I'm in the process of teaching myself C and I'm mistified as to what's causing the following issue: when I create an array in a method and return it as a pointer to the calling function, none of the content is correct. I've boiled down this problem to the following example:
char * makeArr(void){
char stuff[4];
stuff[0]='a';
stuff[1]='b';
stuff[2]='c';
stuff[3]='d';
printf("location of stuff:%p\n",stuff);
int i;
for(i = 0; i < 4; i++){
printf("%c\n",stuff[i]);
}
return stuff;
}
int main(void){
char* myarr;
myarr = makeArr();
int i;
printf("\n");
printf("location of myarr:%p\n", myarr);
for(i = 0; i < 4; i++){
printf("%c\n",myarr[i]);
}
}
The output returns the following:
location of stuff:0028FF08
a
b
c
d
location of myarr:0028FF08
Ä
ÿ
(
(a null character)
So I've verified that the locations between the two values are the same, however the values differ. I imagine that I'm missing some critical C caveat; I could speculate it's something to do with an array decaying into a pointer or a problem with the variable's scope, but and any light that could be shed on this would be much appreciated.
What you're attempting to do is return the address of a local variable, one that goes out of scope when the function exits, no different to:
char *fn(void) {
char xyzzy = '7';
return &xyzzy;
}
That's because, other than certain limited situations, an array will decay into a pointer to the first element of that array.
While you can technically return that pointer (it's not invalid in and of itself), what you can't do is dereference it afterwards with something like:
char *plugh = fn();
putchar (*plugh);
To do so is undefined behaviour, as per C11 6.5.3.2 Address and indirection operators /4 (my bold):
If an invalid value has been assigned to the pointer, the behaviour of the unary * operator is undefined.
Among the invalid values for dereferencing a pointer by the unary * operator are a null pointer, an address inappropriately aligned for the type of object pointed to, and the address of an object after the end of its lifetime.
Having stated the problem, there are (at least) two ways to fix it.
First, you can create the array outside of the function (expanding its scope), and pass its address into the function to be populated.
void makeArr (char *stuff) {
stuff[0]='a';
stuff[1]='b';
stuff[2]='c';
stuff[3]='d';
}
int main(void) {
char myarr[4];
makeArr (myarr);
// Use myarr here
}
Second, you can dynamically allocate the array inside the function and pass it back. Items created on the heap do not go out of scope when a function exits, but you should both ensure that the allocation succeeded before trying to use it, and that you free the memory when you're finished with it.
char *makeArr (void) {
char *stuff = malloc (4);
if (stuff != NULL) {
stuff[0]='a';
stuff[1]='b';
stuff[2]='c';
stuff[3]='d';
}
return stuff;
}
int main(void) {
char *myarr;
myarr = makeArr();
if (myarr != NULL) {
// Use myarr here
free (myarr);
}
}
stuff[] only exists on the stack during function call, it gets written over after return. If you want it to hold values declare it static and it will do what you want.
However, the whole idea is fundamentally lame, don't do that in real life. If you want a function to initialize arrays, declare an array outside of the function, pass a pointer to this array as a parameter to the function and then initialize an array via that pointer. You may also want to pass the size of the array as a second parameter.
Since you're learning, a sample code is omitted intentionally.
Your array stuff is defined locally to the function makeArr. You should not expect it to survive past the life of that function.
char * makeArr(void){
char stuff[4];
Instead, try this:
char * makeArr(void){
char *stuff=(char*)calloc(4, sizeof(char));
This dynamically creates an array which will survive until you free() it.
Lets say I have the following situation (some rough pseudocode):
struct {
int i;
} x
main(){
x** array = malloc(size of x pointer); // pointer to an array of pointers of type x
int* size = current size of x // (initally 0)
add(array, size);
}
add(x** array, int* size){ // adds one actual element to the array
x** temp = realloc(array, (*size)+1); // increase the array size by one
free(array);
array = temp;
// My question is targeted here
array[*size] = malloc(size of x); // makes a pointer to the value
array[*size]->i = size;
*size++;
}
My question is: Once add() is finished, do the values of the pointers stored in array disappear along with the function call stack, since I allocated them inside func()? I fear that they might, in which case would there be a better way for me to do things?
No, they don't. They persist until the pointer returned by malloc() is passed to the corresponding free() function. There would be no point in the existence of the malloc() function if it worked the same way as automatic arrays.
Edit: sidenote. As #Ancurio pointer it out, you're incorrectly freeing the memory behind the previous pointer returned by malloc() which is at that time invalid as realloc() has been used on it. Don't do that. realloc() does its job properly.)