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.
Related
I have a C structure like this:
struct my_struct {
int i;
double d;
struct expensive_type * t;
};
An instance of this structure is created and initialized as:
struct my_struct * my_new( int i , double d)
{
struct my_struct * s = malloc( sizeof * s);
s->i = i;
s->d = d;
s->t = NULL;
return s;
}
Calculating the struct expensive_type * t member is quite expensive, and might not be needed - it is therefor just initialized to NULL - and later calculated on demand:
const struct expensive_type * my_get_expensive( const struct my_struct * s)
{
if (!s->t)
s->t = my_expensive_alloc( s->i , s->d );
return s->t;
}
In C++ I would have used mutable on the struct expensive_type *member, is it possible to achieve something similar in C, i.e. casting away the const locally:
{
struct my_struct * mutable_s = (struct my_struct*) s;
mutable_s->t = ...;
}
Or is removing const in the signature my only standard-compliant alternative?
You could(1) restructure your code and add a layer of indirection:
struct expensive; // Forward declaration, ignore
// One could also use a struct expensive * (a pointer) instead
// of this structure. IMO giving it a name is the better option.
struct expensive_handle {
struct expensive * target;
};
// Store the simple data members as usual, store a pointer to a
// handle (pointer) to the expensive ones
struct my_struct {
int simple;
struct expensive_handle * handle;
};
struct expensive {
int content; // whatever
};
Creating a my_struct must create the additional pointer/handle used for the indirection:
struct my_struct * new() {
struct my_struct * data = malloc(sizeof(*data));
// Error handling please
// Set simple data members
data->handle = malloc(sizeof(*(data->handle)));
// Error handling please
data->handle->target = NULL;
return data;
}
The target member (which will point to the expensive data once it is computed) is set to NULL initially.
Accessing (and thus possibly lazy computation of) the expensive data members is then possible even with a const qualified my_struct, because no data member of that my_struct is changed:
int get_expensive(struct my_struct const * ptr) {
if (ptr->handle->target == NULL) {
ptr->handle->target = malloc(sizeof(struct expensive));
// Error handling please
puts("A hell of a computation just happened!");
ptr->handle->target->content = 42; // WOO
}
return ptr->handle->target->content;
}
The only thing that changes is the data member of *(ptr->handle), a struct expensive_handle. Which is not const qualified (only the pointer to it named handle is).
Test (Live on ideone):
int main(void) {
struct my_struct * p = new();
printf("%d\n", get_expensive(p));
printf("%d\n", get_expensive(p));
}
(1) Whether this is reasonable or a complete waste of resources (both programmer and computation) cannot be decided from your dummy example, though.
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
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.
struct result {
int number;
int length;
};
struct result findLongestSeq(int intarray[], int size) {
result->number // undefined symbol
}
how to access the struct result inside the function findLongestSeq?
thanks
struct result {
int number;
int length;
};
struct result findLongestSeq(int intarray[], int size) {
struct result result;
result.number = 0;
result.length = 42;
return result;
}
If you are dealing with struct result foo then you access its members via foo.number.
If however you are dealing with a pointer to foo (struct result *foo) then you access its members via foo->number.
If you were to manually allocate your result struct via
struct result *result = (struct result *)malloc(sizeof (struct result));
Then you'd have to access its members via result->number (and would be responsible for freeing it once not used anymore).
Further more I'd rather use this for the sake of better readability:
typedef struct {
int number;
int length;
} ResultStruct;
This way you can then use ResultStruct result; instead of redundant and verbose struct result result;.
You have to keep in mind that by simply typing
struct result {
int number;
int length;
};
you only define how a struct with name result actually looks like, i.e. of what parts it is made up. This is a general definition, but you have variable of that type yet.
To access values of this struct you have to create a variable by
struct result myResult;
or however you want to call it. At this point you are able to access the members of this struct with myResult.number
I'm having issues writing a function that allocates a struct in C. Ideally, I want to have the function fill the fields of the struct with parameters passed into it.
I have defined the struct in my header file like so:
typedef struct {
char name[NAME_SIZE]; //Employee name
int birthyear; //Employee birthyear
int startyear; //Employee start year
} Employee;
And this is what I have for my function currently:
void make_employee(char _name, int birth_year, int start_year) {
Employee _name = {_name,birth_year,start_year}; //allocates struct with name
} /* end make_employee function */
Any advice on how to accomplish this?
The problem with your current code is that the struct your creating is created on the stack and will be cleaned up as soon as the function returns.
struct foo
{
int a;
int b;
};
struct foo* create_foo( int a, int b )
{
struct foo* newFoo = (struct foo*)malloc( sizeof( struct foo ) );
if( newFoo )
{
newFoo->a = a;
newFoo->b = b;
}
return newFoo;
}
This will get you a heap allocated object. Of course, you'll need a function to free that memory or this is a memory leak.
void destroy_foo( struct foo* obj )
{
if( obj )
free( obj );
}
void print_foo( struct foo* obj )
{
if( obj )
{
printf("foo->a = %d\n",obj->a);
printf("foo->b = %d\n",obj->b);
}
}
(btw, this style gets you part of the way toward an "object oriented" C. Add some function pointers to the struct (to get polymorphic behavior) and you have something interesting; though I'd argue for C++ at that point.)
You have to return a pointer allocated via malloc:
Employee* new_employee(char *_name, int birth_year, int start_year) {
struct Employee* ret = (struct Employee*)malloc(sizeof(struct Employee));
ret->name = _name;
ret->birth_year = birth_year;
ret->start_year = start_year;
return ret;
}
two more things: (1) you should make the struct definition of name a char* instead of char[NAME_SIZE]. Allocating a char array makes the struct much bigger and less flexible. All you really need is a char* anyway. And (2) change the function definition to char*.
Why does the make Employee return void? You need to return the Employee from the make_employee function!
Are you having trouble with the compiler complaining about the x = {a,...} syntax? Write it the long way then: Emp e; e.field1 = a; ...
Are you having weird overwriting / bogus numbers problems? If you allocate a struct in the function it will become invalid (and prone to being overwriten) as soon as the function returns! To go around this you either have to:
Return a copy of the struct (this is OK for small structs):
Employee make_emp(int a){
Emp emp; //Allocate temporary struct
emp.filed1 = a; //Initialize fields;
return emp; // Return a copy
}
Allocate the struct in the heap instead and deal with it through references (ie.: pointers) instead:
Employee* make_emp(int a){
Emp* emp = malloc(sizeof(Emp)); //Allocate the struct on the heap
//And get a reference to it
emp->filed1 = a; //Initialize it
return emp; //Return the reference
}
Don't forget to free() the Employee after you are done with it in this case!
Employee * make_employee(char *_name, int birth_year, int start_year)
{
Employee *employee;
if (employee = (struct Employee *)memalloc(sizeof(Employee)) == NULL)
{
return NULL;
}
else
{
strcpy(&(employee->name), _name);
employee->birthyear = birth_year;
employee->startyear = start_year;
return employee;
}
}