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;
}
Related
I want to use a struct to contain some data and passing them between different functions in my program,this struct has to contain a dynamic 2D array (i need a matrix) the dimensions change depending on program arguments.
So this is my struct :
struct mystruct {
int **my2darray;
}
I have a function that read numbers from a file and has to assign each of them to a cell of the struct array.
I tried doing this :
FILE *fp = fopen(filename, "r");
int rows;
int columns;
struct mystruct *result = malloc(sizeof(struct mystruct));
result->my2darray = malloc(sizeof(int)*rows);
int tmp[rows][columns];
for(int i = 0;i<rows;i++) {
for(int j = 0;j<columns;j++) {
fscanf(fp, "%d", &tmp[i][j]);
}
result->my2darray[i]=malloc(sizeof(int)*columns);
memcpy(result->my2darray[i],tmp[i],sizeof(tmp[i]));
}
But this is giving me a strange result : all the rows are correctly stored except for the first.
(I'm sure that the problem is not in the scanning of file).
While if i change the fourth line of code in this :
result->my2darray = malloc(sizeof(int)*(rows+1));
it works fine.
Now my question is why this happens?
Here's an answer using some "new" features of the language: flexible array members and pointers to VLA.
First of all, please check Correctly allocating multi-dimensional arrays. You'll want a 2D array, not some look-up table.
To allocate such a true 2D array, you can utilize flexible array members:
typedef struct
{
size_t x;
size_t y;
int flex[];
} array2d_t;
It will be allocated as a true array, although "mangled" into a single dimension:
size_t x = 2;
size_t y = 3;
array2d_t* arr2d = malloc( sizeof *arr2d + sizeof(int[x][y]) );
Because the problem with flexible array members is that they can neither be VLA nor 2-dimensional. And although casting it to another integer array type is safe (in regards of aliasing and alignment), the syntax is quite evil:
int(*ptr)[y] = (int(*)[y]) arr2d->flex; // bleh!
It would be possible hide all this evil syntax behind a macro:
#define get_array(arr2d) \
_Generic( (arr2d), \
array2d_t*: (int(*)[(arr2d)->y])(arr2d)->flex )
Read as: if arr2d is a of type array2d_t* then access that pointer to get the flex member, then cast it to an array pointer of appropriate type.
Full example:
#include <stdlib.h>
#include <stdio.h>
typedef struct
{
size_t x;
size_t y;
int flex[];
} array2d_t;
#define get_array(arr2d) \
_Generic( (arr2d), \
array2d_t*: (int(*)[(arr2d)->y])(arr2d)->flex )
int main (void)
{
size_t x = 2;
size_t y = 3;
array2d_t* arr = malloc( sizeof *arr + sizeof(int[x][y]) );
arr->x = x;
arr->y = y;
for(size_t i=0; i<arr->x; i++)
{
for(size_t j=0; j<arr->y; j++)
{
get_array(arr)[i][j] = i+j;
printf("%d ", get_array(arr)[i][j]);
}
printf("\n");
}
free(arr);
return 0;
}
Advantages over pointer-to-pointer:
An actual 2D array that can be allocated/freed with a single function call, and can be passed to functions like memcpy.
For example if you have two array2d_t* pointing at allocated memory, you can copy all the contents with a single memcpy call, without needing to access individual members.
No extra clutter in the struct, just the array.
No cache misses upon array access due to the memory being segmented all over the heap.
The code above never sets rows and columns, so the code has undefined behavior from reading those values.
Assuming you set those values properly, this isn't allocating the proper amount of memory:
result->my2darray = malloc(sizeof(int)*rows);
You're actually allocating space for an array of int instead of an array of int *. If the latter is larger (and it most likely is) then you haven't allocated enough space for the array and you again invoke undefined behavior by writing past the end of allocated memory.
You can allocate the proper amount of space like this:
result->my2darray = malloc(sizeof(int *)*rows);
Or even better, as this doesn't depend on the actual type:
result->my2darray = malloc(sizeof(*result->my2darray)*rows);
Also, there's no need to create a temporary array to read values into. Just read them directly into my2darray:
for(int i = 0;i<rows;i++) {
result->my2darray[i]=malloc(sizeof(int)*columns);
for(int j = 0;j<columns;j++) {
fscanf(fp, "%d", &result->my2darray[i][j]);
}
}
In your provided code example, the variables rows and columns have not been initialized before use, so they can contain anything, but are likely to be equal to 0. Either way, as written, the results will always be unpredictable.
When a 2D array is needed in C, it is useful to encapsulate the memory allocation, and freeing of memory into functions to simplify the task, and improve readability. For example, in your code the following line will create an array of 5 pointers, each pointing to 20 int storage locations: (creating 100 index addressable int locations.)
int main(void)
{
struct mystruct result = {0};
result.my2darray = Create2D(5, 20);
if(result.my2darray)
{
// use result.my2darray
result.my2darray[0][3] = 20;// for simple example, but more likely in a read loop
// then free result.my2darray
free2D(result.my2darray, 5);
}
return 0;
}
Using the following two functions:
int ** Create2D(int c, int r)
{
int **arr;
int y;
arr = calloc(c, sizeof(int *)); //create c pointers (columns)
for(y=0;y<c;y++)
{
arr[y] = calloc(r, sizeof(int)); //create r int locations for each pointer (rows)
}
return arr;
}
void free2D(int **arr, int c)
{
int i;
if(!arr) return;
for(i=0;i<c;i++)
{
if(arr[i])
{
free(arr[i]);
arr[i] = NULL;
}
}
free(arr);
arr = NULL;
}
Keep in mind that what you have created using this technique is actually 5 different pointer locations each pointing to a set of 20 int locations. This is what facilitates the use of array like indexing, i.e. we can say result.my2darray[1][3] represents the second column, forth row element of a 5X20 array, when it is not really an array at all.
int some_array[5][20] = {0};//init all elements to zero
Is what is commonly referred to in C an int array, also allowing access to each element via indexing. In actuality (Even though commonly referred to as an array.) it is not an array. The location of elements in this variable are stored in one contiguous location in memory.
|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0... (~ 82 more)
But C maintains the locations such that they are all indexable as an 2D array.
I can sort a array of pointers to words so that they are ordered alphabetically, the problem is that I need to ALSO sort an integer array (the number of times that specific word is used) so that the integers are in the same place as their respective words:
my code:
for (i = 0; i < numWords; i++) {
// prints out the words and their frequency respectively
printf("%s - %d\n", dictionary[i], frequency[i]);
}
//sorts the dictionary so that the words are 'alphabetical'
qsort(dictionary, numWords, sizeof(char *), rstrcmp);
printf("\nafter qsort\n"); //checkmark
for (i = 0; i < numWords; i++) {
// prints the word list alphabetically, but the frequencies are no longer matched
printf("%s - %d\n", dictionary[i], frequency[i]);
}
...comparison function V
int rstrcmp(const void *p1, const void *p2) {
return strcmp(*(char * const *)p1, *(char * const *)p2);
}
A simple thing to do would be to use a struct to store word/frequency pairs and then sort an array of these structs.
For example:
struct WordFrequency
{
const char * word;
int frequency;
} wordFreqs[numWords]; // Assumes numWords is static/global and constant...
Then:
for (i = 0; i < numWords; i++) {
printf("%s - %d\n", dictionary[i], frequency[i]);
wordFreqs[i].word = dictionary[i];
wordFreqs[i].frequency = frequency[i];
}
//sorts the dictionary so that the words are 'alphabetical'
qsort(wordFreqs, numWords, sizeof(struct WordFrequency), wfcmp);
for (i = 0; i < numWords; i++) {
printf("%s - %d\n", wordFreqs[i].word, wordFreqs[i].frequency);
}
And:
int wfcmp(const void *p1, const void *p2) {
return strcmp(((const struct WordFrequency *)p1)->word, ((const struct WordFrequency *)p2)->word);
}
The standard qsort() function cannot do as you wish directly.
All else apart, how does it know (or how do you tell it) which two arrays to sort in parallel?
You either have to change the data structure (use an array of a structure type), or you have to write your own sort function. Of the two, changing the data structure is probably the easier.
There is another option — but a somewhat contorted one. You could create an array of int with entries such that:
for (int i = 0; i < N; i++)
index[i] = i;
You then pass this array to the sort function, along with a comparator that knows the base addresses of the two arrays. The qsort() function permutes the data in the array; the comparator looks at the data in the other arrays. The other two arrays have to be global (at least file scope) variables, or you need global variables that are pointers that can be initialized with the the base addresses of the two arrays.
After the sort, you can use array1[index[i]] and array2[index[i]] to access the ith element of the sorted arrays.
One other option if you're on BSD: you could use the qsort_r() function:
void qsort_r(void *base, size_t nel, size_t width, void *thunk,
int (*compar)(void *, const void *, const void *));
The 'thunk' is a pointer that's passed to the comparator as the first argument. You could use this with the index-array scheme to pass the pointers to the two arrays into the comparator, so you wouldn't need file scope variables at all. You still can't do two independent swaps, though, so you'd have to use the index-array scheme.
One approach that you might find useful for sorting parallel arrays: create an array of integers (size_ts to be strictly correct) and initialize it with the values 0 through numWords-1. Then qsort that array using a comparison function that does strcmp(dictionary[*(int *)p1], dictionary[*(int *)p2], then use the sorted array of indices to permute both dictionary and frequency at the same time (this is very easily done by copying, or a little less easily done in-place with swaps: here is an example of the latter).
Turix probably has the better solution though — using an array of structs instead of two arrays avoids the whole problem.
I have utitlity function which gives me a char buffer of individual bytes, when I provide it with a structure.
unsigned char complete[16] = { 0 };
char* construct_complete_array(socketType* m)
{
unsigned char *temp = (unsigned char*) m;
size_t j;
for (j = 0; j < sizeof(*m); j++)
{
complete[j] = *(temp);
printf("%.2x ", *(temp));
*temp++;
}
return complete;
}
int diff_bit_calc(socketType* datanode, socketType* knode)
{
char* result = construct_complete_array(datanode);
size_t j;
printf("\nPrinting result: \n");
for (j = 0; j < sizeof(*datanode); j++)
{
printf("%.2x ", *(result));
*result++;
}
}
I want it to be a generic function which when provided with a structure will return me a char buffer of the structure.
I might have another invocation like
char* result1 = construct_complete_array(knode);
(I don't think having complete[16] buffer as global a good idea. Having it local and returning it is still a worser idea. )
In general, you can't do that without dynamically allocating memory. Most people get around it by declaring the buffer in the calling function and passing that buffer to a function, which will then fill in the passed buffer.
In your specific case, I'm not so sure a function is necessary; it's rather short to do it inline, e.g.:
/* to get the bytes representing `something' into a char array */
char something_chars[sizeof(something)];
memcpy(something_chars, &something, sizeof(something));
As for as I know, there are two ways to do that.
Since the return value of the function is a pointer, so you must make sure that the memory you store result won't be destroyed. Other than using global variable, you can use dynamic allocating memory(like icktoofay said) or static keyword
(like Tay Wee Wen said).
When using dynamic allocating memory, the user of this function should remember to free() outside the function.
When using static keyword inside the block, there is a problem of overriding. If you call the function several times, only the last return value was kept.
By the way, *temp++; is a little strange, why not use temp++; instead.
Declare the array static inside the function.
char* construct_complete_array(socketType* m){
static unsigned char complete[16]= {0};
unsigned char *temp = (unsigned char*)m;
size_t j;
for (j = 0;j<sizeof(*m);j++){
complete[j] = *(temp);
printf("%.2x ", *(temp));
*temp++;
}
return complete;
}
You'd have to change your interface a bit:
char* construct_complete_array(socketType* m, char temp[]);
then on the calling side you can use a compound literal to provide temp
char* result = construct_complete_array(datanode, (char[sizeof *datanode]){ 0 });
If you have to repeat that in several places you could put that into a macro
#define CONSTRUCT_ARRAY(X) construct_complete_array((X), (char[sizeof *(X)]){ 0 })
so then again your call side looks almost as you had it before
char* result = CONSTRUCT_ARRAY(datanode);
For this to work you just have to have in mind that the value in result points to local data with the same life time as result itself.
I am trying to wrap my head about the concept of 2-dimensional arrays (of structs) in C
Say I have the following definition:
typedef struct group group;
struct group {
int members;
int neighbours;
char color;
};
#define NUM_CELLS 10
With the following function that is supposed to copy some data from a single array to a multidimensional array:
void test_mgroup_arr(group clusters[][NUM_CELLS],group tests[NUM_CELLS], int num_groups) {
int i;
int j = 0;
for (i = 0; i < num_groups; ++i)
clusters[i][j] = tests[i];
}
This is called like:
int num_groups = 5;
group clusters[NUM_CELLS][NUM_CELLS];
group tests[NUM_CELLS];
tests[0].members = 101;
tests[0].neighbours = 111;
tests[1].members = 102;
tests[1].neighbours = 112;
tests[2].members = 103;
tests[2].neighbours = 113;
tests[3].members = 104;
tests[3].neighbours = 114;
tests[4] = tests[3];
test_mgroup_arr(clusters, tests, num_groups);
I expect the code in the function to copy the 5 items from the test array to the right place in the multi-dimensional array. However, this does not work as expected, and even segfaults in some cases.
How is this not correct? What would be the right way of copying a struct from a 1dim array to a 2 dim array?
I do not see an issue in how you are passing the array or accessing it. The code actually looks right, and gives me the right results. Note:
for(i = 0; i < num_groups, ++i)
clusters[i][j] = tests[i];
Lets say the address of:
clusters[0][0] is 0x0047F7EC
clusters[1][0] is 0x0047F864
clusters[2][0] is 0x0047F8DC
sizeof(group) = 0xC * 0xA (num of groups) = 0x78
So you can see the math works out here.
j always == 0, so what's i doing?
The address of clusters+i is:
0x0047F7EC for i=0
0x0047F864 for i=1
0x0047F8DC for i=2
Exactly what you'd expect. When I get out of test_mygroup_arr I get values of clusters[0][0], clusters[1][0], clusters[2][0], clusters[3][0], clusters[4][0] are set to the values in tests[0], tests[1], tests[2], tests[3], tests[4] respectively.
That's what you were going for correct?
Did you try printing out the addresses to see what was happening? Is there more to your code that you're not showing? I'm wondering if something else is the cause of your seg fault.
I assume you're using a C99 Compiler?
Note: My test of your code that worked fine was only and exactly what you posted.
int main()
{
int num_groups = 5;
...
test_mgroup_arr(clusters, tests, num_groups);
return 0;
}
Actually to pass array as parameter you have to pass pointer on it`s first element, this is how compiler expects it, so instead of
void test_mgroup_arr(group clusters[][NUM_CELLS],group tests[NUM_CELLS], int num_groups)
use
void test_mgroup_arr(group (*)[NUM_CELLS],group tests[NUM_CELLS], int num_groups)
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;