What is best solution for initialize struct array? - c

First solution:
struct str {
char *name;
int flag;
};
enum {
HELP,
OUTPUT,
OTHER
};
typedef struct str table;
table arr[] = {
{ "help", HELP },
{ "output", OUTPUT },
{ NULL, OTHER },
};
int main(int argc, char **argv) {
table *opt = arr;
printf("%s\n", (opt+HELP)->name);
printf("%s\n", (opt+OUTPUT)->name);
return 0;
}
Second solution:
struct str {
char *name;
int flag;
};
enum {
HELP,
OUTPUT,
OTHER
};
typedef struct str table;
table arr[OTHER];
void start_table() {
arr[HELP] = (struct str) { "help", HELP };
arr[OUTPUT] = (struct str) { "output", OUTPUT };
arr[OTHER] = (struct str) { NULL, OTHER };
}
int main(int argc, char **argv) {
start_table();
table *opt = arr;
printf("%s\n", (opt+HELP)->name);
printf("%s\n", (opt+OUTPUT)->name);
return 0;
}
What are the best? Second solution change automatically if I add or change any element of the array, but is efficient? Is the best enumerate or using the #define preprocessor directive?

It depends!
When initialization can be used, use it — so the first solution is often better, especially if the code never changes the structure (array) contents.
If your code can change the contents but might need to be able to reset to the original state, then the initialization function becomes more appropriate and using direct initialization is not appropriate.
There is no one 'best' solution; what is best depends on what you need to do with the array.

Using a C99 specific intializer syntax, you can get the advantages of the second approach in a static initializer:
#include <stdio.h>
struct str {
const char *name;
int flag;
};
enum {
HELP,
OUTPUT,
OTHER,
};
typedef struct str table;
table arr[] = {
[HELP] = { "help", HELP },
[OUTPUT] = { "output", OUTPUT },
[OTHER] = { NULL, OTHER },
};
int main(int argc, char **argv) {
table *opt = arr;
printf("%s\n", opt[HELP].name);
printf("%s\n", opt[OUTPUT].name);
return 0;
}
The advantage of this technique is it makes no assumption on the order of the enum values, nor on their actual values as long as they are positive, distinct and reasonably small.

Related

Some issues with "read access violation"

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
typedef struct {
char name[128], code[128];
} info;
info db[3];
info* data=db;
void find (const char *code, int size, ...) {
bool mismatch = true;
va_list arg;
va_start(arg,size);
while (size-- > 0) {
data = va_arg(arg,info*);
printf("%s", data->code);
if (!strcmp(data->code,code))
{
printf("%s [id:%s]\n",data->name,data->code), mismatch = false;
}
}
if (mismatch) printf("No data available!");
return;
}
int main (int argc, char *argv[], char *envp[]) {
const char *spec[] = {
"Physics of Elementary Particles",
"Physics of Hign Energy",
"Low-level Programming"
};
const char *code[] = {
"2396","0812", "0773"
};`enter code here`
for (int count = 0; count < 3; ++count) {
strncpy(db[count].name,spec[count],128);
strncpy(db[count].code,code[count],128);
}
find("0812",3,db[0],db[1],db[2]);
return 0;
}
After running it says "read access violation", although I hope everything is correct, it happens after function "va_arg(arg, info*)". Is it some troubles with stack or decrypting?
The problem is in the function call:
find("0812",3,db[0],db[1],db[2]);
The variadic argument that you're passing in are of type info. However, when you retrieve them with va_arg you're looking for a info *. These don't match up.
You want to pass in the address of each array member.
find("0812",3,&db[0],&db[1],&db[2]);
Also, you need to call va_end at the bottom of find before you return.

C Function pointers with parameter at declaration/ compile time

Suppose we have a list of events (int) and actions (function pointers), as in:
typedef struct action_type {
int event;
int (*func)();
} action_type;
action_type actions[] = {
{ my_event1, my_action1 },
{ my_event2, my_action2 },
{ my_event3, my_action3 },
{ my_event4, my_action1 }
}
and i want to add conditions to actually running the action as part of the table, for
better readability and
simplification of the action functions.
action_type actions[] = {
{ my_event1, exceeds(&temperature, 100) , my_action1 },
{ my_event1, between(&temperature, 50, 80), my_action2 },
...
}
is there a way to get a notation like this?
Or would I need to create something like:
action_type actions[] = {
{ my_event1, $temperature, exceeds, 100, my_action1 },
...
}
However, this approach allows only a fixed number of parameters with a fixed type. As I am writing a library and conditions could be pretty much anything, I am looking for a way to allow different variable types and different parameter counts for the condition() function.
Edit: Added additional info on the conditions possibly having different numbers and types of parameters.
I'd use an X_MACRO, ie: something like this:
#define MY_EVENT_1 1
#define MY_EVENT_2 2
#define MY_EVENT_3 3
static int my_action1(void) { printf("Over 100!\n"); return 0; }
static int my_action2(void) { printf("Over 120!\n"); return 0; }
static int my_action3(void) { printf("Over 160!\n"); return 0; }
static int exceeds(int *val, int temp) { return *val > temp; }
typedef struct action_type {
int event;
int (*func)();
} action_type;
#define X_ACTIONS \
X(MY_EVENT_1, exceeds(&temperature, 100), my_action1) \
X(MY_EVENT_2, exceeds(&temperature, 120), my_action2) \
X(MY_EVENT_3, exceeds(&temperature, 160), my_action3)
static action_type actions[] = {
#define X(type, cond, cb) { type, cb },
X_ACTIONS
#undef X
};
int main() {
int temperature = 130;
#define X(type, cond, cb) if (cond) cb();
X_ACTIONS
#undef X
return 0;
}
you can do something like this
#define __NO__FUNC NULL
typedef unsigned char (*func)(void);
typedef unsigned char (*con)(unsigned char param1, unsigned char param2, unsigned char param3);
typedef struct {
int event
func custom_func;
con condition;
} action_type;
then use like this
action_type action[] = {
{ 1,SomeFunc, SomeCondition },
{ 2,__NO__FUNC,__NO__FUNC },
};
Where some func must retun unsigned char and have input type void such as
unsigned char SomeFunc(void)
{
// some logic
return 1;
}
unsigned char SomeCondition(unsigned char param1, unsigned char param2, unsigned char param3)
{
// logic
return 1;
}
and use it like this
if (action[0].condition(1,2,3)){
action[0].custom_func();
}
you can also check if a function is set with the following example:
if (action[0].condition(1,2,3)){
if(action[0].custom_func)
action[0].custom_func();
}
Example usage all together
unsigned char SomeFunc(void)
{
// some logic
return 1;
}
unsigned char SomeCondition(unsigned char param1, unsigned char param2, unsigned char param3)
{
// logic
return 1;
}
#define __NO__FUNC NULL
typedef unsigned char (*func)(void);
typedef unsigned char (*con)(unsigned char param1, unsigned char param2, unsigned char param3);
typedef struct {
int event
func custom_func;
con condition;
} action_type;
action_type action[] = {
{ 1,SomeFunc, SomeCondition },
{ 2,__NO__FUNC,__NO__FUNC },
};
void main(void)
{
unsigned char temperature = 0;
unsigned char val = 30;
unsigned char another_val = 50;
if (action[0].condition(temperature ,val,another_val )){
action[0].custom_func();
}
}
UPDATE : I have added a second function parameter, called condition which can be used to check a output before executing custom_func()
UPDATE 2 : Added the condition function to accept variables as input
UPDATE 3 : I have added a example code of how to use it, however i like to point out that in your question you cannot have a variable number of arguments inside the declaration of those functions. The C syntax does not allow that.
An element is created inside the struct of type " typedef unsigned char (*con)(unsigned char param1, unsigned char param2, unsigned char param3);
"
Meaning that those element accepts a function that returns unsigned char and has a input of (unsigned char param1, unsigned char param2, unsigned char param3);
You cannot add functions that have different return type or different parameters.
Hope it helps!
Best regards

Is it possible to only send one variable from a struct if that struct exists as an array?

I apologise if this seems simple, I'm still learning and I'm new to C.
I have this as my struct:
struct Game{
char id;
char name[50];
char genre[20];
char platform[15];
char company[30];
float price;
int quantity = 10;
};
And this declared as a struct array:
struct Game gList[30];
I have a function where I'm passing all of 'gList' to search through values in the gList[i].name variables.
So my question is, is it possible to send only the gList[i].name part of the struct to the function as a parameter?(ie All the 30 name values only).
No.
But you could make an array of pointers that point to the name field and pass it to the function:
char* ptr[30];
for(int i = 0; i < 30; i++)
ptr[i] = gList[i].name;
func(ptr);
No you can't. However, you can pass iterators to functions just fine. Typical pattern:
struct context { struct Game *gList; int nList; int i; }
char *iter_names(void *baton)
{
struct context *ptr = baton;
if (ptr->i == ptr->nList) return NULL;
return ptr->gList[ptr->i++].name;
}
void wants_name_array(char (*nextname)(void *), void *baton)
{
while (char *name = nextname(baton))
{
printf("%s\n", name);
/* and whatever else you are doing */
}
}
/* ... */
struct context baton = { gList, 30, 0 };
wants_name_array(iter_names, baton);
Yeah it looks kinda bad. Thankfully, gcc has an extension that makes this much better.
void wants_name_array(char (*nextname)())
{
while (char *name = nextname())
{
printf("%s\n", name);
/* and whatever else you are doing */
}
}
/* ... */
{
int i = 0;
char *nextname()
{
if (i == 30) return NULL;
return gList[i++].name;
}
wants_name_array(nextname);
}
When using this particular gcc extension, never ever return nested functions. Undefined behavior.

merging of text

Can you please help me with merging of two texts into one using just only stdio.h and stdlib.h? The result should be HelloWorld.
So far, I have the following, but there is a mistake somewhere.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
char *spojeni(char *t1, char *t2)
{
char pole_spolecne[10];
for (*t1 = 0; *t1 < 5; t1++)
{
pole_spolecne[*t1] = *t1;
}
for (*t2 = 0; *t2 < 10; t2++)
{
pole_spolecne[*t2 + 5] = *t2;
}
return pole_spolecne;
}
int main()
{
char pole1[] = { "Hello" };
char pole2[] = { "World" };
printf("%s\n", spojeni(pole1, pole2));
system("pause");
return 0;
}
My new solution, but it returns an error at the end:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
char *spojeni(char *t1, char *t2)
{
char pole_cele[20];
char *p_pole_cele;
p_pole_cele = t1;
strcat(p_pole_cele, t2);
return p_pole_cele;
}
int main()
{
char pole1[] = { "Hello" };
char pole2[] = { "World" };
char *p_pole1;
char *p_pole2;
p_pole1 = pole1;
p_pole2 = pole2;
printf("%s\n)", spojeni(p_pole1, p_pole2));
system("pause");
return 0;
}
Finally, this change of function helped:
char *spojeni(char *t1, char *t2)
{
char pole_cele[20];
char *p_pole_cele;
p_pole_cele = (char *)malloc(10);
strcpy(p_pole_cele, t1);
p_pole_cele = (char *)realloc(p_pole_cele, 20);
strcat(p_pole_cele, t2);
return p_pole_cele;
}
I am not quite sure how to answer this, as this is clearly a teaching exercise, and, to be blunt, the code given shows a lack of understanding of pointers. And pointers is a topic better taught in person than via a web-site comment.
A few hints, though:
Think very clearly about pointers, what they are pointing to, and what makes them different from array indices.
Draw diagrams to visualize what you're doing.
Your exercise can be solved using calloc(), strlen() and strcpy().

Best way to pass a struct within a struct to a GSourceFunc

Which way is best to get S to a GSourceFunc? Or neither?
typedef struct{
//...
}S;
struct MS{
//..
S *St;
};
static gboolean AL_Calback(gpointer data){
S *St = (S*)user_data;
St->Something = SomethingElse;
return TRUE;
}
int main (int argc, char *argv[]){
//...
MS *MainStruct = gnew0(MS, 1);
Mainstruct->St = gnew0(S, 1);
clutter_threads_add_timeout_full(G_PRIORITY_HIGH, 100, AL_Callback, MainStruct->St, NULL);
//...
}
or like this,
typedef struct{
//...
}S;
struct MS{
//..
S St;
};
static gboolean AL_Calback(gpointer data){
MS *MV = (MS*)user_data;
MV->S.something = SomethingElse;
return TRUE;
}
int main (int argc, char *argv[]){
//...
MS *MainStruct = gnew0(MS, 1);
clutter_threads_add_timeout_full(G_PRIORITY_HIGH, 100, AL_Callback, MainStruct, NULL);
//...
}
I've tried other ways, but have not been able to make them work. clutter_add_timeout needs to take a pointer as an argument.
If you are passing the parameter to clutter_threads_add_timeout_Full via pointer, then you could just pass the address of the St member of MainStruct thus reducing the need for dynamic allocation (for the inner structure).
struct MainStruct{
//..
S St; // note: no pointer
};
// in main
MainStruct* ms = gnew0(MS, 1);
clutter_threads_add_timeout_Full(G_PRIORITY_HIGH, 100, AL_Callback, &(ms->St),
NULL);
Edit: updated code to dynamically allocate MainStruct structure to avoid possible segfault as pointed out by ptomato

Resources