I'm currently self-studying C for mastering an university project. In that project we have several signatures given that we need to implement for solving our task. After several hours of trying to make some progress, I must admit that I'm totally confused about the return types of functions. I will show you some code:
This is a structure given to represent numbers in the power to the basis 32.
#include <stdio.h>
#include <stdlib.h>
typedef unsigned int uint32;
typedef struct
{
int n;
uint32* words;
}
foo;
We need to implement some functions like the one with the following signature:
foo add(foo* a, foo* b);
As can you see, the function takes two pointers to the structure as parameters, and returns the value of a structure, and not the pointer to it. That means that I have to locally create an instance of foo and return it.
foo add(foo* a, foo* b)
{
foo result = {1, malloc(sizeof(uint32))};
// do something with result
return result;
}
1) Is there anything wrong in this attempt? In my production code I get problems with accessing the value of the returned structure: it seems to they have changed after the structure was returned. Unfortunately I was not able to reproduce that behaviour in a more simple application, which got me even more worried that I'm doing this all wrong. I have also tried to allocate memory with malloc for the variable result, but that only seems to work if I create a pointer to foo, which seems to be no option, because I can't return the pointer.
2) I'm looking for a way to cast (probably not the correct term) the return type back into a pointer. Let开发者_运维技巧s just say I have this code:
foo* bar1 = malloc(sizeof(foo));
bar1->n = 1;
bar1->words = malloc(bar1->n * sizeof(uint32));
bar1->words[0] = 4294967295;
foo* bar2 = malloc(sizeof(foo));
bar2->n = 1;
bar2->words = malloc(bar2->n * sizeof(uint32));
bar2->words[0] = 21;
foo bar3 = add(bar1, bar2);
Works fine. How could I now use the value of bar3 to call the add function again. Like this:
foo bar4 = add(bar1, bar3);
After also tried various attempts with creating foo* and trying to assign values, but they all failed and I decided to post this question to get some nice answer that helps me understanding C a little bit more.
1) To access the returned structure you only need to do something like:
printf("[bar3] n %d words %d\n", bar3.n, *(bar3.words));
2) To pass bar3
again to the function add
. You need to pass the mem address of bar3
which can be accessed by using the operator &
:
foo bar4 = add(bar1, &bar3);
or
foo bar3_p = &bar3;
foo bar4 = add(bar1, bar3_p);
If you do it like this you can keep the definition of the function without returning a pointer.
You're looking for the address-of operator, &. &foo3 will return a pointer to foo3.
Update I withdraw my previous explanation. I ran your code through valgrind and indeed you don't produce any leaks or incorrect memory accesses. The way you have it, the struct is returned by value, so it is copied into a new struct on return. The only thing you would have to do is free()
the words
pointer when you're done.
Your strange results might be the result of something you're doing that's not shown here.
You need to return a pointer to foo:
foo* add (foo* a, foo* n) {
foo result* = malloc(...);
/* do some addition */
return result;
}
Don't forget to free()
the foo
structs which are obtained this way.
To undesrtand the reason why your way doesn't work, consider the lifetime of variables declared within the add()
scope:
add()
is entered.- A new
foo
struct is created and assigned to the variableresult
. - The function
add()
returns and the memory for variables within that scope is freed. - Outside of
add()
, the caller receives a struct stored at a location in memory which is marked as unused. - Attempts to access that struct produce undefined results because the memory where it is located could be allocated for other data.
Consider the flow of the solution I presented:
add()
is entered.- New memory is allocated on the heap and the address of that memory is stored in
result
. - The function
add()
returns the value ofresult
(an integer indicating an address in memory). - Outside of
add()
, the location pointed at byresult
is still an allocated location on the heap, and the pointer returned may be safely dereferenced. - When you are done with the struct at that location, you call
free(result)
and that location is marked as unused.
Hope that helps! For further information, you should investigate what the memory heap is and how allocation works.
精彩评论