I have a function which takes a structure as a parameter, like:
add_new_structure(structure s);
then store it inside
structure structure_list[200];
question:
1. when I want to use the structure, I have a function like
structure *getStructure(int id)
{
return &structure_list[id];
}
is it gonna work if I add one structure like this:
void init()
{
structure test;
memset(&test,0,sizeof(structure));
add_new_structure(test);
}
and then call getStructure from another function? like this:
void anotherFunction()
{
structure *got_test = getStructure(0);
}
because I remember I can't have local variable and then call it from another function right?
2.is it better to just store it like this?
change the add_new_structure() parameter to structure *s;
then store it inside
structure *structure_list[200]; by calling add_new_structure(&test);
3. which one is better? or what is the right way to do it?
The first approach, i.e. you pass the instance directly as a parameter, works. Because the whole instance is copied when calling the function. And what you store is a copy of the original struct instance.
However, you can't pass and store a pointer to a local variable. The problem you mentioned above will occur in this case.
IMHO, neither of the above approaches are right. The first approach will introduce too much overhead when passing parameters to the function. While the second one cannot achieve what you want.
You'd better dynamically allocate memory with malloc/calloc and store the pointer in the array. Don't forget to release the object at the end of use in case of memory leak. Like this:
void init()
{
structure *test = NULL;
test = (structure *) calloc(1, sizeof(structure));
add_new_structure(test);
}
void add_new_structure(structure *s);
Option 2, as I think you point out, will not work. It's a bit more subtle than saying that pointers to local variables can't be used outside of a function; it's that they are only valid while the function is still "active", so to speak. In option 2, a pointer to structure test would be stored inside of structure *structure_list[200] when you call add_new_structure. At this point, some function is calling init which is calling add_new_structure. When you return from init, the memory address you put into structure_list is no longer owned by the original owner, and this is dangerous. If this is too mechanical of an explanation, you should look at how stacks work to see why.
Without using malloc and its friends, which can introduce a lot of complexity, I would be inclined to keep the memory stored in structure_list, with the minor modification that you can pass structure test by reference and not by value. This is probably a reasonable compromise between the two stylistically.
void init() {
structure test;
memset(&test,0,sizeof(structure));
add_new_structure(&test);
}
void add_new_structure(structure *s) {
if (structure_count < 200) {
structure_list[structure_count++] = *s;
}
}
A lot of this depends on what structure is (if it contains pointers itself, who owns those?), but hopefully this provides some intuition.
Related
Generally it is preferred to pass pointer to structure to a function in C, in order to avoid copying during function call. This has an unwanted side effect that the called function can modify the elements of the structure inadvertently. What is a good programming practice to avoid such errors without compromising on the efficiency of the function call ?
Pass a pointer-to-const is the obvious answer
void foo(const struct some_struct *p)
That will prevent you from modifying the immediate members of the struct inadvertently. That's what const is for.
In fact, your question sounds like a copy-paste from some quiz card, with const being the expected answer.
In general, when it comes to simple optimizations like what you've described, it is often preferable to use a pointer-to-struct rather than passing a struct itself, as passing a whole struct means more overhead from extra data being copied onto the call stack.
The example below is a fairly common approach:
#include <errno.h>
typedef struct myStruct {
int i;
char c;
} myStruct_t;
int myFunc(myStruct_t* pStruct) {
if (!pStruct) {
return EINVAL;
}
// Do some stuff
return 0;
}
If you want to avoid modifying the data passed to the function, just make sure that the data is immutable by modifying the function prototype.
int myFunc(const myStruct_t* pStruct)
You will also benefit from reading up on "const correctness".
A very common idiom, particularly in unix/posix style system code is to have the caller allocate a struct, and pass a pointer to that struct through the function call.
This is a little different than what I think your asking about where you are passing data into a function with a struct (where as others have mention you may the function to treat the struct as const). In these cases, the struct is empty (or only partially full) before the function call. The caller will do something like allocate an empty struct and then passes a pointer to this struct. Probably different than your general question, but relevant to the discussion I think.
This accomplishes a couple handy things. It avoids copying a possibly large structure, also it lets the caller fill in some fields and the callee to fill out other (giving an effective shared space for communication).
The most important aspect to this idiom is that the caller has full control over the allocation of the struct. It can have it on the stack, heap, reuse the same one repeatedly, but where it comes from the caller is responsible for the handling the memory.
This is one of the problems with passing around struct pointers; you can easily lose track of who allocated the struct and whose responsibility it is to free it. This idiom gives you the advantage of not having to copy the struct around, while making it clear who has the job of free'ing the memory is.
I'm wondering if it is always better to use pointers. I have a structure with only one byte (or some integers ).
This structure contains i.e. parameters to a routine and will be passed there.
If I don't use pointers (inside of the struct), but pass this struct by pointer, would the change (for logPrio) made in main_loop be visible outside (i.e in main)?
Please see this sample to get me:
typedef struct mainloop_param_t
{
unsigned char *logPriop;
//or versin w/o pointer
unsigned char logPrio;
}mainloop_param_t;
int main()
{
mainloop_param_t mlparams;
unsigned char logPrio;
mlparams.logPriop = &logPrio;
// or nothing cause mlparams.logPrio already initialized
// would mlparams.logPrio be a copy or original?
g_timeout_add (5000, (GSourceFunc)main_loop, &mlparams);
}
If I don't use pointers (inside of the struct), but pass this struct by pointer, would the change (for logPrio) made in main_loop be visible outside (i.e in main)?
Yes, after you have passed the address of mlparams, every change made in main_loop can be visible in main, regardless of whether a pointer or an variable inside mlparams.
I guess your probloem is when a pointer should be used. In my opinion, pointer is just a tool to access data, it should not be a problem of itself. The important things are "which place the data should be?" and "how does programs access the data?"
The followings are parts of usages:
data is here(locally) and will be accessed here --> just define and use an local variable
data in somewhere(another scope, e.g. outside) and will be accessed here --> define a pointer that point to the data and access tha data via operator *
data is here and will be accessed in somewhere(another scope, e.g. inside) --> define an variable and pass the address of the variable somewhere
data in somewhere and will be accessed in otherwhere --> define a pointer that point to the data and pass the pointer otherwhere
sometimes you need some data that may be in a large amout, insdead of copying all of them to stack(might cause overflow), it's better to copy an address of the beginning of the data. The copy of the address is just a pointer.
I'm wondering if it is always better to use pointers.
Use pointers when it is needed. Unnecessarily use of it may cause some confusion later to you and others readers.
If I don't use pointers, would the change (for logPrio) made in main_loop be visible outside (i.e in main)?
In case of global variable and structs YES, Otherwise NO.
unsigned char logPrio;
mlparams.logPriop = &logPrio;
In this code, it doesn't make any sense to use a pointer. The change happens in main and will be visible to g_timeout_add since you pass this struct to that function.
I think you are confusing things with how parameters are passed by pointer to a function. If you have a function like
void func (int x)
{
x = 2;
}
then the original variable passed to the function is not altered, because x inside the function is a copy of the variable from the caller.
int var = 1;
func(var);
printf("%d", var); // will print 1
If you want to alter the variable's value, you would have to write the function like:
void func (int* x)
{
*x = 2;
}
int var = 1;
func(&var);
printf("%d", var); // will print 2
Why would you do this:
void f(Struct** struct)
{
...
}
If I wish to operate on a list of structs, is it not enough to pass in a Struct*? This way I can do struct++ to address the next struct or am I very confused here? :)
Wouldn't it only be useful if I want to rearrange the list of structs in some way? However if I'm just reading I don't see the point.
It depends on what your data structure looks like. Assuming that p is a null-terminated array of pointers to struct s, you can run through it using a loop like this:
void f(struct s **p)
{
while (*p != NULL) {
/* some stuff */
(*p)++;
}
}
Generally, use a pointer to a pointer is useful only if you attempt to modify the pointer itself.
If you want to modify the pointer in caller which was passed to this function, you'd typically do this.
Because, everything is passed by value in C, passing struct* will only pass the copy of the pointer and won't modify pointer in the caller. Why passing struct * is explained in this C-FAQ.
If you don't intend to modify the pointer in caller, it's not neccessary to pass struct **.
There are a number of uses for this kind of parameter...
One already mentioned, and quite common is to allow the caller to use the function to modify a pointer. The obvious case here would be when getting some blob of data...
void getData( void** pData, int* size )
{
*pData = getMyDataPointer();
*size = getMyDataSize();
}
Another option is that perhaps the extra level of indirection allows for the list to behave in some way? e.g. by using indices to refer to specific elements they can be allocated and reallocated without having the risk of dangling pointers.
Yet another option is that the list is very large and lives in fragmented memory, or is rapidly accessed so that the list is actually several smaller lists grouped together. This sort of technique can also be used to 'lazily' allocate huge arrays, e.g. providing an interface to an array of a billion elements, but then allocating chunks of 100k on demand as they are read/written with struct** pointing at the whole thing, and each struct* being either null or pointing to 100k structs...
To be honest the context is quite important... there are plenty of uses for also triple pointers as function parameters that follow similar reasoning. (e.g. combine the first thing i mention with the second, or the second with the third etc.)
You are correct, there is no reason to pass a pointer to pointer unless your function is intended to modify the pointer passed in. In case of accessing an array of structs, a single level of indirection is definitely sufficient.
The creator of the API probably thought that the argument list would be easier to memorize if the first argument of every function is the same.
void my_cool_function()
{
obj_scene_data scene;
obj_scene_data *scene_ptr = &scene;
parse_obj_scene(scene_ptr, "test.txt");
}
Why would I ever create a pointer to a local variable as above if I can just do
void my_cool_function()
{
obj_scene_data scene;
parse_obj_scene(&scene, "test.txt");
}
Just in case it's relevant:
int parse_obj_scene(obj_scene_data *data_out, char *filename);
In the specific code you linked, there isn't really a reason.
It could be functionally necessary if you have a function taking an obj_scene_data **. You can't do &&scene, so you'd have to create a local variable before passing the address on.
Yes absolutely you can do this for many reasons.
For example if you want to iterate over the members of a stack allocated array via a pointer.
Or in other cases if you want to point sometimes to one memory address and other times to another memory address. You can setup a pointer to point to one or the other via an if statement and then later use your common code all within the same scope.
Typically in these cases your pointer variable goes out of scope at the same time as your stack allocated memory goes out of scope. There is no harm if you use your pointer within the same scope.
In your exact example there is no good reason to do it.
If the function accepts a NULL pointer as input, and you want to decide whether to pass NULL based on some condition, then a pointer to a stack variable is useful to avoid having to call the same function in separate code paths, especially if the rest of the parameters are the same otherwise. For example, instead of this:
void my_function()
{
obj_data obj = {0};
if( some condition )
other_function(&scene, "test.txt");
else
other_function(NULL, "test.txt");
}
You could do this:
void my_function()
{
obj_data obj = {0};
obj_data *obj_ptr = (condition is true) ? &obj : NULL;
other_function(obj_ptr, "test.txt");
}
If parse_obj_scene() is a function there may be no good reason to create a separate pointer. But if for some unholy reason it is a macro it may be necessary to reassign the value to the pointer to iterate over the subject data.
Not in terms of semantics, and in fact there is a more general point that you can replace all local variables with function calls with no change in semantics, and given suitable compiler optimisations, equal efficiency. (see section 2.3 of "Lambda: The Ultimate Imperative".)
But the point of writing code to communicate with the next person to maintain it, and in an imperative language without tail call optimisation, it is usual to use local variables for things which are iterated over, for automatic structures, and to simplify expressions. So if it makes the code more readable, then use it.
I have the following problem with a program which I wrote in Visual C++ and I hope that anyone can help me please:
typedef struct spielfeld
{
int ** Matrix;
int height;
int width;
Walker walker;
Verlauf history;
} Spielfeld;
void show(Spielfeld fieldToShow); //Prototype of the Function where I have this
//problem
int main(int argc, char *argv[])
{
int eingabe;
Spielfeld field;
//Initialize .. and so on
//Call show-Function and pass the structure with Call by Value
show(field);
//But what's happened? field.Matrix has changed!!
//can anyone tell me why? I don't want it to become changed!
//cause that's the reason why I pass the field as Call by Value!
}
void show(Spielfeld fieldToShow)
{
//Here is the problem: Alltough the parameter fieldToShow has been passed
//with call by value, "fieldToShow.Matrix[0][0] = 1" changes the field in
//main!!
fieldToShow.Matrix[0][0] = 1;
//Another try: fieldToShow.walker.letter only affects the local fieldToShow,
//not that field in main! That's strange for me! Please help!
fieldToShow.walker.letter = 'v';
}
When you pass the structure in, you are passing it in by value. However, the matrix within it is implemented as a pointer to pointer to int. Those pointers are references, and so when you modify the value referenced by them in your function, the same value is referenced by the original structure in main.
If you want to pass these objects by value, you need to do a deep copy yourself, in which you allocate a new matrix, and copy all of the values from the original matrix into it.
As Drew points out, in C++, the preferred way to implement that deep copy is via a copy constructor. A copy constructor allows you to perform your deep copy any time your object is passed by value, without having to explicitly copy the object yourself.
If you are not ready for classes and constructors yet, you can simply write a function, perhaps Spielfeld copySpielfeld(Spielfeld original), that will perform that deep copy; it will essentially be the same as your initialization code that you elided in your example, except it will take values from the Spielfeld passed in, instead of creating a new Spielfeld. You may call this before passing your field into the show function, or have the show function do it for any argument passed in, depending on how you want your API to work.
You're copying the pointer when you pass fieldToShow. Pass-by-value does not perform a deep copy, so both the Spielfeld in an invocation of show(...) and main(...) (although distinct) have the same value for Matrix.
Fixing this is non-trivial. Probably the easiest thing to do would be to change show(...) to pass-by-reference (using a Spielfeld* basically) and make an explicit copy at the start of the function.
When your Spielfeld object is copied:
The copy has its own "walker", which is a copy of the original's "walker". Since walker is a struct, that means you have two structs.
The copy has its own "Matrix" member, which is a copy of the original's "Matrix" member. But Matrix is a pointer, which means you have two pointers. A copy of a pointer points to the same thing the original points to.
So, modifications to the contents of the copy's walker don't affect the original, because they have different walkers. Modifications to the contents of the copy's matrix do affect the original, because they share the same matrix.
The structure is begin passed by value, but since it contains a pointer (the matrix) what that pointer is pointing to can be changed by anyone that has access to the structure. If you don't want this to happen, you can make the pointer const.
As interesting trivia: this is how call by value works in java. Object references are always passed by value. If you manipulate the objects to which these references point tough it will feel like call by reference happened.
Has really nothing to do with your question but maybe you find that interestring.
Happy hacking