Saving state with a struct in a c file - c

I want to be able to access a struct variable from all functions in a .c file.
I assumed that the way is to declare the struct as static outside any function.
I have something like this:
static struct gameBoard current_game_board;
int foo() {
current_game_board = { .x = 1, .y = 2 }
}
This shouts "expected expression before '{' token". When I try the same with and int instead of a struct gameBoard it works.
Is it even possible with a struct? Is there a better way to save state across a file?

The Initializer list is for initializing objects. An Initialization is when you define a variable and explicitly assign it a value in the same go.
As you defined the variable outside the block already, you can't use an initializer list that way. Do this instead:
current_game_board.x = 1;
current_game_board.y = 2;
Also as #UnderDog pointed out, you are misunderstanding what static means. static for a variable at file scope denotes that it has internal linkage, i.e. it is restricted to the current translation unit and is not visible outside.
What you wanted is having the variable at file scope, which would work without the static qualifier too. You were right in choosing static though, as you should restrict access to everything that's not needed from outside. You just did it for the wrong reason.

If I understand you correctly, that you essentially want a global structure you can write to wherever, then define the structure and create a global pointer to it. Allocate the pointer anywhere, and you can use it wherever you like:
#include <stdio.h>
#include <stdlib.h>
typedef struct gameBoard {
int a;
int b;
} gameBoard;
gameBoard *current_gameboard; /* declare global pointer */
void prngameboard ()
{
printf ("\ncurrent_gameboard-> a: %d\ncurrent_gameboard-> b: %d\n\n",
current_gameboard-> a, current_gameboard-> b);
}
void setgameboard (int x, int y)
{
current_gameboard-> a = x;
current_gameboard-> b = y;
}
int main () {
/* allocate memory for pointer */
current_gameboard = malloc (sizeof *current_gameboard);
current_gameboard-> a = 1;
current_gameboard-> b = 2;
prngameboard ();
setgameboard (3, 4);
prngameboard ();
/* free memory allocated to pointer */
if (current_gameboard)
free (current_gameboard);
return 0;
}
output
$ ./bin/struct_global
current_gameboard-> a: 1
current_gameboard-> b: 2
current_gameboard-> a: 3
current_gameboard-> b: 4
Note: you should always check the return from malloc and test whether current_gameboard has been allocated before using it. Both have been omitted for brevity. let me know if you have questions.

You can possibly use:
static struct gameBoard current_game_board;
void foo(void) {
current_game_board = (struct gameBoard){ .x = 1, .y = 2 };
}
This assigns a 'compound literal' of the appropriate type to your global variable.
A once-only alternative is:
static struct gameBoard current_game_board = { .x = 1, .y = 2 };
These require C99 or better support, but the fact that you're trying suggests that you probably have that.

Related

The right way of implementing a constructor in C

I want to create a constructor using C.
What is the cleanest way to achieve this?
My attempt:
#include <stdio.h>
struct line {
void (*add_line_ptr)(struct line*, int x, int y);
int x;
int y;
};
void add_line(struct line* lptr, int x, int y)
{
lptr->x = x;
lptr->y = y;
}
int main()
{
struct line line1 = {add_line, 0, 0};
line1.add_line_ptr(&line1, 10, 20);
printf("%d %d\n", line1.x, line1.y);
}
I think that using line1.add_line(&line1, is a bit redundant - since it's quite obvious that I want to do the operation on line1.
Is there a way to implement this without passing a pointer to the "object"(struct)? or some other way I didn't think of?
Using function pointers just for the sake of emulating C++-like syntax is just messy with no obvious benefits. You won't have RAII in C no matter what you do, so you need to call constructors/destructors explicitly. If you do so by typing obj.foo() or obj = foo() has absolutely nothing to do with OO, it's mere coding style.
The main problem here though, is that your code does not have proper OO design, since the struct is completely open and not using private encapsulation. For the same reason as class line { public: int x; int y; }; is not proper OO either - you don't get OO just because you smash some related variables into an aggregate type, regardless of language.
"Cleanest"/"prettiest" would mean full private encapsulation. In C, that can be achieved with opaque types. I prefer to implement them without hiding pointers behind typedef, so:
line.h
#include <stdio.h>
#include <stdlib.h>
typedef struct line line; // forward declaration of incomplete type
line* line_construct (int x, int y);
line.c
#include "line.h"
struct line { // actual definition of the struct, local to line.c
int x; // private variable
int y; // private variable
};
line* line_construct (int x, int y)
{
line* obj = malloc (sizeof *obj);
if(obj == NULL) { /* error handling here */ }
obj->x = x;
obj->y = y;
return obj;
}
caller.c
#include "line.h"
int main(void)
{
line* x = line_construct(10, 20);
}
Here line is 100% encapsulated and the contents of the struct cannot be accessed by the caller. Since I don't hide pointers behind typedef, the caller must always use line* pointers and can never declare an instance of the object directly.
If the constructor is only meant to zero-out the struct members, then it doesn't need to get passed any parameters but can do so internally.
And obviously you need to implement a corresponding destructor with free as well.
line* line_destruct(line* obj) { free(obj); return NULL; } or so.
I wouldn't put the initializer into your structure to begin with. Other functions, sure, but not the first one. Something like this:
#include <stdio.h>
struct line {
int x;
int y;
};
void add_line(struct line *lptr, int x, int y)
{
lptr->x = x;
lptr->y = y;
}
int main()
{
struct line line1 = {0, 0};
add_line(&line1, 10, 20);
printf("%d %d\n", line1.x, line1.y);
}
The reason is that you have to assign the initializer anyway after you allocate your structure, either implicitly or explicitly. In OOP languages you normally name the class you want once, and both the allocator and initializer will run. In C you have to run them separately. Whether you allocate an object on the stack or on the heap, you will have to explicitly name the function you want to call at least once anyway.

Is there a way to make a variable survive 1 scope out of the current one?

I want to make a function that returns a pointer to a locally-defined variable. For the sake of argument, I'll call the function struct awesome *makeCoolStruct() (I don't want to declare the variable in the outer scope which should have the call struct awesome coolness = makeCoolStruct(); because the function will be called in more than one place).
I understand why the compiler errors out when I try doing that - the local variable will be 'destroyed' as soon as the program exits that scope, so the pointer will basically be invalid.
I looked up how to return a pointer to a local variable in a function, and while I get why malloc would work, that defeats the purpose of trying to do it this way, because malloc, as far as I understand, keeps the variable for as long as the program runs - or until free is called. However, that means that I'll have to have free called at the end of anything that calls my function. At that point, I'd be better off declaring the variable in every calling scope and then passing a pointer to it like makeCoolStruct(&existingVariable);.
If, however, there's a way to declare "keep this variable for 1 position higher in the stack" (which would obviously produce a compilation error in the global scope since there are no higher positions in the stack), then I could return a pointer and it'll exist just fine for as long as I need it to, wherever I decide to call struct awesome x = makeCoolStruct(); (I'm aware of the mutability issues - I'm not looking for mutability). I could truly return anything I want in a function from that point on, not just stuff that was passed in.
I haven't really tried anything because I don't know of anything that would work.
I expect to be able to return a pointer to a local variable after doing whatever keeps the variable for one scope higher, without having to do any preparations for the function call when I call it (creating a variable for it to use for the output instead of just assigning the output to something.
What you're asking isn't possible in C, but here are some alternatives:
Passing a stack variable in:
typedef struct {
int a;
int b;
} Foo;
void bar(Foo* foo)
{
foo->a = 5;
}
int main(void)
{
Foo foo = {0};
bar(&foo);
return 0;
}
Returning the struct directly:
Foo bar(void)
{
Foo foo = {1, 2};
return foo;
}
int main(void)
{
Foo foo = bar();
return 0;
}
Managing the memory manually:
Foo* bar(void)
{
Foo* foo = malloc(sizeof(*foo));
return foo;
}
int main(void)
{
Foo* foo = bar();
free(foo);
return 0;
}
Lastly, if you really hate whoever is going to inherit this project, you could always use a macro:
#define FOO(X) \
Foo X = {0}; \
bar(&X);
Although not recommended, it is actually safe to return a pointer to a static variable, assuming your program is not multithreaded.
struct myStruct {
int x;
char y;
};
struct myStruct *foo()
{
static struct myStruct bar = {.x = 0, .y = 'a'};
return &bar;
}
I would never write something like that, but it is safe in the sense that it does not invoke undefined behavior.
And just in case you did not know, it's perfectly cool to return a struct. You don't need malloc for that. This would be fine:
struct myStruct foo()
{
struct myStruct bar = {.x = 0, .y = 'a'};
return bar;
}

How can I properly assign a value to an array (of structure type) element?

#include <stdio.h>
struct virus
{
char signature[25];
int size;
}v[2];
int main(void) {
static v[0] = {"Yankee",1813};
static v[1] = {"Doodle",2813};
int i;
for(i=0;i<=1;i++)
{
printf("%s %d\n",v[i].signature,v[i].size);
}
return 0;
}
I am getting the compiler error in this C code.
Error: Declaration syntax in function main()
I am guessing that there is some error in v[2], as it is associated with extern class whereas, v[0] and v[1] are associated with static class.
But, I am not sure that is this the only reason or some other ?
Edit : I have edited the code by removing the wrong syntax.
There is no error in declaration of v[2], the problem is later.
You've written
static struct v[0] = {"Yankee",1813};
which attempts to define a 0-sized array, which is not allowed by default C standard.
That said, the syntax is also horribly wrong. You don't have a proper type there, remember, struct itself is not a type, it's a keyword. struct <something> is actually a type.
Then, from the logical point of view, you probably don't want a new variable altogether. In case you want to use the array elements from the v, just use the variable name, that's all. Something like
#include <stdio.h>
struct virus
{
char signature[25];
int size;
}v[2] = { {"Yankee",1813}, {"Doodle",2813}}; //get it initialized, job done
int main(void) {
int i;
for(i=0;i<=1;i++)
{
printf("%s %d\n",v[i].signature,v[i].size);
}
return 0;
}
will do the job in much better way, IMHO.
EDIT:
In case, you're interested in assigning individual elements (not initialization), well, you cannot use a brace-enclosed initializer for that purpose, it's not meant to be RHS operand for an assignment. You need to use a compound literal for that purpose, something like
v[0] = (struct virus){"Yankee",1813};
v[1] = (struct virus){"Doodle",2813};
will also do the job.
Don't mix up struct definitions with variable declarations, that's sloppy practice.
Instead, use a typedef:
typedef struct
{
char signature[25];
int size;
} virus_t;
Then you can declare variables of this type as you please:
static virus_t v[2] =
{
{"Yankee",1813},
{"Doodle",2813}
};
Or with designated initializers:
static virus_t v[2] =
{
[0] = {"Yankee",1813},
[1] = {"Doodle",2813}
};

Get address of a static struct member from another header file

I am having trouble putting together some code in which I wish to have the following:
Have a header file myHeader.h in which I create a type struct myStruct with members int number1, int number2 and int number3. This file would also contain a "getter" prototype for getting the address of each of the members in a struct instance.
A translation unit (file.c) in which I declare a static instance of struct myStruct, i.e. static struct myStruct myStructInstance. This translation unit defines the "getter" functions (I will illustrate with a code example at the end of the post).
Another header file anotherHeader.h in which I wish to - now this is a tricky bit that's causing problems for me - get the addresses of each of the members of a static structure and use them for something.
Here's an example to show what I am talking about.
myHeader.h
struct myStruct{
int number1;
int number2;
int number3;
};
int* get_number1(void);
int* get_number2(void);
int* get_number3(void);
file.c
#include <myHeader.h>
static struct myStruct myStructInstance = {
.number1 = 0,
.number2 = 0,
.number3 = 0
};
int* get_number1(void){
struct myStruct* ptr_myStructInstance = &(myStructInstance);
int* number1Address = &(ptr_myStructInstance->number1);
return number1Address;
}
int* get_number2(void){
struct myStruct* ptr_myStructInstance = &(myStructInstance);
int* number2Address = &(ptr_pfcVariables->number2);
return number2Address;
}
int* get_number3(void){
struct myStruct* ptr_myStructInstance = &(myStructInstance);
int* number3Address = &(ptr_myStructInstance->number3);
return number3Address;
}
anotherHeader.h
#include <myHeader.h>
int* pNumber1 = get_number1();
int* pNumber2 = get_number2();
int* pNumber3 = get_number3();
The problem is that the code shown above throws "initializer element is not constant" error in anotherHeader.h. I've read a few answers as to why we cannot use non-constant expressions when initializing variables with static storage duration, however I do not understand how this relates to my code.
I've read a few answers as to why we cannot use non-constant expressions when initializing variables with static storage duration, however I do not understand how this relates to my code.
A function call is a non-constant expression.
int* pNumber1 = get_number1();
The above code is trying to initialize a global variable with a non-constant expression.
You simply can't call code in the global scope.
However, you could easily accomplish the same thing as what you appear to be trying to do by simply extending myHeader.h with:
extern int *pNumber1, *pNumber2, *pNumber3;
and then allocating and initializing these in file.c with:
int *pNumber1 = &myStructInstance.number1,
*pNumber2 = &myStructInstance.number2,
*pNumber3 = &myStructInstance.number3;

About default C struct values, what about this code?

I'm trying to create structs with default values. I don't know how to accomplish this because every code that I see, is about initialising, and I would it for the natural way like...
struct stuff {
int stuff_a = 1;
int stuff_b = 2...
...and so on...
};
and looking about, I found this (C++) code:
struct a{ a() : i(0), j(0) {}; INT i; INT j;}
I never saw anything like this for C. Please, help me to understand it; I think that it is very nice!
UPDATE: Wait, I'm asking about C!!!! Why changed my question? If that is not possible in C just say... I don't know C++, I didn't know that was about C++...
If you want to set a struct object in one go and you have a C99 compiler, try this:
struct stuff {
int stuff_a;
int stuff_b;
// and so on...
};
struct stuff foo;
/* ... code ... */
foo = (struct stuff){.stuff_b = 42, .stuff_a = -1000};
Otherwise, with a C89 compiler, you have to set each member one by one:
foo.stuff_b = 42;
foo.stuff_a = -1000;
Running example # ideone : http://ideone.com/1QqCB
The original line
struct a{ a() : i(0), j(0) {} INT i; INT j;}
is a syntax error in C.
As you have probably learned from the other answers, in C you can't declare a structure and initialize it's members at the same time. These are different tasks and must be done separately.
There are a few options for initializing member variables of a struct. I'll show a couple of ways below. Right now, let's assume the following struct is defined in the beginning of the file:
struct stuff {
int stuff_a;
int stuff_b;
};
Then on your main() code, imagine that you want to declare a new variable of this type:
struct stuff custom_var;
This is the moment where you must initialize the structure. Seriously, I mean you really really must! Even if you don't want to assign specific values to them, you must at least initialize them to zero. This is mandatory because the OS doesn't guarantee that it will give you a clean memory space to run your application on. Therefore, always initialize your variables to some value (usually 0), including the other default types, such as char, int, float, double, etc...
One way to initialize our struct to zero is through memset():
memset(&custom_var, 0, sizeof(struct stuff));
Another is accessing each member individually:
custom_var.stuff_a = 0;
custom_var.stuff_b = 0;
A third option, which might confuse beginners is when they see the initialization of struct members being done at the moment of the declaration:
struct stuff custom_var = { 1, 2 };
The code above is equivalent to:
struct stuff custom_var;
custom_var.stuff_a = 1;
custom_var.stuff_b = 2;
... create structs with default values ...
That is impossible in C. A type cannot have default values. Objects of any type cannot have a default value other than 0, though they can be initialized to whatever is wanted.
The definition of a struct is a definition of a type, not of an object.
What you asking is about the same thing as a way to have ints default to, say, 42.
/* WRONG CODE -- THIS DOES NOT WORK */
typedef int int42 = 42;
int42 a;
printf("%d\n", a); /* print 42 */
Or, adapting to your example
/* WRONG CODE -- THIS DOES NOT WORK */
struct stuff {
int42 stuff_a;
int65536 stuff_b;
}
struct stuff a;
printf("%d\n", a.stuff_b); /* print 65536 */
Update: This answer assumes we 're talking about C++ because the code posted in the answer is not legal C.
struct a {
a() : i(0), j(0) {} // constructor with initialization list
int i;
int j;
}
The line marked with the comment is simply the constructor for instances of struct a (reminder: structs are just like classes, except that the default member visibility is public instead of private).
The part after the : is called an initialization list: it allows you to initialize the members of the struct with values (either constants or passed as constructor parameters). Initialization of members in this list happens before the body of the constructor is entered. It is preferable to initialize members of classes and structs this way, if at all possible.
See also C++: Constructor versus initializer list in struct/class.
in C (pre C99) the following also works:
#include <stdio.h>
typedef struct
{
int a;
int b;
int c;
} HELLO;
int main()
{
HELLO a = {1,2,3};
printf("here: %d %d %d\n",a.a,a.b,a.c);
exit(1);
}
See codepad
I'm not sure quite sure what your problem is. The standard way of initialising structures in c is like this:
struct a_struct my_struct = {1, 2};
Or the more recent and safer:
struct a_struct my_struct = {.i1 = 1, .i2 = 2};
If there is more than one instance of a structure, or it needs to be re-initialised, it is useful to define a constant structure with default values then assign that.
typedef struct a_struct {
int i1;
int i2;
} sa;
static const sa default_sa = {.i1 = 1, .i2 = 2};
static sa sa1 = default_sa;
static sa sa2 = default_sa;
// obviously you can do it dynamically as well
void use_temp_sa(void)
{
sa temp_sa = default_sa;
temp_sa.i2 = 3;
do_something_with(&temp_sa);
}
// And re-initialise
void reset_sa(sa *my_sa)
{
*my_sa = default_sa;
}
Type initializer is not possible in C.
A value must be stored in the memory.
A type does not occupy memory, what occupies memory is a variable of that type.
struct stuff; is a type; it does not occupy memory
struct stuff aStuff; is a variable of that type; aStuff occupies memory
Because a type does not occupy memory, it is not possible to save values into a type.
If there is syntactic sugar to support store/initialize values into a type then there must be additional code that is inserted to assign values to every instant variables of that type (e.g: in constructor in C++). This will result in a less efficient C if this feature is available.
How often do you need to retain this default values? I think it is unlikely. You can create a function to initialize variable with the default values or just initialize every fields with the values you want. So type initializer is not fundamental thing. C is about simplicity.
Can't initialize values within a structure definition.
I'd suggest:
typedef struct {
int stuff_a;
int stuff_b;
} stuff ;
int stuffInit(int a, int b, stuff *this){
this->stuff_a = a;
this->stuff_b = b;
return 0; /*or an error code, or sometimes '*this', per taste.*/
}
int main(void){
stuff myStuff;
stuffInit(1, 2, &myStuff);
/* dynamic is more commonly seen */
stuff *dynamicStuff;
dynamicStuff = malloc(sizeof(stuff)); /* 'new' stuff */
stuffInit(0, 0, dynamicStuff);
free(dynamicStuff); /* 'delete' stuff */
return 0;
}
Before the days of Object Oriented Programming (C++), we were taught "Abstract Data Types".
The discipline said 'never access your data structures directly, always create a function for it' But this was only enforced by the programmer, instructor, or senior developer, not the language.
Eventually, the structure definition(s) and corresponding functions end up in their own file & header, linked in later, further encapsulating the design.
But those days are gone and replaced with 'Class' and 'Constructor' OOP terminology.
"It's all the same, only the names have changed" - Bon Jovi.

Resources