Referring to data both by name and by number in C - c

I have twenty or so integers which I want to be able to refer to by name when they're being set, but I would like to also be able refer to them by number like they were in an array, so I can print them out one by one using a for loop. Any ideas how to code this in C? Here's what I'm talking about in pseudo code:
/* a data structure to keep a count of each make of car I own */
my_cars;
/* set the counts */
my_cars.saabs = 2;
my_cars.hondas = 3;
my_cars.porsches = 0;
/* print the counts */
for(all i in my_cars) {
print my_cars[i];
}
Is this asking too much of a low level language like C?

struct car {
const char *name;
int count;
} my_cars[] = {{"Saab", 2}, {"Honda", 3}, {"Porsche", 0}};
int i;
for (i = 0; i < sizeof(my_cars) / sizeof(my_cars[0]); i++)
printf("%s: %d\n", my_cars[i].name, my_cars[i].count);

To do that you should use an array instead of standalone data fields
#include <stdio.h>
typedef enum CarType {
CART_SAAB,
CART_HONDA,
CART_PORSHE,
CART_COUNT_
} CarType;
typedef struct MyCars {
unsigned ncars[CART_COUNT_];
} MyCars;
int main(void)
{
MyCars my_cars = { 0 } ;
unsigned i;
my_cars.ncars[CART_SAAB] = 2;
my_cars.ncars[CART_HONDA] = 3;
for (i = 0; i < CART_COUNT_; ++i)
printf("%u\n", my_cars.ncars[i]);
return 0;
}

C can do anything any other language can do. This does look like homework and I bet you are expected to make something with a key. Remember, your instructor wants you to use the data structures he or she is trying to teach you. He doesn't really want the problem solved in any random way, he wants it solved applying the topics you have been discussing.
So think about a data structure containing both strings and counts, one that can be searched, and provide functions to do that. What you are likely to get here are nice, professional, simple solutions to the problem. And that's not really what your instructor wants...

enum Makes { SAAB, HONDA, PORSCHE, INVALID };
int my_cars[INVALID];
my_cars[SAAB] = 2;
my_cars[HONDAS] = 3;
my_cars[PORSCHE] = 0;

You need two data structures. An array to hold the numbers, and a map from the name to the index in the array. In C++ you'd use one of the map classes in the standard library. I don't know what's available in C but I'm sure there are map implementations available.

The low-level C way to do this would be to wrap the cars structure into a union:
// define a structure for the cars.
typedef struct
{
int saabs;
int hondas;
int porsches;
} cars;
// wrap it into a union:
typedef union
{
cars byname;
int byid[3]; // Note: Number and type must match with the cars structure.
} cars2;
int main (int argc, char **arg)
{
cars2 my_cars;
int i;
// fill out by name:
my_cars.byname.saabs = 1;
my_cars.byname.hondas = 5;
my_cars.byname.porsches = 3;
// print by index:
for (i=0; i<3; i++)
printf ("%d\n", my_cars.byid[i]);
}

Umm...based on what you've pseudo coded up there you could probably use a union. The answers others are giving seem oriented around allowing a mapping between names and numbers. If thats what you're looking for (as in, being able to print the names) then their answers will be better. However it sounds like to me you're simply looking for clarity in the code to allow you to reference things by name or number, in this case a union would be ideal I think. This is exactly the type of thing a low level language like C lets you do.
union my_cars {
struct names {
int saab;
int ford;
...
}
int[NUM_MAKES] nums;
}
You will have to be careful to ensure NUM_MAKES is in sync with the number of makes you define. Then you can do something like:
my_cars.names.saab = 20;
my_cars.nums[0] = 30;
And modify the same element.
FYI, my C is a little rusty so there may be syntax errors there, feel free to correct.
EDIT:
Ahh, I read some of the other answers using ENUMs or DEFINEs and those might actually be simpler/easier than this one...but unions are still worth knowing.

There are maybe a couple of options.
It is possible to have the same space in memory defined (and used) in two different ways. In other words, you could have a struct with the named members and reference it either as the struct or as an array depending on how you intended to address it.
Alternatively, you could do an enumerated typedef that names the locations in the array, e.g.
typedef enum {
SABS = 0,
HONDAS,
PORSCHES
} cars;
This would then allow you to refer to offsets in the array by name, e.g.
mycars[SABS] = 5;

Related

Using struct field as loop counter?

Some background to the issue
if I have a struct like
typedef struct {
idx_type type;
union {
char *str;
int num;
} val
} cust_idx;
and I have loops like this
for (i = 0; i < some_get(x); i++) {
some_fun(z, NULL, i);
}
that I want to refactor to use the struct like some_fun(z, idx) where idx is one of my cust_idx structs, would it be best to keep i as the loop counter and update idx or change the for header to use idx.val.num instead of i?
For the purposes of this, assume idx_type is an enum for string and number types, and all other fields will have macros, but I'm only going to use the IDX_NUM macro here as I'm not worried about anything to do with idx.type.
To sum up my concerns:
Will it be readable? I don't want to leave behind a mess that someone will read and just shake their head...
Is it advised against?
Which of these is the best solution?
Struct field as loop counter
#define IDX_NUM(x) (x.val.num)
...
cust_idx j;
j.type = TYPE_num;
for (IDX_NUM(j) = 0; IDX_NUM(j) < some_get(x); IDX_NUM(j)++) {
some_fun(z, j);
}
This does the same as the original, but the using struct field/macro extends and complicates the for loop header in my opinion but it's still fairly understandable.
Modify struct with original counter
cust_idx j;
j.type = TYPE_num;
for (i = 0; i < some_get(x); i++) {
IDX_NUM(j) = i;
some_fun(z, j);
}
This results in the least changes from old code logically, but will end in by far the largest amount of code due to the add assignment lines.
Pointer to struct field
cust_idx j;
int *i = &(j.val.num);
j.type = TYPE_num;
for ((*i) = 0; (*i) < some_get(x); (*i)++) {
some_fun(z, j);
}
I'm not sure how good this would be in the long run, or if it's advised against.
As to readability, I would always prefer separate loop counters.
EDIT: The following in italic is not right in this specific case as C structs by default are passed as value copies over the stack, so passing j to some_fun() in the loop is ok. But I'll leave the caveat here, as it applies to many similar situations, where the struct or array is passed by a pointer value. (aka 'passed by reference').
That is especially true in code like you posted, where you call a function with the structure as an argument inside the loop.
If I don't know what some_fun() does, I can only hope that the struct's member that I use as a loop counter is not modified. And hope is not a strategy.
So, unless there are very hard reasons for doing otherwise, I'd always place readability first. Remember: If you write code that is at the limits of your own syntactic and semantic capabilities, you will have very little fun debugging such code, as debugging is an order of magnitude harder than writing (buggy) code. ;)
Addition: You could look at the disassemblies of all variants. The compiler might do a lot of optimizations here, especially if it can 'see' some_fun().

Avoiding memset for a multi-type structure

I would like to avoid using memset() on a structure like this:
typedef struct {
int size;
float param1;
} StructA;
typedef struct {
StructA a;
unsigned int state;
float param2;
} Object;
Can I do something like this (pseudo code, I can't check right now)?
Object obj;
int *adr = (int*)&obj;
for (int i; i < sizeof(obj); i++) {
*adr++ = 0;
}
Will it set every member of obj to zero?
EDIT: to answer questions on comments.
I have been working on some cases (with uni-type structures), where memset is twice as slow than initializing by hand. So I will consider trying initializing multi-type structure as well.
Avoiding memcpy() would be nice too (avoiding the <string.h> lib).
The universal zero initializer initializes everything (recursively) to zero of the proper type.
Object object = {0};
You can create a "zero" object, then copy it to other objects of the same type. Maybe it's faster than memset(), I haven't tested efficiency.
const Object zeroobject = {0};
/* ... */
Object obj;
memcpy(&obj, &zeroobject, sizeof obj);
/* assignment may work too */
obj = zeroobject;
memset initializes the structure to all bits zero. This would initialize the integers and the floats to 0 on IEEE compliant architectures but the C Standard does not guarantee it. On an exotic system, this might not initialize param1 or param2 to 0.0.
If the hand coded initialization is faster, use that, or use a static initializer:
Object obj = { 0 };
No.
I would prefer to use memset:
memset(&obj, 0, sizeof(obj));
Or if you want it to do your way:
char* adr = (char*)&obj;
for(int i = 0; i < sizeof(obj); i++)
{
*adr++ = 0;
}
You should be using memset, unless it's very hard to do. Like it doesn't exist in your environment and you can't add an equivalent. It's fast, checks all the right edge cases and is essentially bug-free.
That is close enough to working actually.
But sizeof produces the size in bytes. You should switch the int to char.
Since all elements involved are of a size which is a multiple of four, you could do something like this, and still get the same result.
int* adr = (int*)&obj;
for (int i = 0; i < sizeof(obj); i+=4) {*adr = 0; adr += 4;}
Baring any padding the compiler might insert between the fields, for example. It might put each field on a 8 byte / 64 bits region, so access to it is faster.

C Programming - Non static initialization of a flexible array member

I think my english is just to bad to understand the other articles about this. But anyway:
I just thought i could write a program (in C), that can store a set of cards.
Not complicated, just store values and names of cards and print them out.
I'm a beginner in C, and because i'm in the section "Strings in Structures" in my Book, i wanted to try out structures on my own. This is my Code so far:
#include <stdio.h>
struct card
{
int value;
char name[];
};
int main(void)
{
const struct card heart[13] = { {2,"two"}, {3,"three"}, {4,"four"}, {5,"five"}, {6,"six"}, {7,"seven"}, {8,"eight"}, {9,"nine"}, {10,"ten"}, {11,"jack"}, {12,"queen"}, {13,"king"}, {14,"ace"} };
int i;
for (i = 0; i < 13; ++i)
{
printf("The card heart-%s has the value of %i", heart[i].name, heart[i].value);
}
return 0;
}
I just wanted to test if it works, so i just wrote the heart-cards in the code. If i want to compile this file, my compiler (gcc/mingw) hits me with 26 errors. It says:
"(near initialization of heart[0])"
"non static initialization of a flexible array member"
I don't really understand this. In the book, everything works as expected. I tried to rebuild the code in the book and changing the names, but it doesn't work. I think it's a problem with the strings, because if i use integers only, everything works.
In already read in another post, that every string should be allocated manually, and there was a code example, but i don't know what all the lines should mean, and i want understand what my code does, so i don't copy + paste.
Could you explain me why this doesn't work?
PS: I am writing currently in windows, so please don't use bash commands to explain or something like that.
I am also german and my english is not the "yellow of the egg", try to explain without using complex 'sentence builds' (i hope you know what i mean :D) and unusual words.
Thanks for all help!
You need to create some space for the name of each card. Easiest way to do this would be to change your struct card definition to something like:
struct card
{
int value;
char name[16]; // doesn't have to be 16, but make sure it's large enough to hold each card name plus a '\0' terminator
};
The prior answers suggest allocating a fixed length for your names. This has limitations and even dangers. It is always a good idea to avoid it all together.
e.g. You want to alter the name during the game, e.g. "Ace (Trump Card)" but that might be both too long even worse overwrite memory. (Many of the known vulnarabilities in code are caused by buffer overruns)
You are also building in a limitation; What if your game needs translating into another language?
By using pointers, you don't need to resort to either variable length structures or fixed string lengths.
You also add the ability to add API access functions that set data, allowing checks before it's written, preventing buffer overruns.
Instead of using character array (aka strings) you should use pointers in your structures. If you follow the link at the bottom I take this further and use pointers to the structures themselves.
As the pointer storage size never changes your names can be of any length and even altered later, perhaps as the game progresses.
Your card could look something like
typedef struct card
{
int value;
char * name;
}
Now the initial assignment can be done like this
card_t card_ace = {14, "Ace"};
And the values are not fixed (unless that is what you want, then you make them const).
card_ace.value = 200;
card_ace.name = "Trump card";
or an array of cards like this
card_t suit_hearts[] = {{2,"two"}, {3,"three"}, {4,"four"}, {5,"five"}, {6,"six"}, {7,"seven"}, {8,"eight"}, {9,"nine"}, {10,"ten"}, {11,"jack"}, {12,"queen"}, {13,"king"}, {14,"ace"}}
Even better make the whole thing using pointers
typedef card_t * cards_t;
cards_t mysuit = &(card_t){2,"two"}, &(card_t){3,"three"}, ...
Perhaps consider makeing the suit a structure.
typedef struct
{
char * name;
card_t ** cards;
} suit_t;
typedef card_t * cards_t[];
suit_t mysuit = {
.name = "Hearts",
.cards = (cards_t){&(card_t){2,"two"}, &(card_t){3,"three"},....}
}
* For a fully working example of the latter, demonstrating using arrays of pointers to sidestep the limitations of variable length members of fixed arrays, see this gist on github

Is it possible to create an array of names of variables?

I have a table of variables.
int var1;
int var2;
int var3;
I would like to access values of those variables either explicitly by name, like var1 = 3; or as an array (in a for loop):
for (i = 0; i < sizeof(vars_array) / sizeof(int); i++)
{
vars_array[i] = nnn;
}
How can I achieve this?
You cannot use:
for (i = 0; i < sizeof(vars_array); i++)
{
vars_array[i] = nnn;
}
However, if you are willing to store an array of pointers, you can use:
int* vars_array[] = {&var1, &var2, &var3};
for (i = 0; i < sizeof(vars_array)/sizeof(vars_array[0]); i++)
{
*vars_array[i] = nnn;
}
No, you can't do this. (Note: you might be able to pull it off with some sort of horrid memory map, don't do it). You generally want to avoid dynamically referencing variables by name even if the language allows it. It makes understanding the code very difficult. What you want instead is an array or hash table to store and retrieve data in pairs.
If the variables are simply numbered var1, var2, var3... then instead of using individual variables, put the values in an array.
int vars[] = { 23, 42, 99 };
for( int i = 0; i < 3; i++ ) {
printf("vars%d: %d\n", i, vars[i]);
}
If the variable names are not numbers, or the numbers are not contiguous, then the general idea is to use a hash table. This is like an array, but instead of using numbers of the index it uses strings. Lookup is fast, but it inherently has no order.
C doesn't have hashes built in, so you'll have to use a library like Gnome Lib.
#include <glib.h>
#include <stdio.h>
int main() {
/* Init a hash table to take strings for keys */
GHashTable *vars = g_hash_table_new(g_str_hash, g_str_equal);
/* For maximum flexibility, GHashTable expects the keys and
values to be void pointers, but you can safely store
integers by casting them */
g_hash_table_insert(vars, "this", (gpointer)23);
g_hash_table_insert(vars, "that", (gpointer)42);
g_hash_table_insert(vars, "whatever", (gpointer)99);
/* And casting the "pointer" back to an integer */
printf("'this' is %d\n", (int)g_hash_table_lookup(vars, "this"));
g_hash_table_unref(vars);
return 0;
}
Here's a good tutorial on using Gnome Lib.
Of course you can. You would need a union:
union {
struct {
int var1, var2, var3;
};
int vars_array[3];
}name;
Although this way you should prefix your variable instances with 'name.'. You can't omit it and export the identifiers in the enclosing space (as unnamed structure and union members) for some reason.
Your code for accessing array elements (which directly map to your variables - eventually?) should look like this:
for (i = 0; i < sizeof(name.vars_array) / sizeof(int); i++)
{
name.vars_array[i] = nnn;
}

Allocating pointers inside an array of structs

OK, so the problem is basically like the title. Couldn't find a question that got all bits of it, so I figured I'd ask.
Say I want an array of structs shaped like the following
typedef struct s_woo{
char** n;
char* x;
} t_woo;
So I believe I should do
t_woo* woos = malloc(num_woos * sizeof(*woos));
Seems simple enough (and should deter people from yelling at me for my habit of casting malloc).
Then I want to initialize the things in each of those structs.
So intuitively I do:
for(i = 0; i < num_woos; i++){
num_ns = randomint1 / randomint2; //let's say num_ns is big, like 250-ish, average, and changes every round of the loop
woos[i].n = malloc(num_ns * sizeof(char*));
woos[i].x = malloc(num_ns * sizeof(char));
for(j = 0; j < num_ns; j++){
woos[i].n[j] = malloc(16 * sizeof(char)); // I just want 16 characters per char*
}
}
This is the boiled down version of what I have in my code. I want to know what can possibly go wrong with what I've written - like any possible thing. I'm not looking for anything in particular, just general problems with the above, like memory/heap issues, pointer mistakes etc.
Leave out "Virtual Memory Exhausted". My code error checks for that using a wrapper function on malloc, so I'm very sure that's not it.
Even better:
static const size_t woo_n_size = 16;
/* To make sure you use 16 everywhere,
* also easier to change it
*/
struct woo_item {
char n[woo_n_size];
char x;
};
struct s_woo {
struct woo_item *items;
size_t size; / * optinal, to keep track of item count */
}
With the woo_item struct you can make sure there is no x without n[woo_n_size] allocated, and vice versa.
You can remember the count of woo_items by having a designated null element to close each of your lists, or just store a size member in s_woo

Resources