I have an assignment to do for my Data Structures class and I'm in a little bit of trouble. I have some structures, namely:
typedef struct {
char *materie;
int ore_curs;
int ore_lab;
int credit;
int teme;
} TMaterie;
typedef struct {
char *nume;
float medie;
char grupa[6]; // 324CB + NULL
int varsta;
} TStudent;
typedef struct {
void *key;
void *value;
int frequency;
} Pair;
typedef struct celulag {
void *info;
struct celulag *urm;
} TCelulaG, *TLG, **ALG;
The last one is a generic list structure that will accept in the info any kind of structure. The thing is that I need to convert it to the structure pair so that it will point out to a key (that will be either a char or an int) and a value (that will be of the type TMaterie or TStudent). I need to make functions that allocate that accordingly and I have managed to do this:
TLG aloca_string_materie(char *key, TMaterie value){
TLG cel = (TLG) malloc(sizeof(TCelulaG));
if(!cel)
return NULL;
cel->info = (Pair*)malloc(sizeof(Pair));
if( !cel->info){
free(cel);
return NULL;
}
cel->urm = NULL;
((Pair*)cel->info)->value = (TMaterie*)malloc(sizeof(TMaterie));
((Pair*)cel->info)->key = (char*)malloc(50*sizeof(char));
((Pair*)cel->info)->frequency = 0;
((Pair*)cel->info)->key = key;
((TMaterie*)(Pair*)cel->info)->materie = value.materie;
((TMaterie*)(Pair*)cel->info)->ore_curs = value.ore_curs;
((TMaterie*)(Pair*)cel->info)->ore_lab = value.ore_lab;
((TMaterie*)(Pair*)cel->info)->credit = value.credit;
((TMaterie*)(Pair*)cel->info)->teme = value.teme;
return cel;
}
The problem that I am facing is that when I try to print out the key, namely
(((Pair*)cel->info)->key)
it gives me the same value as
((TMaterie*)(Pair*)cel->info)->materie
and I have no idea why.
Can someone please tell me what I'm doing wrong?
You have two main problems
((Pair*)cel->info)->value = (TMaterie*)malloc(sizeof(TMaterie));
[...]
((TMaterie*)(Pair*)cel->info)->materie = value.materie;
TMaterie member into Cel->info is value, so
((TMaterie*)(Pair*)cel->info)->materie
must be
((TMaterie*)((Pair*)cel->info)->value)->materie
Moreover using
((Pair*)cel->info)->key = (char*)malloc(50*sizeof(char));
[...]
((Pair*)cel->info)->key = key;
You are overwriting memory mallocated for key.
If, as I guess, key is a string, just use strcpy
((Pair*)cel->info)->key = (char*)malloc(50*sizeof(char));
[...]
strcpy(((Pair*)cel->info)->key, key);
The problem is you are overwriting the pointer value instead of writing to the buffer it points to. You are doing the following:
((Pair*)cel->info)->key = malloc(...);
((Pair*)cel->info)->key = key;
In the second line you asign the pointer whatever is passed in the key argument, so you are not using the memory you have allocated above and it is being leaked.
What you probably want is to copy the contents pointed by the key argument, you can use the strcpy function. Do something like:
((Pair*)cel->info)->key = malloc(...);
strcpy(((Pair*)cel->info)->key, key);
Related
I have a problem in adding an element (a struct) in a dynamic array which is in a struct.
Here the main struct
struct testfw_t
{
char* program;
int timeout;
char *logfile;
char *cmd;
bool silent;
bool verbose;
struct testTab *tests;
};
Here the array
struct testTab
{
int size;
struct test_t *oneTest;
};
and at last the element to add:
struct test_t
{
char *suite; /**< suite name */
char *name; /**< test name */
testfw_func_t func; /**< test function */
};
So I have to add a struct test_t in the array testTab in the struct testfw_t and I am lost in a lot of malloc and realloc calls.
PS : The init of the main struct if it can be useful which works:
struct testfw_t *testfw_init(char *program, int timeout, char *logfile, char *cmd, bool silent, bool verbose){
struct testfw_t *t;
t = malloc(sizeof(struct testfw_t));
t->program = program;
t->timeout = timeout;
t->logfile = logfile;
t->cmd = cmd;
t->silent = silent;
t->verbose = verbose;
t->tests = malloc(sizeof(struct testTab));
t->tests->size=0;
t->tests->oneTest=NULL;
return t;
}
EDIT : What I am trying
struct test_t *nouveau;
nouveau->suite = suite;
nouveau->name = name;
nouveau->func=func;
//fw->tests=realloc(fw->tests->oneTest,(fw->tests->size+1) * sizeof(struct testTab));
fw->tests->oneTest=malloc((fw->tests->size+1) * sizeof(nouveau));
fw->tests->oneTest[fw->tests->size+1] = *nouveau;
fw->tests->size++;
return nouveau;
In your code, nouveau doesn't point anywhere when you access it with ->. That's undefined behaviour.
Instead, just make the array larger with realloc and then assign to the last element:
// make array larger by one
fw->tests->oneTest = realloc(fw->tests->oneTest,
(fw->tests->size + 1) * sizeof(struct testTab));
// to do: test success
// assign values to new slot
fw->tests->oneTest[fw->tests->size]->suite = strdup(suite);
fw->tests->oneTest[fw->tests->size]->name = strdup(name);
fw->tests->oneTest[fw->tests->size]->func = func;
// increase the array size
fw->tests->size++;
This is allocation code that cannot recover old data after allocation failure. The only useful thing to do on failure is to exit with an error. Jonathan Leffler points out that this can be avoided by allocating to a temporary pointer first and recover the old data when allocation fails. (Of course, you still have to decide what to do in such cases.)
I've used the (non-standard, but widely available) function strdup here to copy the strings' contents. Your variant works if the strings are guaranteed to "live" as long as your structure and are different or if the are literals, but usually it is better to store copies.
I'm pretty bad at remembering C rules with structs. Basically, I have a struct like this:
typedef struct {
char* ptr;
int size;
} Xalloc_struct;
Where the char* ptr will only be one character max.
In my program, I have to allocate and free memory to a fake disk (declared globally as char disk[100];) using my own functions:
char disk[100];
void disk_init() {
for(int i = 0; i < 100; ++i) {
disk[i] = memory[i] = 0;
}
}
struct Xalloc_struct* Xalloc(int size) {
// error checking
// ...
// run an algorithm to get a char* ptr back to a part of the global disk
// array, where index i is the index where content at disk[i] starts
char* ptr = &disk[i];
struct Xalloc_struct *ret = malloc(sizeof(struct Xalloc_struct));
ret->size = size;
ret->ptr = malloc(sizeof(char));
ret->ptr = ptr;
return ret;
}
int Xfree(void* ptr) {
struct Xalloc_struct* p = (struct Xalloc_struct*) ptr;
int size = p->size;
int index = *(p->ptr);
// .. more stuff here that uses the index of where p->ptr points to
free(p->ptr);
free(p);
return 0;
}
int main() {
disk_init();
struct Xalloc_struct* x = Xalloc(5);
Xfree(x);
return 0;
}
When this compiles I get quite a few errors:
error: invalid application of ‘sizeof’ to incomplete type ‘struct Xalloc_struct’
struct Xalloc_struct *ret = malloc(sizeof(struct Xalloc_struct));
^
error: dereferencing pointer to incomplete type
ret->size = size;
^
error: dereferencing pointer to incomplete type
free(x->ptr);
^
error: dereferencing pointer to incomplete type
int size = cast_ptr->size;
^
error: dereferencing pointer to incomplete type
int free_ptr = *(cast_ptr->ptr);
^
So, how should I be allocating and deallocating these structs? And how can I modify / edit what they contain?
First problem is Xalloc_struct is a type, not the name of a struct. You declared that type with this:
typedef struct {
char* ptr;
int size;
} Xalloc_struct;
typedef is of the form typedef <type name or struct definition> <name of the type>. So you declared the type Xalloc_struct to be struct { char *ptr; int size; }.
That means you use it like any other type name: Xalloc_struct somevar = ...;.
Had you declared the struct with a name...
struct Xalloc_struct {
char* ptr;
int size;
};
Then it would be struct Xalloc_struct somevar = ...; as you have.
The rule of thumb when allocating memory for an array (and a char * is an array of characters) is you allocate sizeof(type) * number_of_items. Character arrays are terminated with a null byte, so for them you need one more character.
Xalloc_struct *ret = malloc(sizeof(Xalloc_struct));
ret->ptr = malloc(sizeof(char) * num_characters+1);
But if you're only storing one character, there's no need for an array of characters. Just store one character.
typedef struct {
char letter;
int size;
} Xalloc_struct;
Xalloc_struct *ret = malloc(sizeof(Xalloc_struct));
ret->letter = 'q'; /* or whatever */
But what I think you're really doing is storing a pointer to a spot in the disk array. In that case, you don't malloc at all. You just store the pointer like any other pointer.
typedef struct {
char* ptr;
int size;
} Xalloc_struct;
Xalloc_struct *ret = malloc(sizeof(Xalloc_struct));
ret->ptr = &disk[i];
Then you can read that character with ret->ptr[0].
Since you didn't allocate ret->ptr do not free it! That will cause a crash because disk is in stack memory and cannot be free'd. If it were in heap memory (ie. malloc) it would probably also crash because it would try to free in the middle of an allocated block.
void Xalloc_destroy(Xalloc_struct *xa) {
free(xa);
}
Here's how I'd do it.
#include <stdio.h>
#include <stdlib.h>
char disk[100] = {0};
typedef struct {
char *ptr;
int idx;
} Disk_Handle_T;
static Disk_Handle_T* Disk_Handle_New(char *disk, int idx) {
Disk_Handle_T *dh = malloc(sizeof(Disk_Handle_T));
dh->idx = idx;
dh->ptr = &disk[idx];
return dh;
}
static void Disk_Handle_Destroy( Disk_Handle_T *dh ) {
free(dh);
}
int main() {
Disk_Handle_T *dh = Disk_Handle_New(disk, 1);
printf("%c\n", dh->ptr[0]); /* null */
disk[1] = 'c';
printf("%c\n", dh->ptr[0]); /* c */
Disk_Handle_Destroy(dh);
}
What you are attempting to accomplish is a bit bewildering, but from a syntax standpoint, your primary problems are treating a typedef as if it were a formal struct declaration, not providing index information to your Xalloc function, and allocating ret->ptr where you already have a pointer and storage in disk.
First, an aside, when you are specifying a pointer, the dereference operator '*' goes with the variable, not with the type. e.g.
Xalloc_struct *Xalloc (...)
not
Xalloc_struct* Xalloc (...)
Why? To avoid the improper appearance of declaring something with a pointer type, (where there is no pointer type just type) e.g.:
int* a, b, c;
b and c above are most certainly NOT pointer types, but by attaching the '*' to the type it appears as if you are trying to declare variables of int* (which is incorrect).
int *a, b, c;
makes it much more clear you intend to declare a pointer to type int in a and two integers b and c.
Next, in Xfree, you can, but generally do not want to, assign a pointer type as an int (storage size issues, etc.) (e.g. int index = *(p->ptr);) If you need a reference to a pointer, use a pointer. If you want the address of the pointer itself, make sure you are using a type large enough for the pointer size on your hardware.
Why are you allocating storage for ret->ptr = malloc(sizeof(char));? You already have storage in char disk[100]; You get no benefit from the allocation. Just assign the address of the element in disk to ptr (a pointer can hold a pointer without further allocation) You only need to allocate storage for ret->ptr if you intend to use the memory you allocate, such as copying a string or multiple character to the block of memory allocated to ret->ptr. ret->ptr can store the address of an element in data without further allocation. (it's unclear exactly what you intend here)
You are free to use a typedef, in fact it is good practice, but when you specify a typedef as you have, it is not equivalent to, and cannot be used, as a named struct. That is where your incomplete type issue arises.
All in all, it looks like you were trying to do something similar to the following:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char* ptr;
int size;
} Xalloc_struct;
char disk[100] = "";
Xalloc_struct *Xalloc (int size, int i) {
char *ptr = &disk[i];
Xalloc_struct *ret = malloc (sizeof *ret);
ret->size = size;
// ret->ptr = malloc (sizeof *(ret->ptr)); /* you have a pointer */
ret->ptr = ptr;
return ret;
}
int Xfree (void *ptr) {
Xalloc_struct *p = (Xalloc_struct *) ptr;
// int size = p->size; /* unused */
// int index = *(p->ptr); /* what is this ?? */
// .. more stuff here that uses the index of where p->ptr points to
// free (p->ptr);
free (p);
return 0;
}
int main (void) {
int i = 0;
Xalloc_struct *x = Xalloc (5, i++);
Xfree(x);
return 0;
}
Look at the difference in how the typedef is used and let me know if you have any questions.
I've just started out with C and I'm struggling to get to grips when mixing pointers and arrays.
I am getting the following error:
error C2106: '=' : left operand must be l-value
#include <stdio.h>
struct PersonDetails {
char *name;
int *phoneNumber;
};
int* getPhoneNumber(struct PersonDetails *phoneBook[], char* name);
int main() {
struct PersonDetails a;
struct PersonDetails b;
struct PersonDetails people[2];
struct PersonDetails *ptr[2];
char aName = 'T';
int aNum = 123;
char bName = 'O';
int bNum = 456;
a.name = &aName;
a.phoneNumber = &aNum;
b.name = &bName;
b.phoneNumber = &bNum;
people[0] = a;
people[1] = b;
ptr = &people;
printf("%d", *getPhoneNumber(ptr, aName));
return 0;
}
int* getPhoneNumber(struct PersonDetails *phoneBook[], char* name) {
int i;
for (i = 0; i < 2; i++) {
if (*phoneBook[i]->name == *name) return phoneBook[i]->phoneNumber;
}
return 0;
}
It's happening on the line:
ptr = &people;
Edited Code:
#include <stdio.h>
struct PersonDetails {
char *name;
int *phoneNumber;
};
int* getPhoneNumber(struct PersonDetails *phoneBook[], char* name);
int main() {
struct PersonDetails a;
struct PersonDetails b;
struct PersonDetails people[2];
struct PersonDetails *ptr;
char aName = 'T';
int aNum = 123;
char bName = 'O';
int bNum = 456;
a.name = &aName;
a.phoneNumber = &aNum;
b.name = &bName;
b.phoneNumber = &bNum;
people[0] = a;
people[1] = b;
ptr = people;
printf("%d", *getPhoneNumber(ptr, aName));
return 0;
}
int* getPhoneNumber(struct PersonDetails *phoneBook, char* name) {
int i;
for (i = 0; i < 2; i++) {
if (*phoneBook[i].name == *name) return phoneBook[i].phoneNumber;
}
return 0;
}
Transferring sundry comments of mine in dialogue with the OP into an answer
Because the method getPhoneNumber() requires the parameter struct PersonDetails *phoneBook[].
Why does getPhoneNumber() require that eccentric type? There must be a reason why you chose to use it (like "the teacher set that in the question I'm working on"). Otherwise, it seems more likely that the parameter should be either struct PersonDetail *who or struct PersonDetail who[] — which, in the context of a function's parameter list (and only in the context of a function's parameter list) amounts to the same thing.
Originally it was PersonDetails *phoneBook, but I didn't think that would work? Am I wrong in thinking that, and how would I go about using that to find a number using a name?
Assuming you mean struct PersonDetails *phoneBook (there isn't a type PersonDetails in your code, but there is the type struct PersonDetails), then that would work fine. It is a pointer parameter that can either point to a single person's details, or to the start of an array of people's details. Inside the function, as long as you know that the array is big enough, you can use phoneBook[i].name or phoneBook[i].number with care. (Or, indeed, phoneBook->name and phoneBook->number, which refer to the single element pointed at by phoneBook, or you can think of it as using an effective subscript of 0.)
Oh wow, thank you, that helps so much. So I would change ptr to just struct PersonDetails *ptr; as opposed to an array of pointers?
Yes — using struct PersonDetails *ptr; is all you need. You are (accidentally) delving into more complex structures which do have a place in more complex situations, which is why no-one could say "this is wrong", but they're currently beyond what you need, or what you currently understand. That's OK; what you've just learned probably covers 95% or more of real life use cases.
Okay, it all compiles now, but crashes when executed. I have a feeling it has something to do with how I'm assigning both ptr and people. Do I just delete the people array? I've added an edited section in the question if you could have a look for me please?
You are now passing a char value, aName, where the function expects a char *, which would be &aName. The function prototype at the top also doesn't match the function definition; the definition is correct. You need to remove either the * or the [] but not both from the prototype. With that, it 'works'.
Be aware that you don't have strings (the char * values do not point to null terminated arrays of characters) so you can't do string comparison (strcmp()), but fixing that is probably the next phase of development.
Your compiler should have been generating warnings; pay heed. Remember, it knows a lot more about C than you do at the moment!
Working code
#include <stdio.h>
struct PersonDetails
{
char *name;
int *phoneNumber;
};
int *getPhoneNumber(struct PersonDetails *phoneBook, char *name);
int main(void)
{
struct PersonDetails a;
struct PersonDetails b;
struct PersonDetails people[2];
struct PersonDetails *ptr;
char aName = 'T';
int aNum = 123;
char bName = 'O';
int bNum = 456;
a.name = &aName;
a.phoneNumber = &aNum;
b.name = &bName;
b.phoneNumber = &bNum;
people[0] = a;
people[1] = b;
ptr = people;
printf("%d\n", *getPhoneNumber(ptr, &aName));
return 0;
}
int *getPhoneNumber(struct PersonDetails *phoneBook, char *name)
{
int i;
for (i = 0; i < 2; i++)
{
if (*phoneBook[i].name == *name)
return phoneBook[i].phoneNumber;
}
return 0;
}
Note that printing the result directly as shown will fail horribly (usually) if the 'name' is not found. You'll be dereferencing a null pointer, which invokes undefined behaviour — A Bad Thing™! You really need to use:
int *p_number = getPhoneNumber(ptr, &name);
if (p_number == NULL)
printf("No entry for name %c\n", name);
else
printf("Number for %c is %d\n", name, *p_number);
You should also review why you have int *number; instead of just int number; or char *number;. The former is better if you simply store an unformatted integer; the latter is better if you might need to store +44 1395 276679 or something like that, though you should then consider the relative merits of char number[MAX_PHONE_NUMBER_STRING_LEN]; instead of a pointer.
Also, for more nearly general-purpose code, your function should probably be told how many entries there are in the phone-book, rather than using a hard-wired size of 2 (which is a pretty minimal phone-book by any standard):
int *getPhoneNumber(int n_entries, struct PersonDetails *phoneBook, char *name)
{
int i;
for (i = 0; i < n_entries; i++)
{
if (*phoneBook[i].name == *name)
return phoneBook[i].phoneNumber;
}
return 0;
}
Where the number of entries in the array is a parameter. Assuming you have C99 or C11, you could also sensibly write that as:
int *getPhoneNumber(int n_entries, struct PersonDetails phoneBook[n_entries], char *name)
{
for (int i = 0; i < n_entries; i++)
{
if (*phoneBook[i].name == *name)
return phoneBook[i].phoneNumber;
}
return 0;
}
In both these last samples, I've not changed the data types in the structure (even though I think they should be changed). I've also not added const qualifiers to the pointer/array or the name, even though both could legitimately be const-qualified.
struct PersonDetails *ptr[2];
ptr is an array of pointers and array itself is never a modifiable value. lvalue should be some location where you store values(like variable). So this is an error.
You define as follows -
struct PersonDetails people[2];
struct PersonDetails *ptr[2];
which means the people is a 2-element array of structs of type PersonDetails, while ptr is a 2-element array of pointers to such structs.
You can't override the address of an array, it's not just some pointer (although there are some mutual semantics), it's allocated on the stack.
If you meant each element in ptr to point to the respective people element, use a loop:
for (i = 0; i < 2; ++i)
ptr[i] = &people[i];
Also note that one of the effects of passing around all these pointers to simple variables defined in main, is that you can return a null pointer from getPhoneNumber, and pass it to printf - that would segfault
ptr is an array of pointers to struct PersonDetails, so ptr[0] and ptr[1]
are pointers to struct PersonDetails, then you can asign the address of a variable of the type struct PersonDetails to each element of ptr.
in C an array is something like a pointer (but it's not exactly the same) which points to a part of the
memory (with the size of the type of variables times the numbers of elements of the array) where you can store one or more variables of one type, so in
your example, you could see people like a pointer to struct PersonDetails, and ptr like a pointer to a pointer to struct PersonDetails.
So, with all that said, what you can do is ptr[0] = people or ptr[1] = people.
So I'm trying to learn C right now, and I have some basic struct questions I'd like to clear up:
Basically, everything centers around this snippet of code:
#include <stdio.h>
#include <stdlib.h>
#define MAX_NAME_LEN 127
typedef struct {
char name[MAX_NAME_LEN + 1];
unsigned long sid;
} Student;
/* return the name of student s */
const char* getName (const Student* s) { // the parameter 's' is a pointer to a Student struct
return s->name; // returns the 'name' member of a Student struct
}
/* set the name of student s
If name is too long, cut off characters after the maximum number of characters allowed.
*/
void setName(Student* s, const char* name) { // 's' is a pointer to a Student struct | 'name' is a pointer to the first element of a char array (repres. a string)
char temp;
int i;
for (i = 0, temp = &name; temp != '\0'; temp++, i++) {
*((s->name) + i) = temp;
}
/* return the SID of student s */
unsigned long getStudentID(const Student* s) { // 's' is a pointer to a Student struct
return s->sid;
}
/* set the SID of student s */
void setStudentID(Student* s, unsigned long sid) { // 's' is a pointer to a Student struct | 'sid' is a 'long' representing the desired SID
s->sid = sid;
}
I've commented up the code in an attempt to solidify my understanding of pointers; I hope they're all accurate.
Also, I have another method,
Student* makeAndrew(void) {
Student s;
setName(&s, "Andrew");
setStudentID(&s, 12345678);
return &s;
}
which I'm sure is wrong in some way... I also think my setName is implemented incorrectly.
Any pointers? (no pun intended)
This is very wrong. If you insist on not using strcpy do something like this (not tested)
int iStringLength = strlen(name);
for (i = 0; i < iStringLength; i++) {
s->name[i] = name[i];
}
but make sure that the length is not longer than your array size.
This is also wrong
Student* makeAndrew(void) {
Student s;
setName(&s, "Andrew");
setStudentID(&s, 12345678);
return &s;
}
because the s object is destroyed when the function exits - it is local to the function scope and yet you return a pointer to it. So if you try to access the struct using this pointer it will not be valid as the instance no longer exists. If you want to do this you should dynamically allocate it using malloc . Alternatively do not return a pointer at all and use the alternative option of #Andrew .
In your "another method" you are locally declaring Student s, which will dynamically allocate space (usually on the stack) and you are returning that address on completion.
However, that stack-space will be released on the return, so there is no guarantee that the data is uncorrupted - in fact the likelyhood is that it will be!
Declare Student s in the call to your method, and pass the pointer to makeAndrew:
void makeAndrew(Student *s) {
setName( s, "Andrew");
setStudentID( s, 12345678);
}
...
Student s;
makeAndrew( &s );
...
Your function makeAndrew returns pointer to a local variable. It is only valid before the scope ends, so as soon as the function finishes, it will change when the memory gets overwritten - i. e. almost instantly. You would have to allocate it dynamically (using Student *s = new Student;, or if you really want to stick to pure C, Student *s = malloc (sizeof Student );, and then free it outside the function after it is not needed to avoid memory leak.
Or do it as Andrew suggested, it's less error-prone.
I would change the makeAndrew() function to just return a struct, not a pointer to a struct to correct the error with respect to returning a pointer to a temporary variable:
Student makeAndrew(void)
{
Student s;
setName(&s, "Andrew");
setStudentID(&s, 12345678);
return s;
}
Student aStudent = makeAndrew();
Your setName does have an error with respect to temp, which should be a char *, since you are incrementing it in your loop to point to another character in the input c-string. I think it was missing the null termination as well. And as you mention in your comment, there should be a check for overflow of the name char array in Student:
void setName(Student* s, const char* name) { // 's' is a pointer to a Student struct |
// 'name' is a pointer to the first element of a char array (repres. a string)
const char *temp;
int i;
for (i = 0, temp = name; *temp != '\0' && i <= MAX_NAME_LEN; temp++, i++)
{
*((s->name) + i) = *temp;
}
s->name[i] = '\0';
}
You can use strncpy to simplify setName:
void setName2(Student *s,const char *name)
{
#include <string.h>
strncpy(s->name, name,MAX_NAME_LEN);
s->name[MAX_NAME_LEN] = '\0';
}
plain C have nice feature - void type pointers, which can be used as pointer to any data type.
But, assume I have following struct:
struct token {
int type;
void *value;
};
where value field may point to char array, or to int, or something else.
So when allocating new instance of this struct, I need:
1) allocate memory for this struct;
2) allocate memory for value and assign it to value field.
My question is - is there ways to declare "array of type void", which can be casted to any another type like void pointer?
All I want is to use "flexible member array" (described in 6.7.2.1 of C99 standard) with ability to casting to any type.
Something like this:
struct token {
int type;
void value[];
};
struct token *p = malloc(sizeof(struct token) + value_size);
memcpy(p->value, val, value_size);
...
char *ptr = token->value;
I suppose declaring token->value as char or int array and casting to needed type later will do this work, but can be very confusing for someone who will read this code later.
Well, sort of, but it's probably not something you want:
struct token {
// your fields
size_t item_size;
size_t length
};
struct token *make_token(/* your arguments */, size_t item_size, size_t length)
{
struct token *t = malloc(sizeof *t + item_size * length);
if(t == NULL) return NULL;
t->item_size = item_size;
t->length = length;
// rest of initialization
}
The following macro can be used to index your data (assuming x is a struct token *):
#define idx(x, i, t) *(t *)(i < x->length ? sizeof(t) == x->item_size ?
(void *)(((char *)x[1]) + x->item_size * i)
: NULL : NULL)
And, if you like, the following macro can wrap your make_token function to make it a little more intuitive (or more hackish, if you think about it that way):
#define make_token(/* args */, t, l) (make_token)(/* args */, sizeof(t), l)
Usage:
struct token *p = make_token(/* args */, int, 5); // allocates space for 5 ints
...
idx(p, 2, int) = 10;
Expanding on AShelly's answer you can do this;
/** A buffer structure containing count entries of the given size. */
typedef struct {
size_t size;
int count;
void *buf;
} buffer_t;
/** Allocate a new buffer_t with "count" entries of "size" size. */
buffer_t *buffer_new(size_t size, int count)
{
buffer_t *p = malloc(offsetof(buffer_t, buf) + count*size);
if (p) {
p->size = size;
p->count = count;
}
return p;
}
Note the use of "offsetof()" instead of "sizeof()" when allocating the memory to avoid wasting the "void *buf;" field size. The type of "buf" doesn't matter much, but using "void *" means it will align the "buf" field in the struct optimally for a pointer, adding padding before it if required. This usually gives better memory alignment for the entries, particularly if they are at least as big as a pointer.
Accessing the entries in the buffer looks like this;
/** Get a pointer to the i'th entry. */
void *buffer_get(buffer_t *t, int i)
{
return &t->buf + i * t->size;
}
Note the extra address-of operator to get the address of the "buf" field as the starting point for the allocated entry memory.
I would probably do this:
struct token {
int type;
void *value;
};
struct token p;
p.value = malloc(value_size);
p.value[0] = something;
p.value[1] = something;
...
edit, actually you have to typecast those p.value[index] = somethings. And/or use a union to not have to typecast.
You can't have an array of 'void' items, but you should be able to do something like what you want, as long as you know value_size when you do the malloc. But it won't be pretty.
struct token {
int type;
void *value;
};
value_size = sizeof(type)*item_count;
struct token *p = malloc(sizeof(struct token) + value_size);
//can't do memcpy: memcpy(p->value, val, value_size);
//do this instead
type* p = (type*)&(p->value);
type* end = p+item_count;
while (p<end) { *p++ = someItem; }
Note that you need an extra address-of operator when you want to get the extra storage.
type *ptr = (type*)&(token->value);
This will 'waste' sizeof(void*) bytes, and the original type of value doesn't really matter, so you may as well use a smaller item. I'd probably typedef char placeholder; and make value that type.
following structure can help you.
struct clib_object_t {
void* raw_data;
size_t size;
};
struct clib_object_t*
new_clib_object(void *inObject, size_t obj_size) {
struct clib_object_t* tmp = (struct clib_object_t*)malloc(sizeof(struct clib_object_t));
if ( ! tmp )
return (struct clib_object_t*)0;
tmp->size = obj_size;
tmp->raw_data = (void*)malloc(obj_size);
if ( !tmp->raw_data ) {
free ( tmp );
return (struct clib_object_t*)0;
}
memcpy ( tmp->raw_data, inObject, obj_size);
return tmp;
}
clib_error
get_raw_clib_object ( struct clib_object_t *inObject, void**elem) {
*elem = (void*)malloc(inObject->size);
if ( ! *elem )
return CLIB_ELEMENT_RETURN_ERROR;
memcpy ( *elem, inObject->raw_data, inObject->size );
return CLIB_ERROR_SUCCESS;
}
More Details : clibutils
Array of type void is not supporting in c/c++.
Example like:
int main() {
void alexa[]; // error: declaration of ‘alexa’ as array of void
return 0;
}
Array of void pointer is supported in c/c++.
Example below:
int main(int argc, char argv*[])
{
void *alexa[100]; // Compiled successfully
return 0;
}