I have written the following code for my project. The code is scattered across various files and quite long so i am posting the minimal code.
#include<stdio.h>
#include<stdbool.h>
struct TwoPoint
{
int width;
int value;
};
struct Module
{
int categ;
void *ptr;
};
struct Rect
{
struct TwoPoint val;
struct TwoPoint val_new;
bool is_changed;
};
struct S
{
int numInstances;
struct Module instances[20];
struct Rect RectList[40];
int numRect;
}s1;
struct Test
{
int categ;
struct Rect state;
};
struct TwoPoint initPVal(int v,int w)
{
struct TwoPoint temp;
temp.value=v;
temp.width=w;
return temp;
}
int getValue(struct TwoPoint *b)
{
return (b->value);
}
struct TwoPoint get(struct Rect *r)
{
return (r->val);
}
void initialize()
{
s1.numInstances=0;
s1.numRect=0;
}
void addRect(struct Rect *r)
{
if(s1.numRect<40)
{
s1.RectList[s1.numRect].val=r->val;
s1.RectList[s1.numRect].val_new=r->val_new;
s1.RectList[s1.numRect].is_changed=r->is_changed;
s1.numRect++;
}
}
struct Rect initRect(struct TwoPoint initval)
{
struct Rect temp;
struct TwoPoint tempP;
tempP=initPVal(0,0);
temp.val=initval;
temp.val_new=tempP;
temp.is_changed=false;
addRect(&temp);
return temp;
}
void copy(struct Rect *r)
{
if(r->is_changed)
{
r->val= r->val_new;
r->is_changed=false;
}
}
void copyRect()
{
int i=0;
for(i=0;i<s1.numRect;i++)
{
copy(&s1.RectList[i]);
}
}
void setInstance(struct Module *m)
{
s1.instances[s1.numInstances].categ=m->categ;
s1.instances[s1.numInstances].ptr=m->ptr;
s1.numInstances++;
if (s1.numInstances >= 20)
{
printf("Too many instances");
}
}
void setModule(struct Test *t)
{
struct Module m;
m.categ=t->categ;
m.ptr=&t;
setInstance(&m);
}
void init(struct Test *t)
{
t->categ=2;
struct Rect tr;
struct TwoPoint tb1=initPVal(0,5);
tr=initRect(tb1);
t->state=tr;
}
void actions(struct Test *t)
{
struct TwoPoint tb=get(&t->state);
int y=getValue(&tb);
printf("%d\n",y);
unsigned int x=getValue(&tb);
printf("%u\n",x);
switch(y)
{
....
}
}
void initS()
{
init(s1.instances[0].ptr);
}
void act()
{
actions(s1.instances[0].ptr);
}
void setup()
{
struct Test t;
initialize();
init(&t);
setModule(&t);
}
void run()
{
initS();
act();
copyRect();
}
int main()
{
printf("foo\n");
setup();
printf("bar\n");
run();
return 0;
}
There are two errors:
The init() function when called through initS() function leads to Stack Overdumped error whereas it worked fine while i called it in setup(). I think Call is correct as action() function is being executed.
The second problem is in actions() function. When i am calculating the value of y to be used as switch condition instead of the value being 0,1,2 or 3 it is some memory address which i found by printing it while trying to debug.
The problem is:
void setup()
{
struct Test t;
initialize();
init(&t);
setModule(&t);
}
A Test structure is allocated as a local stack variable and then the address of it assigned to some variable which is accessed later. The next time this variable is accessed is in (init):
void init(struct Test *t)
{
t->categ=2;
struct Rect tr;
struct TwoPoint tb1=initPVal(0,5);
tr=initRect(tb1);
t->state = tr;
}
At this point the pointer points to a variable that has fallen out of scope, resulting in undefined behaviour. What actually happens is that the stack gets smashed because of the structure assignment which is attempted. This is why it's also difficult to get a backtrace.
One solution is to allocate the memory with malloc like so:
void setup()
{
struct Test * t = malloc(sizeof (struct Test));
initialize();
init(t);
setModule(t);
}
Another problem existed, namely a semantic bug in setModule:
void setModule(struct Test *t)
{
struct Module m;
m.categ=t->categ;
m.ptr=&t;
setInstance(&m);
}
m.ptr=&t should actually be m.ptr = t. The assignment of a pointer to a Test structure was intended. Instead, what happened was that the address of a stack variable holding a pointer to a Test structure (double pointer to a Test structure) was assigned.
I'm assuming that where you show run() calling actions(), it is actually calling act(), since the former function requires a parameter.
In setModule(), you have
m.ptr=&t;
where t is already a pointer to struct Test. So what you have stored in m.ptr is a pointer to a pointer to a struct. In act(), you pass this stored pointer to actions(), which is expecting a pointer to a struct, not a pointer to a pointer to a struct. So when the function dereferences the pointer and treats the result as a struct Test, it's getting who-knows-what.
Most likely, you want to simply change the line in setModule() to
m.ptr=t;
since t is already a pointer. But perhaps there is some reason you really want to have a pointer to a pointer, in which case you need to change the code that uses the pointer to use it properly. A problem here is that the compiler can't help you ensure type safety since you're storing the pointer as void * and implicitly converting it to other types.
As a side note, you seem to be using the & operator a lot more than I think is usual. It seems to me that your functions that are read-only, e.g. getValue(), should simply take a struct parameter, not a pointer to a struct, and then you would not need to obtain the addresses of variables so much. But perhaps this is a matter of taste.
Related
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
I'm working on a project that strictly requires to realize two set of functions in C with same signature that can be used from a sigle .c test file. one set is for a data structure, the other one for a different and incompatible data structure.
Since in C there is no polymorphism is not possible to call a function that has two implementation with same signature in two different headers (.h) files and taking for granted that the call will be referred to the right implementation of the function that is actually capable of managing the right data structure.
Ok I know it seems impossible and contradictory but..that is it...
I have to merge two generic items that can be list or dynamic array
Update:
on List.h (dynamicArray is in another .h)
typedef struct Node{
void *data;
struct Node *next, *prevNode;
} Node;
//typedef struct declaration List
typedef struct List {
struct Node *top, *bot, *prev;
int size;
} List;
//in the dynamicarray.h file:
typedef struct dynamicArray{
void **array;
size_t size;
size_t capacity;
}dynArray;
//in the dynamicarray.h file:
void* merge(void *element1,void *element2, int parameters){
void * returner;
if (parameters==ARRAY) {
returner= Array_Merge(element1,element2); // expected to receive two arrays
}
else {
returner= List_Merge(element1,element2); // expected to reveice two lists
}
return returner;
}
Do you have any suggestion to accomplish this request?
Thanks.
You need to pass both, a pointer to your function and some handler function to the test, along with argument(s). In 'c' void * can be use in place of any pointer. Something like the following might work for you:
int mytest(void*(*function)(void *), int(*handler)(void *), void *arg) {
if (handler(function(arg)))
return OK;
return FAIL;
}
So, you just need to have separate handler functions for arrays and lists and pass them to the test function along with other params.
Answering your last comment
I can imagine some scheme as the following.
List list1;
dyArray array1;
MergedList outList;
MergedArray outArray;
...
void *getNextArrayElement(dynArray *array){...}
void *getNextListElement(List *list){...}
int mergeAsList(void* el, void *list){
if (el == NULL)
return 0;
ListMember *mmb = malloc(sizeof(ListMember));
mmb->el = el;
mmb->next = ((MergeList*)list)->head;
(MergeList*)mergeList->head = mmb;
return 1;
}
int mergeAsArray(void *el, void *array) {
if (el == NULL)
return 0;
if (((MergeArray *)array)->index) >= MAX)
return 0;
((MergeArray *)array)[((MergeArray *)array)->index++] = el;
return 1;
}
int mergeAsSortedArray(void *el, void *array){...}
...
test(getNextArrayEelement, mergeAsList, &arraty1, &outList);
test(getNextListEelement, mergeAsList, &list1, &outArray);
...
int test (void *(get*)(void*),
int (merge*)(void *m1, void *result),
void *in,
void *out) {
void *el = get(in);
int res = merge(el, out);
return res;
}
Function pointers are the means in which you accomplish this.
Function pointers are what you would use if, for example, you wanted to pass a function to a sort function that told the sort function how to compare two adjacent members. Such a comparison function allows you to provide a generalized sort function that will work on a collection of any struct, since you can change out the comparison function to accommodate any struct.
Consider the following sort code:
typedef struct node{
void* item;
struct node* next;
} Node;
// Just an ordinary bubble sort
void sort(Node *start, bool greaterThan(void* a, void* b))
{
int swapped, i;
Node *ptr1;
Node *lptr = NULL;
/* Checking for empty list */
if (start == NULL)
return;
do
{
swapped = 0;
ptr1 = start;
while (ptr1->next != lptr)
{
if (greaterThan(ptr1->item, ptr1->next->item))
{
swap(ptr1, ptr1->next);
swapped = 1;
}
ptr1 = ptr1->next;
}
lptr = ptr1;
}
while (swapped);
}
// Swap function used above
void swap(Node *a, Node *b)
{
void* temp = a->item;
a->item = b->item;
b->item = temp;
}
To use it, we just need to define a payload to put into Node* item and a sort function to tell it how to order the items:
typedef struct {
int book_id;
char title[50];
char author[50];
char subject[100];
char ISBN[13];
} Book;
// Comparison function.
bool bookGreaterThan(void* left, void* right)
{
Book* a = (Book*)left;
Book* b = (Book*)right;
return strcmp(a->title, b->title) > 0;
}
Finally, you would sort your list like so:
// Pass a pointer to the first node in your list, and a function pointer to your comparer.
sort(pointerToMyList, bookGreaterThan);
A complete example can be found here.
See also Is it possible to achieve runtime polymorphism in C?
It has been a LONG time (25y) since I have done C and so I forget some things so please forgive the question.
Given that I have the following declarations:
typedef struct item {
int field;
} Item;
typedef struct data {
Item b;
} Data;
I have been trying to update the struct when its passed to a function and this doesn't work at all.
static void foo(Data *data) {
data->b.field = 3; // doesn't work, the struct remains unchanged.
}
static void test() {
Data v = {.b = {.field = 2}};
foo(&v);
}
However, if I alter the declaration slightly, use malloc to allocate it it works.
typedef struct data {
Item *b;
};
static void foo(struct data *data) {
data->b->field = 3; // works.
}
static void test() {
Data v = (struct data*) malloc(sizeof(Data));
Item i = (struct item*) malloc(sizeof(Item));
foo(v);
free(i);
free(v);
}
Can someone inform me why this is? Is it not possible to have struct members that are updatable as members? How could I make the first example work?
Thanks in advance.
Your first approach actually works (and I would have been surprised if it did not):
struct item {
int field;
};
struct data {
struct item b;
};
static void foo(struct data *data) {
data->b.field = 3;
}
static void test() {
struct data v = {.b = {.field = 2}};
printf("v.b.field before calling foo: %d\n", v.b.field);
foo(&v);
printf("v.b.field afterwards: %d\n", v.b.field);
}
int main() {
test();
}
Output:
v.b.field before calling foo: 2
v.b.field afterwards: 3
Probably your setting is a different one that than you've shown in the code. Mysterious things (i.e. undefined behaviour) often happens if you access an object after it's lifetime has ended. malloc often prevents such issues as it keeps an object alive until it is explicitly freed.
But in your case, there should not be any difference.
BTW: the typedef does not make sense, as you do not define an alias for the struct-type just declared. So
struct item {
int field;
};
is sufficient.
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
These are two errors I get, can someone explain to me why my thinking is wrong?
HW3.c: In function ‘newStack’:
HW3.c:23:3: error: invalid use of undefined type ‘struct stack’
myStack.list = malloc(sizeof(job) * 16);
HW3.c:24:3: error: invalid use of undefined type ‘struct stack’
&job1 = myStack.list;
The reason I did
&job1 = myStack.list;
is because I thought that's the same thing as myStack.list = &job1 and when I want to add more jobs, I can code something like
&job2 = myStack.list + sizeof(job);
As for the first error, I'm just at a loss.
typedef struct {
int phaseAndDuration[2][16];
int currentPhase;
int isCompleted;
} job;
typedef struct {
struct job* list;
int currentIndex;
int size;
} stack;
struct stack myStack;
struct job job1;
void newStack(void)
{
myStack.list = malloc(sizeof(job) * 16);
&job1 = myStack.list;
myStack.currentIndex = 0;
}
void pop(void)
{
}
void push(void)
{
if(myStack.size != 0)
{
}
}
int main(void)
{
return 0;
}
The reason for the error is that you typedef an anonymous struct and the try to declare it as if it were not anonymous or typedefed, you need to change the declarations to
stack myStack;
because the struct has no name, you only defined a type named stack which is what you can use to declare a variable, if it were
typedef struct stack
{
/* ... */
} stack;
you could use both, and without the typedef you would only be allowed to use struct stack.
Also, the expression
&job1 = myStack.list;
is invalid, because &job1 is not an l-value and you cannot assign to it. In fact if it were to compile it would mean something that is not really possible which is overwrite the address of a stack variable.
If you use typedef, as in:
typedef struct {
// (your fields here)
}stack;
then, after that you use your struct as just stack, like this:
stack myStack;
...because you have defined stack to be an equivalent of struct {.... does it make sense?
Alternatively, if you want to keep using struct, you can make your structured tagged instead of anonymous, like:
struct t_Stack {
// (your fields here)
};
struct t_Stack myStack;
You have two types stack and job defined via typedef, not struct stack nor struct job.
&job1 = myStack.list;
is bad because &job1 is just a pointer value, not an variable, and the compiler won't know where to store the data.
Not knowing what is meant by "add more jobs",
&job2 = myStack.list + sizeof(job);
Might be bad because the addition to pointer move the pointer to sizeof(job)th element after myStack.list.
Maybe you want to do
job2 = myStack.list + 1;
to have job2 point the next element after myStack.list.
Try this:
#include <stdlib.h> /* add this to use malloc() */
typedef struct {
int phaseAndDuration[2][16];
int currentPhase;
int isCompleted;
} job;
typedef struct {
job* list;
int currentIndex;
int size;
} stack;
stack myStack;
job *job1;
void newStack(void)
{
myStack.list = malloc(sizeof(job) * 16);
job1 = myStack.list;
myStack.currentIndex = 0;
}
void pop(void)
{
}
void push(void)
{
if(myStack.size != 0)
{
}
}
int main(void)
{
return 0;
}