Passing Struct members in Functions - c

I want to pass struct members in function . I don't mean something like that:
struct smth
{
int n;
};
void funct(struct smth s);
I want these structs
struct student {
char name[50];
int semester;
};
struct prof {
char name[50];
char course[50];
};
struct student_or_prof {
int flag;
int size;
int head;
union {
struct student student;
struct prof prof;
}
}exp1;
struct student_or_prof *stack;
struct student_or_prof exp2;
To pass their members in a fucntion with variables not struct variables
int pop(int head,int n)
{
if(head==n)
return 1;
else head++;
}
Because i don't want to use the function for structs only. Is it possible?
EDIT I want the numbers also to change , not return , something like pointer.
EDIT_2 Also i know that this pop(exp1.head,n) it works, but i want also the exp1.head to change after the end of the function pop.

Use pointers. pass poniter to exp1.head and manipulate it by dereferencing it in function as,
int pop(int * head,int n)
{
if(*head==n)
return 1;
else (*head)++;
}
call function as,
pop(&exp1.head,n);

First things first, you are missing a semicolon, after the union definition inside the struct student_or_prof.
As per your edit #2, you should be passing the address of the variable, taking it as a pointer to a variable by the function, and then editing/incrementing the content of the address (the variable that pointer points to). Like the following:
#include <stdio.h>
struct student_or_prof {
int head;
} exp1;
int pop( int * head, int n ) {
if ( *head == n )
return 1;
else (*head)++;
}
int main( ){
int returnval;
exp1.head = 5;
returnval = pop( &exp1.head, 10 );
printf( "%d", exp1.head );
getchar( );
return 0;
}
This will print a 6. Here, I am passing the address of the exp1.head, so that the function pop can refer to the actual exp1.head you have in your hands. Otherwise, the pop will be only informed about the value that exp1.head had, copy that value into its own head variable, play around with that.
And also, it would be sensible to return some int from the pop in any case. Right now it returns a value only when *head == n is satisfied, and returns something that wouldn't make sense. I don't think you'd want that, so:
...
else {
(*head)++;
return 0;
}
...
Would be better.
If you don't like the parenthesis around the *head, then you may want to use ... += 1; instead of a postfix increment, which has less precedence over the dereferencing operator *.

Related

Is there a way to point to a struct member from a function pointer?

I'm doing a double linked list from scratch in C and was programming the iter(able) function.
However my struct has a bunch of fields and I don't necessarily want to mess with all when I call the function. I want to choose what member to alter in the function call.
typedef struct s_command
{
int argc;
char *argv[MAXARGS];
t_token *args;
char **envp;
t_builtin builtin;
void *input;
void *output;
struct s_command *next;
struct s_command *prev;
} t_command;
My obvious choice was having an int argument that gets caught by an if else (can't use switch) to pick what field I want.
As such:
void dll_iter(t_command *lst, int property, void (*f)(void *))
{
if (!lst || !property || !f)
return ;
while (lst)
{
if(property == 1)
f(lst->argc);
else if(property == 2)
f(lst->argv);
else if(property == 3)
f(lst->args);
...
lst = lst->next;
}
}
But I can't stop but wonder if C has any way to simplify this. Make it cleaner.
What I would really like was someting like:
void dll_iter(t_command *lst, void (*f)(void *))
where f would call directly the member it wants.
Is there any way to achieve this?
I don't know how this will go over with a school, because this relies on border-line language-lawyering. But if you want a generic iterating function, just abstract away the only thing that matters to it, the links.
struct link {
struct link *next;
struct link *prev;
};
struct command {
struct link link;
// other members...
};
And now you can write
dll_iter(struct link*, void (*f)(struct link*));
Because a pointer to structure shares an address with it's first member, f can convert internally to the concrete node type it cares about. Meanwhile, the iteration function only deals with (and knows of) the members it needs to implement iteration.
Just note the calling the function is a little different now
void access_fn(struct link* link_p) {
struct command *cmd = (struct command*)link_p;
// do stuff
}
// ...
dll_iter(&cmd->link, access_fn);
Heck, now the function can even access more than one member at a time. How's that for flexibility?
It can be done. Time for stacking function pointers. We're getting really close to higher order functions now.
void dll_iter(t_command *lst, void *(*decoder)(t_command *entry), void (*f)(void *argpointer))
{
if (!lst || !decoder || !f)
return ;
while (lst)
{
f(decoder(lst));
lst = lst->next;
}
}
void *decoder_argc(t_command *entry) { return &entry->argc; }
void *decoder_argv(t_command *entry) { return &entry->argv; }
//...
Note that f always receives a pointer to the struct member.
Invocation looks like:
dll_iter(list, decoder_argc, f); // Process argc for all entries in list
dll_iter(list, decoder_argv, f); // ditto for argv

Comparison of structure pointer address not working

If condition inside the findset is not giving correct comparison. It is always shows not equal.
Where did I make a mistake?
#include<stdio.h>
struct node {
struct node *p;
int rank;
};
void makeset(struct node x) {
x.p = &x;
x.rank = 0;
}
void findset(struct node x) {
if (x.p == &x) {
printf("It worked bro\n");
}
}
int main() {
int nv, ne;
nv = 4;
ne = 5;
for (int i = 0; i < nv; ++i) {
struct node i;
makeset(i);
findset(i);
}
}
void findset(struct node x)
{
if (x.p == &x)
{
that x is a copy of the one passed in... x is always brand new and &x wont match any previous address.
Note that this is true not just of structs but all values...
int i = 3;
void f( int j)
{
// &j != &i
// j == i
// j and I have the same value, but different address
}
int main()
{
f(i);
}
There is no way your code will ever work. You ignore the fact that C uses pass by value -- meaning that when you pass a stuct node as a parameter to your function, (e.g. void makeset(struct node x)) the function receives a copy of the struct with its very own (and very different) address than the original struct in main().
So when you pass your struct to void findset(struct node x), there is no way if (x.p == &x) will ever test true -- because there is no requirement that the address of the copy of x received by void findset(struct node x) and stored in p is the same address as the copy of x that got passed to void makeset(struct node x).
Your second problem is your declare the same struct i 4 times in:
for (int i = 0; i < nv; ++i)
{
struct node i;
makeset(i);
findset(i);
}
You already have a variable i declared in your for loop. When you make the declaration struct node i;, you are not creating struct node 0;, struct node 1; ..., you are simply creating struct node i; 4 times. (no variable can be named a number or begin with a number in C) The i in your struct node declaration shadows the loop counter declaration of i. Add the warning -Wshadow to your compile string as a standard part of your compiler warnings.
What you need to do is declare an array of struct node if your want to be able to fill your nodes separately. For the purpose of this example, you could declare a struct with the same name 4-times - but that is rather limited to the use within your for loop (as your struct is declared within the for loop block, it is destroyed (the stack memory released for reused) each and every iteration of the loop. To prevent that from occurring, you can declare an array of 4 struct node before you enter your loop, e.g.
#include <stdio.h>
#define NNODES 4 /* if you need a constant, define one */
...
int main (void) {
struct node nodes[NNODES] = {{ .p = NULL }};
Next, to have any chance of findset ever being able to compare the original address of the struct node you pass as a parameter, you must pass the address of the struct, instead of the struct itself. That way, even though the function receives a pointer to a struct node, the value contained is the original address of the struct from the calling function (main() here)
So you need to change both function declarations to:
void makeset (struct node *x)
and
void findset (struct node *x)
You will also need to use the -> operator to access the members instead of the '.' operator.
Putting all the pieces together, you could do something similar to the following:
#include <stdio.h>
#define NNODES 4 /* if you need a constant, define one */
struct node {
struct node *p;
int rank;
};
void makeset (struct node *x)
{
x->p = x;
x->rank = 0;
}
void findset (struct node *x)
{
if (x->p == x)
printf ("It worked bro\n");
}
int main (void) {
struct node nodes[NNODES] = {{ .p = NULL }};
for (int i = 0; i < NNODES; i++) {
makeset (&nodes[i]);
findset (&nodes[i]);
}
}
(note: how the address of each struct node is passed to each function in main(), e.g. makeset (&nodes[i]);)
Example Use/Output
$ ./bin/struct_ptr_addr
It worked bro
It worked bro
It worked bro
It worked bro
It works now bro...
If you did really intend to declare a single stuct node in your for loop that is created and destroyed each iteration, then it works the same for a single struct as well -- you still have to pass the address of the struct to each function, e.g.
#include <stdio.h>
#define NNODES 4 /* if you need a constant, define one */
struct node {
struct node *p;
int rank;
};
void makeset (struct node *x)
{
x->p = x;
x->rank = 0;
}
void findset (struct node *x)
{
if (x->p == x)
printf ("It worked bro\n");
}
int main (void) {
for (int i = 0; i < NNODES; i++) {
struct node somenode = { .p = NULL };
makeset (&somenode);
findset (&somenode);
}
}
(the output is the same)
Hopefully, you now understand that when you pass a variable as a parameter, the called function receives a copy of the variable holding the original value. And, if you want to pass the address of the variable, then you have to pass the address as a pointer to insure that that original address is available within the called function (and any changes made visible back in the caller).
As the other poster said, you're passing in the value instead of the actual variable. The solution here is one of the reasons pointers are so powerful, you can just pass the pointer for the actual variable you want to change. For example:
void foo(){
int i = 8;
bar(&i);
}
int bar(int* i){
return *i * 2;
}
That should work better for you

Accessing structure in C - functions

I am trying to play around with structures in C and I am stuck at this point. Here's my code:
#include <stdio.h>
void Test(void);
void updateIt(struct Item* ptr);
struct Item
{
double value;
int unitno;
int isTa;
int quant;
int minQuant;
char name[21];
};
int main(void)
{
Test(); // here I am gonna call updateit() function and print
}
void Test(void) {
struct Item I = { 100.10,100,10,110,10,"NAME!" };
updateIt(&I);
}
void updateIt(struct Item* ptr){
struct Item I[0] = 200 // This doesn't work — but why?
}
How do I update values of Item I = { 100.10,100,10,110,10,"NAME!" } to { 200.20,200,20,220,20,"NAME2!"} by accessing values inside the updateIt function?
In the code snippet:
void updateIt(struct Item* ptr){
struct Item I[0] = 200 // This doesn't work — but why?
}
There is no variable I in this scope.
Since you passed the address of the structure through updateIt(&I); in the above function you will have to use the pointer to it.
The pointer variable ptr in the arguments of the function has the address of the structure, which can be used to update the values as :
ptr->structureMember
where structureMember is any member of the structure.
updateIt(struct Item* ptr) accepts pointer ptr of type item; to access fields of structure Item using a pointer, one should use -> operator like below:
void updateIt(struct Item* ptr){
ptr->value = 200.20;
ptr->unitno = 200;
ptr->isTa = 20;
ptr->quant = 220;
ptr->minQuant = 20;
strcpy(ptr->name, "NAME2");
}
You must use the ptr value like
ptr->unitno = 200 and so for every member of the struct

Creating a binary tree but it doesn't work — tree is always null

I am creating a code to insert the elements in tree, but tinsert function does not insert; what is wrong with my code? I have checked many times but tree is always NULL.
The code has only 2 functions: one to insert, and second to show it in preorder.
#include<stdio.h>
#include<stdlib.h>
struct btree {
int val;
struct btree *left;
struct btree *right;
};
static int c=0;
typedef struct btree node;
void tinsert( node *n,int a)
{
c++;
printf("%d\n",c);
if(n==NULL)
{
n=(node *)malloc(sizeof(node));
n->left=NULL;
n->right=NULL;
n->val=a;
//printf("adding root %d\n",n->val);
//n=temp;
}
else if(a>=(n->val))
tinsert(n->right,a);
else
tinsert(n->left,a);
return ;
}
void preorder_display(node *n)
{
if(n!=NULL)
{
printf("%d\n",n->val);
preorder_display(n->left);
preorder_display(n->right);
}
else
printf("tree is null\n");
}
int main()
{
//int N;
//int num[100];
//int i;
node *ntree=NULL;
tinsert(ntree,4);
tinsert(ntree,6);
tinsert(ntree,8);
tinsert(ntree,1);
printf("tree is \n");
preorder_display(ntree);
return 0;
}
tinsert works on a local copy of your ntree, it doesn't change the one in your main. You can fix it by passing a pointer to it (i.e.: double pointer, pointer to a pointer).
So your tinsert will look like this:
void tinsert( node **n,int a)
And in your main you'll call it like this:
tinsert(&ntree,4);
Of course, you'll need to adjust the code in tinsert to de-reference the pointer and access it correctly.
Or allocate the root node in your main.
you pass your root node ntree to tinsert function by value, so when when the function is done you will stay with original value of ntree which is NULL.
You better rewrite your function, so you will pass pointer to pointer
void tinsert( node **n,int a)
//and invocation is like that :
tinsert(&ntree,4);
when you pass ntree from main to tinsert function,
new copy is created to your node*n;
One way is to make use of pointer to pointer
Or second solution is here:
Here is a solution:
#include<stdio.h>
#include<stdlib.h>
struct btree{
int val;
struct btree *left;
struct btree *right;
};
static int c=0;
typedef struct btree node;
node* tinsert( node *n,int a)
{
c++;
printf("%d\n",c);
if(n==NULL)
{
n=(node *)malloc(sizeof(node));
n->left=NULL;
n->right=NULL;
n->val=a;
//printf("adding root %d\n",n->val);
//n=temp;
}
else if(a>=(n->val))
tinsert(n->right,a);
else
tinsert(n->left,a);
return n;
}
void preorder_display(node *n)
{
if(n!=NULL)
{
printf("%d\n",n->val);
preorder_display(n->left);
preorder_display(n->right);
}
else
printf("tree is null\n");
}
int main()
{
//int N;
//int num[100];
//int i;
node *ntree=NULL;
ntree=tinsert(ntree,4);
ntree=tinsert(ntree,6);
ntree=tinsert(ntree,8);
ntree=tinsert(ntree,1);
printf("tree is \n");
preorder_display(ntree);
return 0;
}
C supports the pass by value only. However, this does not prevent you from modifying the value of a variable from another function, because you can always refer to a variable using it's memory; and in C it's done through pointers, an abstraction representing a memory location.
When you pass a value to the function, the value of the actual parameter is copied to the value of formal parameter. Note that a pointer's value is the address it points to. So, this value is copied into the formal parameter. So the new pointer inside the function points to the exact same location your original variable. You can deference the pointer anytime to manipulate it's value.
Here, you are required to manipulate a pointer. So you pass a pointer-to-pointer to the function:
tinsert(&ntree,4);
In your function, you deference it to get your original pointer; like the following:
void tinsert(node **n, int a)
{
//...
*n = malloc(sizeof(node));
//...
}

How to return a struct without using global declaration of struct in C

Hello i am trying to return a struct from a function but i cant find a way to do so without declaring the struct as global. How can this be done? Here is the code (THIS WORKS AS IT IS)
...
void log_in();
struct node
{
char name_log[20];
int passlog;
int user_point;
}tmp;
int main()
{
...
else if(sel=='2')
{
log_in();
if (tmp.passlog==TRUE)
logged_in(tmp.name_log,tmp.user_point); //and here i want to use the retun values
}
void log_in()
{
... //make the changes in the struct
}
...
What i want to achieve is to place the struct node declaration within main but sadly it wont work. So here is what i am trying to do: (THIS DOESN'T WORK)
...
struct node log_in();
int main() {
...
else if(sel=='2') {
struct node //here is where i want to declare
{
char name_log[20];
int passlog;
int user_point;
}tmp;
log_in();
if (tmp.passlog==TRUE)
logged_in(tmp.name_log,tmp.user_point); //and here i want to use the retun values
}
struct node log_in()
{
...
return tmp;
}
...
else if(sel=='2') //or within this block but I don't know how.
{ struct node tmp;
tmp=log_in();
if (tmp.passlog==TRUE)
logged_in(tmp.name_log,tmp.user_point); //and here I want to use the return values
}
and inside the function log_in()
struct node log_in()
{
struct tmp
...
return tmp;
}
use a local variable inside the function and return this variable. Assign it to another variable inside main().
Declare the structure first, then create the variable temp. Like this:
struct node
{
char name_log[20];
int passlog;
int user_point;
};
Then you can create the local variable like
struct node tmp;
Pass a pointer to the struct node to your log_in function and have it return a boolean value so the caller can check whether logging in succeeded or didn't. (Note I'm trying to guess what you want to achieve, and I might be guessing wrong.)
#include <stdio.h>
#include <string.h>
struct node {
char name_log[20];
int passlog;
int user_point;
};
int log_in(char, struct node *);
int log_in(char sel, struct node * tmp) {
int ret = 0;
if (sel == '2') {
ret = 1;
strcpy( tmp->name_log, "Gonzo" );
tmp->passlog = 33;
tmp->user_point = 99;
}
return ret;
}
int main(int argc, char ** argv) {
struct node tmp;
char sel = argv[1][0];
if ( log_in(sel, &tmp) ) {
// tmp initialized
printf( "%s, %d, %d\n", tmp.name_log, tmp.passlog, tmp.user_point );
}
else {
// tmp not initialized
}
}
Call passing 2 on the command line. (If you don't, undefined behaviour.)
If you want to use some struct in 2 different routines - you must declare it outside of both of them since they both have to see how this struct is structured.
BTW - you invoke log_in but do not use its return value.
You can't operate on a type that is unknown. If log_in() doesn't know the definition of struct node, it can't use it directly. The only thing it can do is somehow receive a pointer to a variable of this type and then either treat it as raw data (sequence of bytes) or cast said pointer to a pointer to a known to log_in() type and work with that.
You can also redefine struct node inside of log_in(), which is a way of making log_in() operate on a known type:
void log_in(void*);
void logged_in(char*, int);
int main(void)
{
int sel = '2';
if (sel == '2')
{
struct node
{
char name_log[20];
int passlog;
int user_point;
} tmp;
log_in(&tmp);
if (tmp.passlog)
logged_in(tmp.name_log, tmp.user_point);
}
return 0;
}
void log_in(void* n)
{
struct node
{
char name_log[20];
int passlog;
int user_point;
} *p = n;
p->passlog = 1;
}
void logged_in(char* name, int point)
{
}
If you don't want to pass tmp by a formal reference into log_in(), you must make it available globally. For example like this:
void log_in(void);
void logged_in(char*, int);
void* pTmp;
int main(void)
{
int sel = '2';
if (sel == '2')
{
struct node
{
char name_log[20];
int passlog;
int user_point;
} tmp;
pTmp = &tmp;
log_in();
if (tmp.passlog)
logged_in(tmp.name_log, tmp.user_point);
}
return 0;
}
void log_in(void)
{
struct node
{
char name_log[20];
int passlog;
int user_point;
} *p = pTmp;
p->passlog = 1;
}
void logged_in(char* name, int point)
{
}

Resources