I have an assignment for which the user will specify at run time the type of struct that they want to create.
For instance, lets say that the user inputs:
name : char[50], address: char[50] and age: int
Then my program will have to create a struct containing these 3 types of variables. Note that the user can specify as many variables as they want for the struct, only limiting them to char and int.
How should my code be in order to create a struct as specified above?
This is for c programming language only!
a variable have 3 fields:
1) type, 2) name, 3) address.
you shuold create an array of struct containing these 3, array of this struct will be what you want
your structs may look like this:
typedef enum _Type{T_INT,T_STRING}Type;
typedef struct _var{
Type type;
char* name;
union {int n; char* str;} data;
}var;
typedef struct _Struct{
int count;
var* array;
} Struct;
when you get the input, you need to build the Struct according to it.
name : char[50], address: char[50] and age: int
Struct *s = malloc(sizeof(Struct));
s->count = 3;//count of fields in the input
s->array = malloc(s->count*sizeof(var));
//you really should do it in a loop, after parsed the input...
for(i=0;i<s->count;i++){
s->array[i].name = strdup(parsedname);//"name", "address", "age"
s->array[i].type = strcmp(parsedtype,"int")?T_STRING: T_INT;
//for string you need to alloc memory for string...
if(s->array[i].type == T_STRING)
s->array[i].data.str=malloc(50 /*the size you've got*/);
//not need to alloc memory for the int
}
when you finish don't forget to free the mallocs:
for(i=0;i<s->count;i++){
free(s-array[i].name);
if(s->array[i].type == T_STRING)
free(s->array[1].data.str);
}
free(s->array);
free(s);
You'll also need a method to fill the struct and print it, and so on...
I have been wondering about this myself, because I was thinking about writing an FFI implementation for a language. (Although I suspect, based on your accepted answer, that your use case is somewhat different).
As pointed out, structs can only be generated at compile time, but this is primarily also a feature of the C language to enable type checking and so that type safety can be enforced.
At run time, you can still manipulate areas in memory as raw bytes. You just need to know the length and offset based on the individual components of the datatype you are declaring and manage these at accordingly.
I picked this up from looking at how the Ruby FFI library was implemented. The following is from their documentation:
When you call Struct.new, it allocs an “internal bytes” worth of
memory right then. When you then do a set, like struct[:member] = 3,
the bits within that struct are set right then. The inverse is also
true; x = struct[:member] does a read from the raw memory (and
translation into a ruby object), each time you access it. Memory is
“zeroed out” when it is first allocated, unless you pass in your own
Pointer or specify it to not clear memory (additional notes). If you
pass it a Pointer it basically uses that as its base instead of
allocating anything.
https://github.com/ffi/ffi/wiki/Structs#when-allocated
"only limiting them to char and int"
So you can create general datatype (struct), holding a list of nodes with name and char*, and a list of nodes with name and int.
On each new input you just fill the lists with required number of char* and int nodes.
To access the field of such data structure you'll need to traverse the list, although.
If you need efficiency, you can replace list to map (associative array). You'll need to implement it yourself as you are on C.
Related
I am trying to initialize a struct of C array in go side.
I am new to cgo. Still trying to understand the use case.
test.h
typedef struct reply {
char *name;
reply_cb callback_fn;
} reply_t;
typedef struct common {
char *name;
int count;
reply_t reply[];
} common_t;
int
init_s (common_t *service);
test.go
name := C.CString("ABCD")
defer C.free(unsafe.Pointer(name))
num := C.int(3)
r := [3]C.reply_t{{C.CString("AB"), (C.s_cb)(unsafe.Pointer(C.g_cb))},
{C.CString("BC"), (C.s_cb)(unsafe.Pointer(C.g_cb))},
{C.CString("CD"), (C.s_cb)(unsafe.Pointer(C.g_cb))}}
g := C.common_t{
name: name,
count: num,
reply : r,
}
rc := C.init_s(&g)
I am getting error on "reply: r" unknown field 'r' in struct literal of type
Any help will be appreciated. The goal is initialize and then use it values in C init_s for processing.
You cannot use a flexible array field from Go: https://go-review.googlesource.com/c/go/+/12864/.
I think the reasonong is simple: this wart of C normally requires you to perform a trick of allocating a properly-aligned memory buffer long enough to accomodate for the sizeof(struct_type) itself at the beginning of that buffer plus sizeof(array_member[0]) * array_element_count bytes. This does not map to Go's type system because in it, structs have fixed size known at compile time. If Go would not hide reply from the definition, it would refer to a zero-length field you cannot do anything useful with anyway—see #20275.
Don't be deceived by code examples where a flexible array member field is initialized with a literal: as torek pointed out, it's a GCC extension, but what is more important, it requires work on part of the compiler—that is, it analyzes the literal, understands the context it appeared in and generates a code which allocates large enough memory block to accomodate both the struct and all the members of the flexible array.
The initialization of the array in your Go code may look superficially similar but it has an important difference: it allocates a separate array which has nothing to do with the memory block of the struct it's supposed to be "put into".
What's more Go's array are different beasts than C's: in C, arrays are pointers in disguise, in Go, arrays are first-class citizens and when you assign an array or pass it to a function call, the whole array is copied by value—as opposed to "decaying into a pointer"—in C's terms.
So even if the Go compiler would not hide the reply field, assignment to it would fail.
I think you cannot directly use values of this type from Go without additional helper code written in C. For instance, to initialize values of common_t, you would write a C helper which would first allocate a memory buffer long enough and then expose to the Go code a pair of pointers: to the beginning of the buffer (of type *C.common_t), and to the first element of the array—as *C.reply_t.
If this C code is the code you own, I'd recommend to just get rid of the flexible array and maintain a pointer to a "normal" array in the reply field.
Yes, this would mean extra pointer chasing for the CPU but it will be simpler to interoperate with Go.
I'm currently having an issue with the following struct:
typedef struct __attribute__((__packed__)) rungInput{
operation inputOperation;
inputType type;
char* name;
char numeroInput;
u8 is_not;
} rungInput;
I create multiple structs like above inside a for loop, and then fill in their fields according to my program logic:
while (a < 5){
rungInput input;
(...)
Then when I'm done filling the struct's fields appropriately, I then attempt to copy the completed struct to an array as such:
rungArray[a] = input; //memcpy here instead?
And then I iterate again through my loop. I'm having a problem where my structs seem to all have their name value be the same, despite clearly having gone through different segments of code and assigning different values to that field for every loop iteration.
For example, if I have three structs with the following names: "SW1" "SW2" SW3", after I am done adding them to my array I seem to have all three structs point me to the value "SW3" instead. Does this mean I should call malloc() to allocate manually each pointer inside each struct to ensure that I do not have multiple structs that point to the same value or am I doing something else wrong?
When you write rungArray[i] = input;, you are copying the pointer that is in the input structure into the rungArray[i] structure. If you subsequently overwrite the data that the input structure is pointing at, then you also overwrite the data that the rungArray[i] structure is pointing at. Using memcpy() instead of assignment won't change this at all.
There are a variety of ways around this. The simplest is to change the structure so that you allocate a big enough array in the structure to hold the name:
enum { MAX_NAME_SIZE = 32 };
…
char name[MAX_NAME_SIZE];
…
However, if the extreme size of a name is large but the average size is small, then this may waste too much space. In that case, you continue using a char *, but you do indeed have to modify the copying process to duplicate the string with dynamically allocated memory:
rungArray[i] = input;
rungArray[i].name = strdup(input.name);
Remember to free the memory when you discard the rungArray. Yes, this code copies the pointer and then overwrites it, but it is more resilient to change because all the fields are copied, even if you add some extra (non-pointer) fields, and then the pointer fields are handled specially. If you write the assignments to each member in turn, you have to remember to track all the places where you do this (that would be a single assignment function, wouldn't it?) and add the new assignments there. With the code shown, that mostly happens automatically.
You should malloc memory for your struct and then store the pointers to the structs inside your array. You could also turn your structs into a linked list by adding a pointer to each struct that points to the next instance of your struct.
http://www.cprogramming.com/tutorial/c/lesson15.html
I am new to C but I am currently working on a project which I cannot work out how I can do what is needed.
I have 2 different struct arrays, they are completely differently defined and I am trying to do the same action as PHP's array_pop would do, i.e. remove the last element of the array structure.
I know I could create 2 separate functions, one for each structure type, but obviously is not the best idea, so am wondering whether it is possible that I can pass either structure type to the one function, and possibly a flag, and the flag determine what type of structure it should be cast to.
My structures are defined as follows
typedef struct CallLogSearchResultStruct
{
long date;
int dRowIndex;
} callLogSearchResultStruct;
typedef struct CallLogSearchDataStruct
{
char * date;
char * time;
char * bParty;
char * aParty;
float duration;
char * cleardownCause;
struct CallLogSearchOutboundStruct * outboundLegs;
} callLogSearchDataStruct;
Below is how the structures are initialised
callLogSearchData = calloc(numRows, sizeof(callLogSearchDataStruct));
callLogSearch = calloc(numRows, sizeof(callLogSearchResultStruct));
numRows being the number of structs to contain within the array.
Below is how I am using the structures
callLogSearchData[dataRow].aParty = NULL;
callLogSearchData[dataRow].bParty = NULL;
callLogSearchData[dataRow].cleardownCause = NULL;
callLogSearchData[dataRow].date = NULL;
callLogSearchData[dataRow].time = NULL;
callLogSearchData[dataRow].outboundLegs = NULL;
Apologise if this is a simple straight forward answer, I can't find anything on Google, although not entirely sure what this would be called so maybe I'm using the wrong keywords.
Thanks for any help you can provide.
What do you mean by "remove"? How are the arrays allocated?
If you have an array created by a declaration such as:
struct foo my_foos[123];
there is nothing you can do to change the fact that my_foos is 123 elements long. You can of course select to ignore some of them by having a separate size_t foo_count variable that you maintain.
Arrays in C are not generally dynamic (unlike lists/arrays in many more high-level languages). You can implement a dynamic array using malloc(), which is not too hard but it's unclear if that's what you've done.
If you're open for using external files, have a look at utarray:
It's a collection of macros stored in one header that allow what you're searching for. No need to link an additional library, just #include the file and you have what you need.
You'd have to implement a custom UT_icd providing functions to init, copy and free the elements stored in the array.
What you want is actually a linked list. It is a collection of structures each one pointing to the Nth element and to the next element in the list. That way you can easily remove any element by unlinking it in the chain. You can google for a linked list lib in C or, implement one (it's a good exercise).
Arrays in C are static memory ranges with only enough space for your elements. Nothing more. In general you can not remove one element. You can, however, use realloc function to resize an existing array.
For what you're trying to do I'd go for a linked list.
I've seen many posts for c++/java, but nothing for C. Is it possible to allocate memory for an array of type X dynamically during run time? For example, in pseudo,
switch(data_type)
case1:float, create a new array of floats to use in the rest of the program
case2:int, create new array of ints to use in the rest of the program
case3:unsigned, ....
// etc.
In my program I determine the data type from a text header file during run time, and then I need to create an appropriate array to store/manipulate data. Is there some kind of generic type in C?
EDIT: I need to dynamically create and DECIDE which array should be created.
Thanks,
csand
Assuming you calculate the total size, in bytes, required from the array, you can just allocate that much memory and assign it to the correct pointer type.
Ex:
void * data_ptr = malloc( data_sz );
then you can assign it to a pointer for whatever type you want:
int *array1 = (int *)data_ptr;
or
float *array2 = (float *)data_ptr;
NOTE: malloc allocates memory on the heap, so it will not be automatically freed. Make sure you free the memory you allocate at some point.
UPDATE
enum {
DATA_TYPE_INT,
DATA_TYPE_FLOAT,
...
};
typedef struct {
int data_type;
union {
float * float_ptr;
int * int_ptr;
...
} data_ptr;
} data;
While this might allow you to store the pointer and tell what type of pointer you should be using, it still leaves the problem of not having to branch the behavior depending on the data type. That will be difficult because the compiler has to know the data type for assignments etc.
You're going to have a hard time doing this in C because C is statically typed and has no run-time type information. Every line of C code has to know exactly what type it is dealing with.
However, C comes with a nifty and much-abused macro preprocessor that lets you (among other things) define new functions that differ only in the static type. For example:
#define FOO_FUNCTION(t) t foo_function_##t(t a, t b) { return a + b; }
FOO_FUNCTION(int)
FOO_FUNCTION(float)
This gets you 2 functions, foo_function_int and foo_function_float, which are identical other than the name and type signature. If you're not familiar with the C preprocessor, be warned it has all sorts of fun gotchas, so read up on it before embarking on rewriting chunks of your program as macros.
Without knowing what your program looks like, I don't know how feasible this approach will be for you, but often the macro preprocessor can help you pretend that you're using a language that supports generic programming.
How can I do something like that (just an example):
any_struct *my_struct = create_struct();
add_struct_member(my_struct, "a", int_member);
add_struct_member(my_struct, "b", float_member);
So that I could load and use a struct instance "from the outside" (at the address addressOfMyStruct) with the given structure here?
any_struct_instance *instance = instance(my_struct, addressOfMyStruct);
int a = instance_get_member(instance, "a");
float b = instance_get_member(instance, "b");
I would also like to be able to create struct instances dynamically this way.
I hope it's clear what I want to do. I know that C/Invoke is able to do it, but is there a separate library to do that?
Actually demonstrating the code to make this work in C is a bit too involved for an SO post. But explaining the basic concept is doable.
What you're really creating here is a templated property bag system. The one thing you'll need a lot of to keep this going is some assiociative structure like a hash table. I'd say go with std::map but you mentioned this was a C only solution. For the sake of discussion I'm just going to assume you have some sort of hashtable available.
The "create_struct" call will need to return a structure which contains a pointer to a hashtable which makes const char* to essentially a size_t. This map defines what you need in order to create a new instance of the struct.
The "insance" method will essentially create a new hashtable with equal number of members as the template hashtable. Lets throw lazy evualation out the window for a second and assume you create all members up front. The method will need to loop over the template hashtable adding a member for every entry and malloc'ing a memory chunk of the specified size.
The implementation of instance_get_member will simply do a lookup in the map by name. The signature though and usage pattern will need to change though. C does not support templates and must chose a common return type that can represent all data. In this case you'll need to chose void* since that's how the memory will need to be stored.
void* instance_get_member(any_struct_instance* inst, const char* name);
You can make this a bit better by adding an envil macro to simulate templates
#define instance_get_member2(inst, name, type) \
*((type*)instance_get_member((inst),(name)))
...
int i = instance_get_member2(pInst,"a", int);
You've gone so far defining the problem that all that's left is a bit of (slightly tricky in some parts) implementation. You just need to keep track of the information:
typedef struct {
fieldType type;
char name[NAMEMAX];
/* anything else */
} meta_struct_field;
typedef struct {
unsigned num_fields;
meta_struct_field *fields;
/* anything else */
} meta_struct;
Then create_struct() allocates memory for meta_struct and initialized it to 0, and add_struct_member() does an alloc()/realloc() on my_struct.fields and increments my_struct.num_fields. The rest follows in the same vein.
You'll also want a union in meta_struct_field to hold actual values in instances.
I did some of this a long time ago.
The way I did it was to generate code containing the struct definition, plus all routines for accessing it and then compile and link it into a DLL "on the fly", then load that DLL dynamically.