Assign value to struct array without function - c

I am currently working on a device manager but encountered a problem...
As shown i declared a struct array which is supposed to hold the writer function of a device (vga, serial)... The main issue is that i don't want to call an initialize function, e.g vga_init() or serial_init() to assign them to the structure, tbh that would lose sense... Rather i wanna have those functions stored in an struct array, is there a way to assign vga_write/serial_write without a function, like shown below (Notice the two comments)?
Thanks for incoming advices!
/* device.h */
#define vga 0
#define serial 1
/* device info structure */
struct device_io {
void (*write)(const char *str);
}
extern struct device_io *io[];
/* vga.c */
io[vga] = { .wr = &vga_write }; // Won't work!
void vga_write(const char *str) { ...
/* serial.c */
io[serial] = { .wr = &serial_write }; // Won't work also!
void serial_write(const char *str) { ...

Outside of a function you can only use an initializer expression to assign a value to a global (or static or bss) variable.
That in turn means the initializer expression you're using must initialize the entire array at once, like so:
static int test[] = { 4, 5, 6 };
, which, of course, can be extended to arbitrary data like function pointers or structs
void some_func0(const char *v) { }
void some_func1(const char *v) { }
static void (*test[])(const char *) = { &some_func0, &some_func1 };
. As you can see though, this requires that all the functions you intend to use are at least declared before the initializer. At the point of declaration of the array in your question (in "device.h") I presume you don't know all implementations.
However, you need to have a source file somewhere in your program where you do know all array elements at once. To work around this, you can restructure your code like:
device.h
extern void (*test[])(const char *); // <-- or your struct type
vga.h
extern void vga_write(const char *);
vga.c
void vga_write(const char *c) {...
device_array_initialization_helper_this_is_a_very_verbose_file_name.c
#include "device.h"
#include "vga.h"
// Definition of the array, which is declared in device.h
void (*test[])(const char *) = { &vga_write, ... };
Of course, you can use your struct type as well.

Related

C Declare array of struct/pointer to array of structs

I have an example tutorial with 2 files, "functions.c" and "functions.h" which contain the prototypes and the body of the functions.
In the example there isn't the main that containing the declaration of the array of struct/pointer to array of structs and the calls to the functions.
functions.c:
#include "functions.h"
const char *getTeamA(const sTest *p)
{
return p->teamA;
}
void setTeamA(sTest *p, char *s)
{
strcpy(p->teamA, s);
}
int getNum(const sTest *p)
{
return p->num;
}
void setNum(sTest *p, int i)
{
p->num = i;
}
functions.h:
#ifndef FUNCTIONS_H_
#define FUNCTIONS_H_
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_CHAR 20
#define SIZE 5
typedef struct {
char teamA[MAX_CHAR];
int num;
// ...
} sTest;
const char *getTeamA(const sTest *p);
void setTeamA(sTest *p, char *s);
int getNum(const sTest *p);
void setNum(sTest *p, int i);
#endif /* FUNCTIONS_H_ */
So my question is
How can i declare the struct according to the code written above?
So for example:
int main()
{
sTest data[SIZE]; //size isn't important
sTest *dataPtr = data;
setTeamA(dataPtr[0].teamA, "name1");
// ...
printf("%d", getNum(dataPtr[1].num)); // just an example. i know that it isn't initialized
// ...
return 0;
}
Is this the correct way? Or is there a better way to declare variables and pass them to the functions?
The important thing is that i have to stick to the code written in functions.c and functions.h, so the functions cannot directly modify the struct data, you need to use pointers (because there are member selection operator "->" in functions.c).
You don't need to have dataPtr. You can do the exact same thing by doing data[i], since you declared data as an array of sTests, and so data points to the first element in the array.
Let's deconstruct what you're doing when you're calling setTeamA(dataPtr[0].teamA, "name1"). You're trying to set the first sTest struct in the data array to have "name1" as the teamA field. Notice that the prototype for setTeamA() actually takes in a sTest *p. In your example, you're passing in the teamA field. So what you really want to call is setTeamA(&dataPtr[0], "name1"). This translates to the pointer pointing to the data at dataPtr[0].
While this works, as I said before, the dataPtr is unecessary. So this is equivalent to:
setTeamA(&data[0], "name1").
Also worth noting, you can simply write:
setTeamA(data, "name1")
since data is already a pointer to the first element in the array.
Use
setTeamA(&data[0], "name1")
It indexes to index 0 and then takes the reference (which is a pointer) of the result therefore making the type an sTest* then the setTeamA function will do it's job setting the teamA field.
That dataPtr variable is useless here.

How to declare a function that has a structure containing an array, whose size is determined by argv, as an argument?

I have a structure dt that contains an internal array whose size is determined by argv. I need to feed this structure to a function func so I tried to declare it with a void pointer argument but the compiler is complaining that it's not being void at the end of the day. Here is the code :
#include <stdio.h>
#include <string.h>
void func(void *);
int main(int argc, char *argv[])
{
int RETSIZE;
sscanf(*++argv, "%d", &RETSIZE);
struct
{
char name[6];
char ret[RETSIZE];
} dt[100];
func(dt);
}
void func(void *dt)
{
dt->ret[2] = 3;
}
How and where do I declare the structure dt and the function func so it works out ?
If you want to use a structure in two (or more) functions, you need to define it in the global scope, so both functions have access to it. There's simply no way around it.
As for the array, in this case it's not possible to use variable-length arrays. You need to either use a flexible array member or to use a pointer. Both of these requires dynamic allocation of the heap. You also need to keep the number of elements in the array as a member in the structure.
Try This:
#include <stdio.h>
#include <string.h>
#define MAX_OBJECT 100
typedef struct
{
char name[6];
char ret[];
} dt;
void func(dt *strPtr)
{
strPtr->ret[2] = 3;
}
int main(int argc, char *argv[])
{
dt obj[MAX_OBJECT];
func(&obj[0]);
printf("Verify values written successfully or not: %d \n",obj[0].ret[2]); //Just for example
}
Here are few corrections/comments for your code:
- Keep the struct in global scope so that the struct is visible to all the whole code.
- In the func void func(void *dt), you should again type cast it the original datatype(struct in this case), in order to use it.
- As suggested in the above post, in C lang the size of the array(string) should be known to the compiler. Or else some garbage value will be present in RETSIZE and that much amount of stack memory is allocated to the ret. So, the struct should be
struct mystruct
{
char name[6];
char *ret;
};
And for memory allocation,
dt.ret = (char *)malloc(RETSIZE*sizeof(char));
- Also your func should be modifed cuz you have declared an struct array of 100, and you are passing it to the func

How to access elements in an array of structs (not global)

Trying to continue with my assignment but would like to sidetrack and figure out how array of structs work. Not sure if I'm not looking hard enough but I can't seem to find an answer.
Let's say I have one source file, main.c
#include "data.h" //this contains the struct data.
newPerson person[20];
int mainMenu(){
addName();
}
void addName(){
strcpy(person[0].firstName, "George");
}
Doing it this way, I'm able to access the array of struct, however isn't this method considered taboo since my array of person is a global variable?
I then tried moving the array initialization into the main function instead
#include "data.h" //this contains the struct data.
int mainMenu(){
newPerson person[20];
addName();
}
void addName(){
strcpy(person[0].firstName, "George");
}
Doing it this way, when I get to the addName() function, I get a 'person undeclared' error. How can I access the person[] array outside of its function without making it a global variable? Thank for the help in advance. Below I have the example data.h included if needed.
data.h
typedef struct person{
char firstName[20];
char familyName[20];
char telephoneNum[20];
}newPerson;
Just pass parameters to the addName() function.
Example
#include "data.h" //this contains the struct data.
int mainMenu(){
newPerson person[20];
addName(person, 0, "George");
}
void addName(newPerson *person, unsigned int index, const char *const name) {
if ((person == NULL) || (index >= 20))
return; /* ^ this number could be specified with a macro */
/* or via a parameter */
strcpy(person[index].firstName, name);
}
Yeah, pass the variable, person in this case.
person is an array of struct newPerson.
to pass arrays as parameters you should define the function like this
//Option 1, the last dimension without number
void addName(newPerson person[]){
//...
}
//Option 2, as a pointer, but it neets a cast on the call (newPerson*)
void addName(newPerson *person){ //I prefer option 1
//...
}

Pointer at function: access the data inside a structure?

I listed some example code below and the question is if there is a way for the function_name to access the value of number from struct_name?
typedef struct struct_name {
int number
void (*func)();
} * struct_name_ptr;
void function_name() {
//access number from struct
}
main() {
struct_name_ptr newobject;
newobject->func=&function_name;
newobject->func(); //can it print the value of the number in the structure above?
}
Uh - no.
A struct can certainly contain a function pointer. But the function you call wouldn't have any knowledge of the struct. Unless you passed a pointer as a function argument, or made the struct global.
With my limited knowledge of programming, I don't think this is possible. Though the struct contains a function pointer, the address of the function assigned to it is different and I don't think there will be anyway for it to access it unless you pass it as an argument.
Well, two things, struct_name->number should have a value, and it either needs to be in the same scope as &function_name or it needs to be explicitly passed. Two ways to do it:
/* Here is with a global calling struct */
#include<stdio.h>
typedef struct struct_name {
int number;
void (*func)();
} * struct_name_ptr;
struct struct_name newobject = { 0 };
void function_name() {
printf("%d",struct_name);
}
void main() {
struct struct_name_ptr newobject;
newobject->func=&function_name;
newobject->func();
}
/* And one with a modified function_name */
#include<stdio.h>
typedef struct struct_name {
int number;
void (*func)();
} * struct_name_ptr;
void function_name(struct_name) {
printf("%d",struct_name);
}
void main() {
struct struct_name_ptr newobject;
newobject.number = 0;
newobject->func=&function_name;
newobject->func(newobject);
}
No, a pizza won't ever know what the pizza delivery guy, who delivered it, looks like.
A regular function is just an address in memory. It can be called using a function pointer like in this case. In any case: The function won't know how it was called. In particular it won't know that it was called using a function pointer that's part of (a piece of memory corresponding to) some struct.
When using a language with classes like C++, member functions will have a hidden argument which is a pointer to the class instance. That's how member functions know about their data.
You can 'simulate' a simple OOP in plain C, for your example like:
typedef struct {
int number;
void (*func)();
} class;
void function_name(class *this) {
printf("%d",this->number);
}
#define CALL(c,f) c.f(&c)
int main() {
class object={12345,function_name};
CALL(object,func); // voilá
}

Good Coding Practice With C structs?

In C, you can define structures to hold an assortment of variables;
typedef struct {
float sp;
float K; // interactive form - for display only
float Ti; // values are based in seconds
float Td;
} pid_data_t;
But lets say that K, Ti, and Td should never be set publicly, and should only be used for storing the values after they have been manipulated. So, I want these values not to be updated by;
pid_data_t = pid_data;
pid_data.K = 10; // no good! changing K should be done via a function
I want them to be set via a function;
int8_t pid_set_pid_params(float new_K_dash, float new_Ti_dash,
float new_Td_dash)
{
… // perform lots of things
pid_data->K = new_K_dash;
pid_data->Ti = new_Ti_dash;
pid_data->Td = new_Td_dash;
}
Any thoughts on this? I know C++ uses like a get/set property, but was wondering what people might do on C.
Your public interface should only offer an opaque pointer (maybe DATA*, or data_handle), as well as handler functions create_data(), set_data_value(), read_data_value(), free_data(), etc., which operate on the opaque pointer.
Much like FILE*.
Just don't give your clients the internal header files :-)
// library.h
typedef struct data_t * data_handle;
data_handle create_data();
void free_data(data_handle);
Private implementation (don't ship):
#include "library.h"
struct data_t
{
/* ... */
};
data_handle create_data() { return malloc(sizeof(struct data_t)); }
void free_data(data_handle h) { free(h); }
/* etc. etc. */
in C, by convention....
for OO C like this...
I'd have a pid_data_create(&data) // initializes your struct
and pid_data_set_proportional_gain(&data, 0.1);
etc...
so basically achieving a C++ ish class... prefix all functions with the "class" / "struct" name and always pass the struct * as the first parameter.
also, it should store function pointers for polymorphisim, and you shouldn't call those function pointers directly, again, have a function that takes your struct as a parameter, and then the can make the function pointer call (can check for nulls, fake inheritance/virtual functions, and other stuff)
The canonical way to do this is by using a combination of opaque pointers and public structs, along with allocators, getters and setters for the private elements. About along these lines:
foo.h
typedef struct Foo {
/* public elements */
} Foo;
Foo *new_Foo(void);
void Foo_something_opaque(Foo* foo);
foo.c
#include "foo.h"
typedef struct Private_Foo_ {
struct Foo foo;
/* private elements */
} Private_Foo_;
Foo *new_Foo(void)
{
Private_Foo_ *foo = malloc(sizeof(Private_Foo_));
/* initialize private and public elements */
return (Foo*) foo;
}
void Foo_something_opaque(Foo *foo)
{
Private_Foo_ *priv_foo = (Private_Foo_*) foo;
/* do something */
}
This woks, because C guarantees, that the address of a struct variable always is equal to the address of the very first struct element. We can use this to have a Private_Foo_ struct, containing a public Foo at the beginning, giving out pointers to the whole thing, with the compilation units not having access to the Private_Foo_ struct defintion just seeing some memory without any context.
It should be noted that C++ works quite similar behind the curtains.
Update
As KereekSB pointed out, this will break if used in a array.
I say: Then don't make Foo f[], however tempting, but make an arrays of pointers to Foo: Foo *f[].
If one really insists on using it in arrays do the following:
foo_private.h
typedef struct Private_Foo_ {
/* private elements */
} Private_Foo_;
static size_t Private_Foo_sizeof(void) { return sizeof(Private_Foo_); }
foo_private.h is written in a way, that it can be compiled into an object file. Use some helper program to link it and use the result of Private_Foo_sizeof() to generate the actual, plattform dependent foo.h from some foo.h.in file.
foo.h
#include
#define FOO_SIZEOF_PRIVATE_ELEMENTS <generated by preconfigure step>
typedef struct Foo_ {
/* public elements */
char reserved[FOO_SIZEOF_PRIVATE_ELEMENTS];
} Foo;
Foo *new_Foo(void);
void Foo_something_opaque(Foo* foo);
foo.c
#include "foo.h"
#include "foo_private.h"
Foo *new_Foo(void)
{
Foo *foo = malloc(sizeof(Foo));
/* initialize private and public elements */
return (Foo*) foo;
}
void Foo_something_opaque(Foo *foo)
{
Private_Foo_ *priv_foo = (Private_Foo_*) foo.reserved;
/* do something */
}
IMHO this is really messy. Now I'm a fan of smart containers (unfortunately there's no standard container library for C). Anyway: In such a container is creates through a function like
Array *array_alloc(size_t sizeofElement, unsigned int elements);
void *array_at(Array *array, unsigned int index);
/* and all the other functions expected of arrays */
See the libowfaw for an example of such an implementation. Now for the type Foo it was trivial to provide a function
Array *Foo_array(unsigned int count);
Object orientation is a way of thinking and modelling, data encapsulation where struct data should not be modified directly by the user can be implemented this way:
my_library.h
#ifndef __MY_LIBRARY__
#define __MY_LIBRARY__
typedef void MiObject;
MyObject* newMyObject();
void destroyMyObject(MyObject*)
int setMyObjectProperty1(MyObject*,someDataType1*);
/*Return a pointer to the data/object, classic pass by value */
someDataType1* getMyObjectProperty2Style1(MyObject*);
int setMyObjectProperty2(MyObject*,someDataType2*);
/* The data/object is passed through reference */
int getMyObjectProperty2Style2(MyObject*,someDataType2**);
/* Some more functions here */
#endif
my_library.c
struct _MyHiddenDataType{
int a;
char* b;
..
..
};
MyObject* newMyObject(){
struct _MyHiddenData* newData = (struct _MyHiddenData*)malloc(sizeof(struct _MyHiddenData);
//check null, etc
//initialize data, etc
return (MyObject*)newData;
}
int setMyObjectProperty1(MyObject* object,someDataType1* somedata){
struct _MyHiddenData* data = (struct _MyHiddenData*)object;
//check for nulls, and process somedata
data->somePropery=somedata;
}
someDataType1* getMyObjectProperty2Style1(MyObject*){
struct _MyHiddenData* data = (struct _MyHiddenData*)object;
//check for nulls, and process somedata
return data->someProperty;
}
/* Similar code for the rest */
And this way you have encapsulated the struct properties as if they were private. On the same manner static functions inside my_libray.c would behave as private functions. Get a good look at C and you'll see, that your imagination is the limit to what you can do.

Resources