I saw a function that takes a list and a function pointer, and applies this
function to each element of the list.
ft_list.h
#ifndef LIST_H
#define LIST_H
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
typedef struct s_list
{
struct s_list *next;
void *data;
} t_list;
#endif
ft_list_foreach.c
void ft_list_foreach(t_list *begin_list, void (*f) (void *))
{
t_list *curr;
curr = begin_list;
while (curr)
{
(*f)(curr->data);
curr = curr->next;
}
}
But why declare t_list *curr ? And not just increment begin_list until the end of the linked list(NULL) ?
Although in this case declaring a new variable which holds the pointer to the list makes no difference, I would say that this is a good practice to never mutate the function parameters, only when the function's nature requires to do so (i.e. when you have an inout parameter, like a buffer). This unwritten rule will save you from a lot of problems in future when dealing with more complex functions.
Consider just a simple case where you would need for some reason to also destroy and free the contents of this list after applying the f function. Of course, in this simple example you would easily spot the issue, but there are cases when this wouldn't be that obvious.
So, again, even though here it makes no difference, I strongly recommend to always write your functions using this pattern and this will avoid a lot of weird and unexpected issues.
A function can be designed to return a value, although there is technically no explicit need to so, when passing a pointer to an object
as argument to modify it in the function.
The reason for this is when you have a critical operation inside of the function, and there is an error with this operation, you can return a specific value to the caller to symbolize that an error occurred inside of the function.
I guess the author later (half) optimized the code of the function here as his/her first intent maybe was to add such a security mechanism or even prepare the code to maybe later add this if the function becomes more critical features.
It is a technique that you return the passed pointer, when the operations in the function were successful and f.e. NULL at an error.
Also a common technique is to reassign the passed pointer with the returned pointer value, although this is risky since you lose the reference in the caller completely if an error occurred in the called function.
Since you increment the pointer in the function, it would be not very good to return the incremented pointer as one might want to reassign the passed pointer with the return value, like:
int *p = //anything ;
p = foo(p);
You need to either store the passed pointer value inside of another separate pointer variable, increment this "copy" pointer and return the passed parameter variable
OR
store the value of the passed pointer into another local pointer variable, increment the parameter pointer and return the "copy" pointer.
Therefore it can make sense to use curr instead of begin_list to increment and use begin_list as return value at success.
Otherwise NULL if an error occurred.
Note that you need to change the return type from void to t_list * then.
Also:
Difference between modifying a function parameter and modifying a local variable
A parameter is a local variable.
Related
Edit:
(1) Title (- previous title: How can I assign the address of a pointer to an already-existing variable? -- resolve at bottom of message);
(2) 'In short';
(3) spelling / punctuation.
In short: I am trying create and then locate a struct on the heap (I want to save memory on the stack), and passing arguments into various functions to populate the struct. In previous projects I created a pointer to struct, allocated this on the heap using malloc, and finally passing the pointer as argument to functions - this worked perfectly. My question: can the same be done without the use of a pointer?
I am trying to store a struct in dynamic memory. I succeeded in a previous mini-project, but I used pointer-to-struct, and passed this pointer to all my functions. Now I am burning to know if I could simply omit passing the pointer and pass the variable struct itself into the function.
My current example
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
typedef struct s_text t_text;
typedef struct s_text
{
int letters;
// some more stuff
} t_text;
int main(void)
{
t_text text;
t_text *tp;
tp = malloc(sizeof(t_text));
//&text = tp; <-- this here I tried, but error (value required as left operand of assignment)
return (0);
}
In the above code I allocate memory on the heap for the tp. This is the memory I'd like to use.
Now, on the stack, memory was reserved for (t_text) text. I would like to discard this and only use the heap.
t_text &text = malloc(sizeof(t_text)); <-- this may work in C++, i don't know, but in C definitely not.
In another post's discussion on NULL pointers, someone claimed in C++ that the address of a variable could point to NULL with the following code
int &x = *(int*)0;
but this definitely is not appreciated by my compiler. In fact, I tried several things with the address of a variable, but each time I try to set eg &text = (some address) this error pops up:
error: lvalue required as left operand of assignment.
(link to the post I refered to: ttps://stackoverflow.com/questions/57483/what-are-the-differences-between-a-pointer-variable-and-a-reference-variable/57492#57492 )
Below what I tried earlier (and works perfectly):
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
typedef struct s_text t_text;
void fn_prompt_user(t_text *tp);
void fn_calc_letters(t_text *tp);
typedef struct s_text
{
int letters;
// some more stuff
} t_text;
int main(void)
{
t_text *tp;
tp = malloc(sizeof(t_text));
fn_prompt_user(tp);
fn_calc_letters(tp);
return (0);
}
To conclude this post with my question: Is there a way I can pass a struct variable
as an argument to a function, or should I just accept passing pointer-to-struct is the one and only way to go?
Thanks!
-- answer to previous title's question (How can I assign the address of a pointer to an already-existing variable?): Not possible.
Error: error: lvalue required as left operand of assignment.
When declaring a variable, it is placed in memory. This memory location can not be changed, and so if int a = 3; a is an lvalue (location value) which can be changed (to eg. 4), but &a is unchangeable, therefor an rvalue (so is 3). So &a = ptr_a; will never work. Thanks for the clarification.
You can pass a struct to a function, like ....
int myfunc(t_text mytext) {....}
then ...
t_text thistext;
...
myfunc(thistext);
and this puts the entire struct onto the stack for the subroutine to use.
but the C language has no 'ref' feature like C++.
You can ...
tp = (t_text *)malloc(sizeof(t_text));
myfunc(*tp);
==
Your second example, passing pointers to objects, is a very conventional means of using structs in C. It has the advantage of not needlessly copying structs to the stack, merely pointers. It has the disadvantage of allowing functions to modify the objects that are pointed to. The latter problem can be remedied by declaring that the argument points to a const struct. Like:
void fn_promt_user(const t_text *tp) {...}
should I just accept passing pointer-to-struct is the one and only way to go?
Basically, yes.
C does not have "pass by reference" built into the language. If you want to have a function populate or otherwise modify a struct for you (or any other object for that matter), passing a pointer is the normal and idiomatic way of doing that. There is no real alternative, short of ugly macro hacks and stuff like that.
I'm trying to create an instance of a struct with a const member.
Because the member is const, I'm creating a temporary value that has it initialized explicitly.
#include <string.h>
#include <stdlib.h>
typedef struct Thing {
const char *value;
} Thing;
void createThing(const char *value) {
// Create a temporary instance of Thing to initialize the const value
Thing temporary = {
.value = value
};
// Create a new thing
Thing *thing = (Thing *)malloc(sizeof(Thing));
if(thing == NULL)
return NULL;
// Copy the contents of temporary into the result
memcpy(thing, &temporary, sizeof(Thing));
// Return the result
return thing;
}
Is it safe to use value this way, or should I create a new copy? For example:
const char *valueCopy = (char *)malloc(sizeof(char) * (strlen(value) + 1));
strcpy(valueCopy, value);
My reasoning is that the argument value will fall out of scope after the function call ends, and without copying, the value in the struct will become invalid.
As a side-note, I think I'm doing the right thing by copying from a temporary struct, but glad to be told otherwise.
Leaving aside the side issue of constness, the question exhibits an essential misunderstanding. Here:
Is it safe to use value this way, or should I create a new copy? For
example:
const char *valueCopy = (char *)malloc(sizeof(char) * (strlen(value) + 1));
strcpy(valueCopy, value);
My reasoning is that the argument value will fall out of scope after
the function call ends, and without copying, the value in the struct
will become invalid.
Although it is true that function parameter value goes out of scope when execution leaves the function, that's irrelevant. The first proposed alternative initializes a structure member from the value of value. The structure member is a separate object from the function parameter. The assignment makes that object refer to the same data that value does. It does not make the member an alias for value itself. The structure member has its own lifetime, separate from and (in this case) unrelated to the lifetime of the value parameter. In that sense, then, yes, it is safe to use value as you do in the first code snippet.
HOWEVER, there are other reasons why you might want to make a copy of the pointed-to data, as well as reasons why you might want to avoid doing that. It's unclear from the question which is appropriate in your particular case. But all this is independent of the constness of the member.
I want to make a function in which I change an already existing struct. So the return value of that function should be a struct. If I want an int as return value I call the function "int example()" ... How do I call the function if I want to return a struct? Since "struct" is already taken — I already take "struct whatever" to create one.
If you want the function to modify an existing struct, you should pass the struct in by pointer:
void modify_thing(struct whatever *thing);
If you want to return a modified copy of the struct, you can return the struct by value:
struct whatever edit_thing(const struct whatever *input);
Note that it is usually more efficient to pass struct variables by pointer, rather than by value.
passing a struct by value will cause the compiler to establish 1 or more reserved areas in memory that can only be used for that function.
Each of those memory areas are manipulated by the compiler inserting calls to memcpy().
Much better to pass a pointer to the struct, then return a simple indication of success/failure of the struct update operation.
Something's wrong with the following function:
typedef struct Data1{
float result;
struct Data1* next;
} Data;
Data* f(Data* info){
Data item;
item.result=info->result;
item.next=info->next;
return &item;
}
I notice two things here:
The returned value is a pointer of local value. However it's still a pointer- the compiler gives a warning: function returns address of local variable. but would it really be a problem? ( I don't return a local value itself)
I believe that the main problem here is that this function suppose to copy the Data struct. it would be OK for the results value, but regarding the 'next' pointers, I believe that at the end of the call to the function the pointers would not be changed, Am I correct? It's like equalize two ints in a outside function, should *(item.next)=*(info->next); solve the problem?
So what's the main problem here? is it both 1 and 2?
The returned value is a pointer of local value. However it's still a pointer- the compiler gives a warning: function returns address of local variable. but would it really be a problem? ( I don't return a local value itself)
That is the main problem. After the function returns, the local variable doesn't exist anymore. The space it occupied may be overwritten immediately or later, but you can't count on ever reading meaningful data from that address.
If you want to copy things, you have to return a pointer to malloced memory.
Data* f(Data* info){
Data *item = malloc(sizeof *item);
item->result=info->result;
item->next=info->next;
return item;
}
But that has the drawback that now the caller has to free the memory allocated by f, so
Data* f(Data* info, Data* item){
item->result=info->result;
item->next=info->next;
return item;
}
with a pointer allocated by the caller.
The problem with returning pointers to local variables is that the space the local variables occupies will be reclaimed when the function returns, so the pointer no longer points to valid memory, or even memory used by other functions called later.
Yes, it would be a problem, since the returned pointer is useless: it's pointing at an object which no longer exists. Hence the warning.
Not sure I follow your reasoning here ... You are not changing anything in the Data passed in, so that's a problem if you expected it to.
1) Yes, it's a problem, because your pointer now points to what used to be on your stack, but is no longer managed memory, which means another function call (or an interrupt) will, with almost 100% certainty, begin mangling that memory.
2) I have no idea what you're asking here.
The main problem is that you're unclear on how memory works in C programs, which leads to constructs like this; not a ding, just an honest observation: http://www.geeksforgeeks.org/archives/14268 gives a relatively good overview and should serve you well.
I have something like the folowing C code:
struct MyStruct MyFunction (something here)
{
struct MyStruct data;
//Some code here
return data;
}
would the returning value be a reference or a copy of the memory block for data?
Should MyFunction return struct MyStruct* (with the corresponding memory allocation) instead of struct MyStruct?
There is no such thing as a reference in C. So semantically speaking, you are returning a copy of the struct. However, the compiler may optimise this.
You cannot return the address of a local variable, as it goes out of scope when the function returns. You could return the address of something that you've just malloc-ed, but you'll need to make it clear that someone will need to free that pointer at some point.
It would return a copy. C is a pass-by-value language. Unless you specify that you are passing pointers around, structures get copied for assignments, return statements, and when used as function parameters.
It is returned as copy. BTW, you should not return it's reference because it has automatic storage duration ( i.e., data resides on stack ).
I have had problems with this (a function in a DLL returning a struct) and have investigated it. Returning a struct from a DLL to be used by people who might have a different compiler is not good practice, because of the following.
How this works depends on the implementation. Some implementations return small records in registers, but most get an invisible extra argument that points to a result struct in the local frame of the caller. On return, the pointer is used to copy data to the struct in the local frame of the caller. How this pointer is passed depends on the implementation again: as last argument, as first argument or as register.
As others said, returning references is not a good idea, as the struct you return might be in your local frame. I prefer functions that do not return such structs at all, but take a pointer to one and fill it up from inside the function.