I have a program that stores two different structs (tri & quad) in an array of a special struct defined below:
struct inst_ptr
{
void* p;
unsigned type;
};
The structs tri & quad have a superbase property
The following code displays how the structs are defined:
struct inst
{
char name[50];
int id;
};
struct tri
{
struct inst superbase;
};
struct quad
{
struct inst superbase;
};
Function for creating new instances (all located outside of main):
struct inst_ptr insts[100]; //instance container
int cinsts=0; //instance count
int inst_new(int type)
{
switch(type)
{
case TYPE_TRI:
{
struct tri i;
insts[cinsts].p=&i;
}
case TYPE_QUAD:
{
struct quad i;
insts[cinsts].p=&i;
}
}
insts[cinsts].type=type;
cinsts++;
return cinsts-1; //return index of instance in array
}
In my main function I create a sample tri, writing and reading it's values:
struct tri* t1=(struct tri*)insts[inst_new(TYPE_TRI)].p;
strcpy(t1->superbase.name, "tri1");
t1->superbase.id=70;
printf("id: %d\n", t1->superbase.id);
printf("id: %d\n", t1->superbase.id); <- problem occurs here and onward
Printing the id the first time works, printing 70 in the output. However, the second time it prints a long random integer.
Output:
id: 69
id: 1973802146
id: 1973802146
As you shown above, after the second read it keeps printing 1973802146. I'm not really sure what I'm doing wrong but I have a feeling I'm missing an extremely basic concept relating to pointers and structs.
You are saving the address of local variables in the array. That's bad because those variables doesn't exist once the function returns. You should use dynamic allocation instead.
Besides that you switch need break statements. And perhaps also a default case.
Like:
int inst_new(int type)
{
switch(type)
{
case TYPE_TRI:
{
struct tri *p = malloc(sizeof *p);
if (p == NULL) exit(1);
insts[cinsts].p=p;
break;
}
case TYPE_QUAD:
{
struct quad *p = malloc(sizeof *p);
if (p == NULL) exit(1);
insts[cinsts].p=p;
break;
}
default:
{
// Unknown type.. add error handling here
exit(1);
}
}
insts[cinsts].type=type;
cinsts++;
return cinsts-1; //return index of instance in array
}
As an alternative you can do:
int inst_new(int type)
{
insts[cinsts].p = NULL
switch(type)
{
case TYPE_TRI:
{
insts[cinsts].p=malloc(sizeof(struct tri));
break;
}
case TYPE_QUAD:
{
insts[cinsts].p=malloc(sizeof(struct quad));
break;
}
}
if (insts[cinsts].p == NULL) exit(1); // malloc failed
insts[cinsts].type=type;
cinsts++;
return cinsts-1; //return index of instance in array
}
Related
Im beggining with linked list in C, and I found some problems where (if I understood well) manipulate linked lists without knowing internal structre (fields)!
Is it possible to append/remove an item in a linked list without knowledge of it's internal structure(opaque) given a pointer to the linked list?
Edit (adding details).
So the problem is to create a set of functions to manipulate linked lists, given a handler on the linked list as a parameter which is declared in the follwoing way :
typedef struct list *handler;
so for example I created a function to create a linked list :
handler ListCreate()
{
handler list = (handler)malloc(sizeof(handler));
if(!list)
{
printf("can not allocate memory \n");
return NULL;
}
return list;
}
but when it comes to appending, Im just blocked and I thought it can't be done, but maybe I'm wrong.
So this is the prototype of the function :
int ListAppend(handler list, void *item)
I wanted to do something similar, but I had to figure it out myself. The idea is to make an opaque object interface, and then give access to attributes of the implementation file by casting using a switch statement. I'm doing it this way to follow the dependency inversion principle. All of the code is in a single file to show that it compiles, but the three comment lines //interface, //dependency, and //context can be broken into different files so you can try different implementations of the dependency file without having to change the interface file.
#include <stdlib.h>
#include <stdio.h>
//interface
typedef enum {
DEP1,
DEP2
} Type;
typedef struct Interface{
struct Interface* ptr;
void* data;
int (*getConcreteStuff)(struct Interface*, Type t);
} Interface;
//dependency
typedef struct {
int concreteStuff1;
} Dependency1;
typedef struct {
int concreteStuff2;
} Dependency2;
static int getConcreteStuff(Interface* interface, Type t) {
switch(t){
case DEP1:
return ((Dependency1*) interface->data)->concreteStuff1;
break;
case DEP2:
return ((Dependency2*) interface->data)->concreteStuff2;
break;
}
}
Interface Dependency1_new(Interface* ptr){
Dependency1* d = malloc(sizeof(*d));
d->concreteStuff1 = 1;
struct Interface x = {ptr, d, getConcreteStuff };
return x;
}
Interface Dependency2_new(Interface* ptr){
Dependency2* d = malloc(sizeof(*d));
d->concreteStuff2 = 2;
struct Interface y = {ptr, d, getConcreteStuff };
return y;
}
//context
typedef struct {
Interface i;
} Context;
void Context_doSomething(Context* ctx, Type t){
printf("%d\n", ctx->i.getConcreteStuff(&ctx->i, t));
}
int main(){
Context ctx1 = { Dependency1_new(NULL) };
Context_doSomething(&ctx1, DEP1);
Context ctx2 = { Dependency2_new(&ctx1.i) };
Context_doSomething(&ctx2, DEP2);
Context ctx3 = { *ctx2.i.ptr };
Context_doSomething(&ctx3, DEP1);
return 1;
}
I am working on a project that involves the implementation of the Stack data structure via a singly linked list. More specifically, I am wondering if there is a way to automatically cycle(iterate) through the attributes of a struct which happen to be of different data types -- it would greatly help when reading input, or when adding more attributes, so, I don't have to manually change everything.
Specific struct
typedef struct Student
{
char regNumber[30];
char fName[30];
char lName[30];
char email[50];
int phoneNumber;
short age;
} Student;
For example: attribute[0] would be regNumber, attribute[1] would be fName, attribute[n] would be the n^{th} element
I cannot think of any good way to do this that neither uses undefined behavior, nor very weird constructs. And the fact that you want fields of different type does not make it easier.
If I wanted to write code like this (which I don't) I would probably do something like this.
void *get_attr(struct Student *student, int field)
{
switch(field) {
case 0 : return (void*)&student->regNumber;
case 1 : return (void*)&student->fName;
case 2 : return (void*)&student->lName;
case 3 : return (void*)&student->email;
case 4 : return (void*)&student->phoneNumber;
case 5 : return (void*)&student->age;
}
return NULL;
}
and then you can use it like this:
int main()
{
struct Student s = { "xxx333", "Jonny", "BGood", "my#email.com", 12345, 22 };
printf ("%s\n%s\n%s\n%s\n%d\n%d\n",
(char*)get_attr(&s, 0),
(char*)get_attr(&s, 1),
(char*)get_attr(&s, 2),
(char*)get_attr(&s, 3),
*(int*)get_attr(&s, 4),
*(short*)get_attr(&s, 5)
);
}
Spontaneously, I don't see a good way around those casts. One way, but not necessarily a good way, is to do something like this:
union attr_field {
char *c;
int *i;
short *s;
};
enum attr_type { CHAR, INT, SHORT };
struct attr {
union attr_field attr;
enum attr_type type;
};
struct attr get_attr2(struct Student *student, int field)
{
struct attr ret;
switch(field) {
case 0 : ret.attr.c = student->regNumber; ret.type = CHAR; break;
case 1 : ret.attr.c = student->fName; ret.type = CHAR; break;
case 2 : ret.attr.c = student->lName; ret.type = CHAR; break;
case 3 : ret.attr.c = student->email; ret.type = CHAR; break;
case 4 : ret.attr.i = &student->phoneNumber; ret.type = INT; break;
case 5 : ret.attr.s = &student->age; ret.type = SHORT; break;
}
return ret;
}
void print_attr(struct attr a)
{
switch(a.type) {
case CHAR: printf("%s\n", a.attr.c); break;
case INT: printf("%d\n", *a.attr.i); break;
case SHORT: printf("%d\n", *a.attr.s); break;
}
}
int main()
{
struct Student s = { "xxx333", "Jonny", "BGood", "my#email.com", 12345, 22 };
for(int i=0; i<6; i++) {
struct attr a = get_attr2(&s, i);
print_attr(a);
}
}
Note that I sometimes used struct and sometimes pointer to struct as argument to functions. The choice was not due to any particular reason. It just happened to be that way. You can do it either way, and both have their pros and cons. If performance is an issue, I'd go for pointers. Same thing with the union. I could have chosen a char array and used strncpy instead. And I could have skipped the pointers for int and short. Here my thought was something like that it's more clear if ALL union members are pointers. But you have to make your own decisions about all this. If you go for pointers, it might be wise to use the const qualifier where appropriate.
If you really want to do so, I guess you could do something like this:
void *attribs[6];
attribs[0] = (void*)s.regNumber;
printf("%s", (char*)attribs[0]);
That could be combined with the techniques mentioned above. For instance
struct attr attribs[6];
for(int i=0; i<6; i++)
attribs[i] = get_attr2(&s, i);
This is a detailed program I am trying to implement:
A naturalist is off to explore the amazon jungle, and needs a computer program to record information about all the new species discovered. For each new species it is necessary to store the name (max 128 characters), size (a real number), and the type of animal. mammal, insect, bird, or fish).
Here is what a sample run should look like (with the keyboard input shown in italics) ...
> NewSpecies
Enter animal information ("exit" to exit)
What is the name : bloatfish
What is the size : 12.47
What is the type : fish
Enter animal information ("exit" to exit)
What is the name : stingybeasty
What is the size : 0.13
What is the type : insect
Enter animal information ("exit" to exit)
What is the name : toothfulsloth
What is the size : 33.33
What is the type : mammal
Enter animal information ("exit" to exit)
What is the name : exit
The following new species were found:
bloatfish has size 12.47 and is a fish
stingybeasty has size 0.13 and is a insect
toothfulsloth has size 33.33 and is a mammal
You must ...
Implement the program in C.
An array of structures must be used, so that each new species can be recorded in an element of the array.
The type of animal is represented as an enum type, indicating one of mammal, insect, bird, or fish.
It's not known in advance how many new species will be found, so the program must malloc for an initial array of size 1, and use the doubling realloc technique to get more memory as required. You must always check the return value from malloc, as done in the Malloc wrapper function (or just use Malloc :-).
My attempt:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAX_CHAR 128
#define LENGTH(A) (sizeof(A)/sizeof(A[0]))
typedef char String[MAX_CHAR];
typedef enum {mammal, insect, bird, fish, error} AnimalType;
typedef struct{
String name;
double size;
AnimalType type;
} Animal;
void * Malloc(size_t Size) {
void * Memory;
if ((Memory = malloc(Size)) == NULL) {
perror("Cannot malloc");
exit(EXIT_FAILURE);
} else {
return(Memory);
}
}
AnimalType CheckAnimalType(String type) {
if (!strcmp(type,"mammal")) {
return (mammal);
}
if (!strcmp(type,"insect")) {
return (insect);
}
if (!strcmp(type,"bird")) {
return (bird);
}
if (!strcmp(type,"fish")) {
return (fish);
}
return (error);
}
char *PrintAnimalType(AnimalType type){
switch(type){
case mammal: return "mammal"; break;
case insect: return "insect"; break;
case bird: return "bird"; break;
case fish: return "fish"; break;
case error: return "error";
}
return "error";
}
void printData(Animal *animal, int size) {
printf("The following species were found:\n");
for(int i = 0; i < size-1; i++)
printf("%s has size %.2lf and is a %s\n", animal[i].name, animal[i].size, PrintAnimalType(animal[i].type));
}
void MainMenu(Animal *animal, int *size){
for(;;){
Animal newAnimal;
String animalName;
double animalSize;
String animalType;
printf("Enter animal information (\"exit\" to exit)\n");
printf("What is the name : ");
scanf("%s", animalName);
if(!strcmp(animalName, "exit")) break;
strcpy(newAnimal.name, animalName);
printf("What is the size : ");
scanf("%lf", &animalSize);
if(newAnimal.size == 0) break;
newAnimal.size = animalSize;
printf("What is the type : ");
scanf("%s", animalType);
newAnimal.type = CheckAnimalType(animalType);
if((animal = realloc(animal, sizeof(newAnimal)*((*size)+1))) == NULL) {
printf("MEMORY ERROR: problem reallocating array\n");
return;
}
animal[(*size)-1] = newAnimal;
(*size)++;
}
printData(animal, *size);
}
int main(void) {
int size = 1;
Animal *animal = Malloc(sizeof(Animal));
MainMenu(animal, &size);
free(animal);
return 0;
}
I am attempting to implement the above in C but I get this error directly after execution:
Link to error: https://pastebin.com/Wcu0wtet
In MainMenu you call realloc on animal. This may resize the existing buffer, but usually allocates a new on, changing the value of the pointer. The new pointer is stored in the local animal variable, and not the variable in main.
When you return to main, you call free(animal), which will attempt to free the original animal buffer that has already been freed by the call to realloc.
You'll want to pass the modified buffer pointer back to the caller, either as a return value, or by passing a pointer to the original variable (Animal **).
I'm having different different types of structs, which are going to be passed to a function which performs the same tasks on them.
int menu_parameter_arrow_print(game_setting_identifier* identifier, controller_direction direction, uint8_t position)
{
if((position > setting->alternatives_number) || position < 0)
{
#ifdef OLED_PRINT_DEBUG_ENABLE
OLED_debug_print("Out of bounds");
#endif
return RETURN_VALUE_FAILURE;
}
else
{
switch ((int)*identifier)
{
case ((int) GAME_SETTING_ANALOG):
game_setting_analog* setting = (game_setting_analog*)&identifier;
case ((int) GAME_SETTING_TOGGLE):
game_setting_toggle* setting = (game_setting_toggle*)&identifier;
case ((int) GAME_SETTING_VALUE):
game_setting_value* setting = (game_setting_value*)&identifier;
}
This function gives a conflicting type-error
The operations performed on the structs are the same, but the structs contains different types of members:
struct game_setting_analog
{
//Identifier for the game-setting type:
game_setting_identifier identifier;
//Alternatives:
char* alternatives[4];
};
typedef struct game_setting_value game_setting_value;
struct game_setting_value
{
game_setting_identifier identifier;
uint8_t* alternatives[6];
uint8_t alternatives_number;
};
typedef struct game_setting_toggle game_setting_toggle;
struct game_setting_toggle
{
//Identifier for the game-setting type:
game_setting_identifier identifier;
toggle_state* alternatives[2];
};
typedef struct game_setting_difficulty game_setting_difficulty;
struct game_setting_difficulty
{
game_setting_identifier identifier;
char* alternatives[3];
};
Actions will be performed on the 'alternatives'-member of the structs, even though these members are of different types.
Is there a solution to doing this without having to use one if-statement for each identifier?
Edit: With a modification to the switch-case, I'm able to get the initialization compiled. The variables inside the switch-scope is however not visible to the rest of the function
int menu_print_parameter_line(game_setting_identifier* identifier, controller* C, uint8_t position)
{
uint8_t next_position = position;
controller_direction previous_direction = C->joystick.generalDirection;
if ((identifier == NULL) || (C == NULL) || (position == NULL))
{
return -1;
}
switch((int) identifier)
{
case ((int) GAME_SETTING_ANALOG):
{
game_setting_analog* setting = (game_setting_analog*)identifier;
uint8_t alternatives_number = 4;
}
break;
case ((int) GAME_SETTING_TOGGLE):
{
game_setting_toggle* setting = (game_setting_toggle*)identifier;
uint8_t alternatives_number = 2;
}
break;
case ((int) GAME_SETTING_VALUE):
{
game_setting_value* setting = (game_setting_value*)identifier;
uint8_t alternatives_number = setting->alternatives_number;
}
break;
default:
{
return -1;
}
break;
}
#ifdef MENU_PARAMETER_ASSIGNMENT_DEBUG
OLED_debug_print("before switch-case");
#endif
switch (previous_direction)
{
case LEFT:
next_position -= 1;
if(next_position <= 0)
{
next_position = alternatives_number;
}
I personally don't like the inheritance model that depends on the first member of the structure, like the BSD socket library is using. Basically you are just trying to implement std::variant from c++ in C.
Is there a solution to doing this without having to use one if-statement for each identifier?
The object-oriented concept of interface works very nice and I believe is applicable in this case. It takes some C discipline to write it, but it works like a charm and you could be looking for it here.
I copied your definitions from which I removed typedefs because I don't like them:
struct game_setting_analog {
char* alternatives[4];
};
struct game_setting_value {
uint8_t* alternatives[6];
uint8_t alternatives_number;
};
struct game_setting_toggle {
toggle_state* alternatives[2];
};
struct game_setting_difficulty {
char* alternatives[3];
};
Let's first implement the interface abstraction with a function pointer that allows to get the alternatives number:
// forward definition
struct game_setting_s;
// the virtual table for game_settings
struct game_setting_vtable_s {
uint8_t (*get_alternatives_number)(struct game_setting_s *t);
// TODO: add other members, constructor, copy constructor, destructor, etc.
};
// represents any game_setting
// exposes a public interface to access and manipulate a game_setting
struct game_setting_s {
// the vtable is const, so it can save RAM
const struct game_setting_vtable_s *v;
// this is a pointer to private settings data
void *data;
};
// accessor for less (or more ;) typing
static inline
uint8_t game_setting_get_alternatives_number(struct game_setting_s *t) {
// alternative you could pass t->data to the function, I pass it all
// so that functions can modify the t->data member
// and also so that advanced functions usages can use like container_of macros
return t->v.get_alternatives_number(t);
}
Then you need to provide the virtual tables for each of the types. The definitions can be in separate types, so you can have a separate .c/.h file pair for each of the type, just exposing public interface.
// game_setting_analog --------------------
static
uint8_t game_setting_analog_get_altenatives_number(struct game_setting_s *t)
{
return 4;
}
const struct game_setting_vtable_s game_setting_analog_vtable = {
.get_alternatives_number = game_setting_analog_get_altenatives_number,
};
// game_setting_toggle --------------------
static
uint8_t game_setting_toggle_get_altenatives_number(struct game_setting_s *t) {
struct game_setting_toggle *data = t->data;
return data->alternatives_number;
}
const struct game_toggle_vtable_s game_setting_toggle_vtable = {
.get_alternatives_number = game_setting_toggle_get_altenatives_number,
};
// and so on...
Then your function takes just the interface and is very clear without any switch case:
int some_function_that_needs_to_know_which_setting_is_passed(struct game_setting_s *s) {
int number_of_alternatives = game_setting_get_alternatives_number(s);
}
Remember to construct the interface object properly and watch who owns the memory of the object. Let's construct a toggle and call out function:
struct game_settting_toggle memory;
// your function to initialize the toggle
game_setting_toggle_intialize(&memory);
// the interface is constructed with the proper vtable
// and a pointer to proper memory region with the data
struct game_setting_s any_setting = {
.vtable = game_setting_toggle_vtable,
.data = &memory,
};
// the initailize function could be in interface too
// so you would just call game_setting_initialize(&any_setting);
// with usage of dynamic allocation, you can just ex.
// struct game_setting_s *any_setting = game_setting_new_toggle();
// and write proper object-oriented factories
// finally call our function.
some_function_that_needs_to_know_which_setting_is_passed(&any_setting);
Case labels do not provide scopes for variables. All three setting variables within the switch have different types which are the conflicts the compiler. Use brackets to define scopes:
switch ((int)*identifier)
{
case ((int) GAME_SETTING_ANALOG):
{
game_setting_analog* setting = (game_setting_analog*)&identifier;
}
case ((int) GAME_SETTING_TOGGLE):
{
game_setting_toggle* setting = (game_setting_toggle*)&identifier;
}
case ((int) GAME_SETTING_VALUE):
{
game_setting_value* setting = (game_setting_value*)&identifier;
}
}
Also, you're not breaking in the cases, so the code in all three cases are run if ((int)*identifier == (int) GAME_SETTING_ANALOG)
I must read and extract some values from string.
These values are coded like this:
k="11,3,1" v="140.3"
I have defined the codes and created struct with all field as well as a temp one where I store k and v. In fillFields proc I transfer values from temp struct to the right one (with the valid types).
It works but I have many fields and fillFields would need to have many if-conditions. Maybe someone could give me any hint how to write it smarter.
The simplified code now:
#define ASK "11,3,1"
#define BID "11,2,1"
#define CLOSE "3,1,1"
typedef struct tic {
float ask;
float bid;
float close;
}tic, *ticP;
typedef struct pElem {
char * k;
char * v;
}pElem, *pElemP;
void fillFields(ticP t, pElemP p)
{
if (strcmp( ASK, p->k)==0)
{
printf ("ASK %s\n", p->v);
t->ask = atof(p->v);
}
if (strcmp( BID, p->k)==0)
{
printf ("BID %s\n", p->v);
t->bid = atof(p->v);
}
if (strcmp( CLOSE, p->k)==0)
{
printf("CLOSE >>>%s<<<\n", p->v) ;
t->close = atof (p->v);
}
}
Rather than save the text value in pElem, save the converted values.
This creates an extra step in parsing k="11,3,1" v="140.3", to convert text to an enumerated type, but it's paid once. The fillFields() calls then run simpler. Assuming you have more ticP variables, it's a win.
typedef enum pElem_type {
pElem_None, pElem_ASK, pElem_BID, pElem_CLOSE, pElem_N
} pElem_type;
typedef struct pElem {
pElem_type type;
float value;
} pElem;
void fillFields(ticP t, const pElem *p) {
switch (p->type) {
case pElem_ASK:
printf("ASK %f\n", p->value);
t->ask = p->value;
break;
case pElem_BID:
printf("BID %f\n", p->value);
t->bid = p->value;
break;
case pElem_CLOSE:
printf("Close %f\n", p->value);
t->close = p->value;
break;
default:
printf("Error\n");
}
}
// Further simplifications possible
typedef struct tic {
float field[pElem_N];
}tic, *ticP;
static const char *FieldName[pElem_N] = {
"None", "ASK", "BID", "Close"
};
void fillFields(ticP t, const pElem *p) {
if (p->type < pElem_N) {
printf("%s %f\n", FieldName[p->type], p->value);
t->field[p->type] = p->value;
}
}