So, we have an interesting situation.
We are supposed to write a DBMS in C under Linux and we have the following problem:
when trying to join two relations/tables the new relation/table has number of Fields/Columns equal to the sum of both joining relations/tables. This is fine, but when we have to copy the data of the tuple/row from the two joining relations/tables we don't seem to find a way. The tuples/rows are realized as list elements via this structure:
typedef struct element {
void *data;
struct element *next;
} Element;
The new element is created via this function:
Element *
newElement (void *data)
{
Element *e = (Element*) malloc (sizeof (Element));
assert (e != NULL);
e->data = data;
e->next = NULL;
return e;
}
And the *data parameter is passed as of this type:
typedef struct {
int sid;
char sname[STRLEN];
int rating;
float age;
} Sailor;
The thing is when we have to join two relations we cannot know what Structure they use for their tuples/rows and therefore we cannot create the new tuples/rows for the new relation from the tuples/rows of the two joining relations.
Please help.
Given you cannot at runtime define new structures, something like the following (hack?) could work..
Firstly define a base structure which only has a type id
typedef struct
{
int type_id; /* this holds a number which identifies the following structure */
} TypeID;
/* now all structures should contain this */
typedef struct {
TypeID type;
char sname[STRLEN];
int rating;
float age;
} Sailor;
typedef struct {
TypeID type;
char sname[STRLEN];
int sailors;
} Boat;
Now treat the data segment as a container of these structs, let's say for example that I will have two structs in data (i.e. joined the two above structs), my data segment would look like:
----------
| Sailor |
+--------+
| Boat |
----------
When reading the data chunk, first cast it to TypeID, which gives you the type, then you can cast it to the real structure. Then if there is more data in the data segment, move the pointer by the sizeof the structure you've just read, and again do the same process. Basically this allows you to have a variable length segment which is a set of structures of different types - i.e. your joined data structure.
Oh, and you'll need to modify your Element structure to hold the size of the data segment as well.
Related
I have a C function which needs a large amount of variables to be passed, so I came to the idea of "packing" them all in a single array (matrix of variables). The point is, these variables are of a very different type, some int, some arrays (strings and vectors), and many of them float. Is there a way to leave unspecified the type of data stored into the matrix? (I unsuccessfully explored the void "data type")
The elements of an array are always of a single type, that's the point.
Collecting variables of multiple types is the job for a structure, i.e. a struct.
This is a quite common way to solve this particular problem. If the structure becomes large, you might find it convenient to pass a pointer to an instance of it, rather than copying the entire thing in the call.
You can use va_list but struct is the best way to do it
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
enum type {
INT,
FLOAT,
PCHAR,
};
struct any_type {
enum type type_;
union {
int int_;
float float_;
char* pchar_;
};
};
#define MYSIZE 10
void process(size_t size, struct any_type* array)
{
for(int i = 0; i < size; i++) {
switch(array[i].type_) {
case INT :
printf("INT: %d\n", array[i].int_);
break;
case FLOAT :
printf("FLOAT: %f\n", array[i].float_);
break;
case PCHAR :
printf("PCHAR: %s\n", array[i].pchar_);
break;
default:
printf("UNKNOWN TYPE PROVIDED\n");
break;
}
}
}
int main(int argc, char *argv[])
{
struct any_type *array;
array = malloc(MYSIZE*(sizeof(struct any_type)));
array[0].type_ = INT;
array[0].int_ = 10;
array[1].type_ = FLOAT;
array[1].float_ = 2.5;
array[2].type_ = PCHAR;
array[2].pchar_ = "hello char";
process(3, array);
return 0;
}
You can extend type and union as needed. However using nameless unions require -std=c11.
Expanding on my comment above:
Needing to pass a large number of parameters1 to a function can be a sign that there is a problem in your design - your function may be trying to do too many things at once, and you would be better off refactoring it into several smaller functions, each of which only takes a subset of the parameters.
Assuming that's not the case, how are your parameters logically related to each other? Can they be considered attributes of a single data item? For example, a person may be described by the following attributes: surname, given name, birth date, sex. These can be collected together into a single struct type such as
#include <time.h>
struct person {
char *surname;
char *name;
struct tm birthdate; // struct tm defined in time.h
char sex;
};
void write_to( struct person *p )
{
p->surname = strdup( "McGillicuddy" );
p->name = strdup( "Aloysius" );
p->sex = 'M';
p->birthdate.tm_year = 32; // tm_year starts at 1900, so this is 1932
p->birthdate.tm_mon = 11; // december
p->birthdate.tm_day = 1;
};
int main( void )
{
struct person p;
...
write_to( &p );
...
}
Note that members of struct types can themselves be struct types - struct tm is a type defined in time.h that specifies a datetime value using multiple attributes.
Some notes on syntax:
When you want to access a member of a struct instance, use the . operator. When you want to access a member of a struct through a pointer, use the -> operator. In the function write_to, p is a pointer to struct person, so to access each member of p we use ->. The birthdate member is an instance of struct tm, not a pointer, so we use the . operator to access each member of birthdate.
p->m is equivalent to (*p).m.
Like I said in my comment, you should not collect otherwise unrelated items into a struct type just to reduce the number of parameters being passed to a function. They should all be attributes of a more complex type. Some other examples of what I mean:
// A node in a list
struct node {
data_t data; // for some data type data_t;
struct node *next;
struct node *prev;
};
// A street address
struct addr {
char *number; // to handle things like 102A, 102B
char *street;
char *city;
char state[3];
char *zip;
};
It's possible that you're really passing only a couple of distinct data items to your function, each of which is composed of a lot of different attributes. Take a step back and look at your variables and see how they relate to each other.
"Large" depends on context, and of course there are always exceptions to any rule, but in general passing more than 7 distinct, unrelated parameters is a sign you may need to refactor your function into several smaller functions.
I have 3 types of structures: book, CD (in the CD I have the struct "song"- and the CD contain a list of songs), and a DVD.
I need to create a linked list of products of a store
My question is how to create a list of products without knowing which type is the pointer in it. It can be book, CD or DVD.
(I cannot use unions.)
Leaving the implementation of the CD / DVD data structures up to you, as well as the implementation of the linked list, you would probably want to do something like this:
enum ptype {
PTYPE_BOOK,
PTYPE_CD,
PTYPE_DVD,
};
struct book {
char *author;
char *title;
char *publisher;
char *isbn;
};
struct product {
enum ptype type;
void *data;
};
struct product_list {
struct product *product;
struct product_list *next;
};
The enumeration is responsible for distinguishing the type of product being pointed to. To create a book, for instance:
struct product *
create_book(char *author, char *title, char *publisher, char *isbn)
{
struct product *p;
struct book *b;
p = calloc(1, sizeof (*p));
if (p == NULL) {
return NULL;
}
p->type = PTYPE_BOOK;
p->data = calloc(1, sizeof(*b));
if (p->data == NULL) {
free(p);
return NULL;
}
b = p->data;
b->author = author;
b->title = title;
b->publisher = publisher;
b->isbn = isbn;
return p;
}
This is a typical interface when unions can't be used for whatever reason. It's unfortunate in that it requires much more memory allocation (and in reality, you'll probably have to strdup(3) author / title / publisher / isbn).
To retrieve a book from a product, you might like to have something like this:
static inline struct book *
get_book(struct product *p)
{
assert(p->type == PTYPE_BOOK);
return p->data;
}
You don't need to (and shouldn't) cast a void pointer in C. If you're using or supporting a C++ compiler, you may need to use return (struct book *)p->data;. You'd implement something similar for your CD and DVD types. Then, when you need to extract the product:
switch (p->type) {
case PTYPE_BOOK:
b = get_book(p);
break;
case PTYPE_CD:
c = get_cd(p);
break;
case PTYPE_DVD:
d = get_dvd(p);
break;
}
You may also want to look at using something other than a linked list for storing these things, especially if they will be read / traversed many times after they are created. (A vector would not be a bad idea). If you know how many items you'll have, this can help reduce the number of allocations you must perform, and the contiguous memory access will improve speed.
If you need to search entries, I suspect you'll need an external searchable data structure anyway.
You need to use void pointers for the data set. Here is a snippet of code from my linked list structures I use modified for your need:
#define CD 1
#define DVD 2
#define BOOK 3
/* Structure for linked list elements */
typedef struct ListElmt_ {
void *data;
unsigned datatype; /* variable to know which data type to cast as */
struct ListElmt_ *next;
} ListElmt;
#define list_data(element) ((element)->data)
Using the void pointer to pack your data into the list, you can now just test the datatype variable and uncast as necessary. I use a macro to return list data (defined above). So you could use something like:
CD_struct *cd_data
if (element->datatype == CD)
cd_data = (CD_struct *) list_data(ListElmt)
if every struct has ITEMTYPE is first member, you can use LinkedList.itemtype on all
this is because the offset to itemtype does not depend on inner struct order, since by rule i said itemtype is same type in all and first in all
One way could be :
Create a generic Structure 'Product'
Keep a variable to keep track of the current type of product.
Keep three pointers of Book, CD & DVD each.
Or As in Archie's Comment :
Create a generic Structure 'Product'
Keep a variable to keep track of the current type of product.
Keep a void * pointer & cast when needed.
I think the first one is useful, if at a later stage, the product can be of multiple type. Eg - Book + CD
I would like to simulate the object oriented programming, so in C++, let's consider the following C code:
typedef struct tAnimal{
char * name;
int age;
}tAnimal;
typedef struct tAnimal2{
char * name;
int age;
float size;
}tAnimal2;
In C++ you can create a table of different objects which are inherited from the same class.
I would like to do the same in C, let's consider the following code:
tAnimal ** tab;
tab = malloc(sizeof(tAnimal*)*2);
tab[0] = malloc(sizeof(tAnimal));
tab[1] = malloc(sizeof(tAnimal2));
Notice that the allocation works because malloc returns a void pointer, and C does not require casting. But I still have no access to the size field, because the type of tab elements is tAnimal after all.
Is there anyway to fix this?, I would like to stay away from void ** pointers.
In C it's common to use a structure with a type-flag, and a union of the data:
typedef enum
{
Animal1,
Animal2
} AnimalType;
struct Animal
{
AnimalType type;
union
{
tAnimal animal;
tAnimal2 animal2;
};
};
Now you can create an array of the Animal structure.
If you want to access the size field you have to cast your pointer to tAnimal2. Note, the same would be true for C++.
You can kind of simulate inheritance by embedding the first struct at the beginning of the second:
struct tAnimal{
char * name;
int age;
};
struct tAnimal2{
struct tAnimal parent;
float size;
};
In order to access the size field in tab[1] you can cast the pointer to a tAnimal2 pointer.
tAnimal2* panimal2 = (tAnimal2*) tab[1];
panimal2->size = 1.0;
However this practice is prone to data corruption since you will need a method to ensure that the element of the table you cast to tAnimal2 is indeed an instance of tAnimal2. You could use an additional type field as Joachim Pileborg suggests to check the type of the object.
Often stacks in C are dependent upon datatype used to declare them. For example,
int arr[5]; //creates an integer array of size 5 for stack use
char arr[5]; //creates a character array of size 5 for stack use
are both limited to holding integer and character datatypes respectively and presumes that the programmer knows what data is generated during the runtime. What if I want a stack which can hold any datatype?
I initially thought of implementing it as a union, but the approach is not only difficult but also flawed. Any other suggestions?
I would use a structure like this:
struct THolder
{
int dataType; // this is a value representing the type
void *val; // this is the value
};
Then use an array of THolder to store your values.
This is really just a variant of Pablo Santa Cruz' answer, but I think it looks neater:
typedef enum { integer, real, other } type_t;
typedef struct {
type_t type;
union {
int normal_int; /* valid when type == integer */
double large_float; /* valid when type == real */
void * other; /* valid when type == other */
} content;
} stack_data_t;
You still need to use some way to explicitly set the type of data stored in each element, there is no easy way around that.
You could look into preprocessor magic relying on the compiler-dependent typeof keyword to do that automagically, but that will probably not do anything but ruin the portability.
Some people have suggested a void* member. In addition to that solution I'd like to offer an alternative (assuming your stack is a linked list of heap-allocated structures):
struct stack_node
{
struct stack_node *next;
char data[];
};
The data[] is a C99 construct. data must be the last member; this takes advantage of the fact that we can stuff arbitrary quantities after the address of the struct. If you're using non-C99 compiler you might have to do some sketchy trick like declare it as data[0].
Then you can do something like this:
struct stack_node*
allocate_stack_node(size_t extra_size)
{
return malloc(sizeof(struct stack_node) + extra_size);
}
/* In some other function... */
struct stack_node *ptr = allocate_stack_node(sizeof(int));
int *p = (int*)ptr->data;
If this looks ugly and hacky, it is... But the advantage here is that you still get the generic goodness without introducing more indirection (thus slightly quicker access times for ptr->data than if it were void* pointing to a different location from the structure.)
Update: I'd also like to point out that the code sample I give may have problems if your machine happens to have different alignment requirements for int than char. This is meant as an illustrative example; YMMV.
You could use macros and a "container" type to reduce "type" from being per-element, to whole-container. (C99 code below)
#define GENERIC_STACK(name, type, typeid, elements) \
struct name##_stack { \
unsigned int TypeID; \
type Data[elements]; \
} name = { .TypeID = typeid }
Of course, your "TypeID" would have to allow every possible agreed-upon type you expect; might be a problem if you intend to use whole structs or other user-defined types.
I realize having a uniquely named struct type for every variable is odd and probably not useful... oops.
I created an library that works for any data type:
List new_list(int,int);
creates new list eg:
List list=new_list(TYPE_INT,sizeof(int));
//This will create an list of integers
Error append(List*,void*);
appends an element to the list. *Append accpts two pointers as an argument, if you want to store pointer to the list don't pass the pointer by pointer
eg:
//using the int list from above
int a=5;
Error err;
err=append(&list,&a)
//for an list of pointers
List listptr=new_list(TYPE_CUSTOM,sizeof(int*));
int num=7;
int *ptr=#
append(&listptr,ptr);
//for list of structs
struct Foo
{
int num;
float *ptr;
};
List list=new_list(TYPE_CUSTOM,sizeof(struct Foo));
struct Foo x;
x.num=9;
x.ptr=NULL;
append(&list,&x);
Error get(List*,int);
Gets data at index specified. When called list's current poiter will point to the data.
eg:
List list=new_list(TYPE_INT,sizeof(int));
int i;
for(i=1;i<=10;i++)
append(&list,&i);
//This will print the element at index 2
get(&list,2);
printf("%d",*(int*)list.current);
Error pop(List*,int);
Pops and element from the specified index
eg:
List list=new_list(TYPE_INT,sizeof(int));
int i;
for(i=1;i<=10;i++)
append(&list,&i);
//element in the index 2 will be deleted,
//the current pointer will point to a location that has a copy of the data
pop(&list,2);
printf("%d",*(int*)list.current);
//To use the list as stack, pop at index list.len-1
pop(&list,list.len-1);
//To use the list as queue, pop at index 0
pop(&list,0);
Error merge(List ,List);
Merges two list of same type. If types are different will return a error message in the Error object it returns;
eg:
//Merge two elements of type int
//List 2 will come after list 1
Error err;
err=merge(&list1,&list2);
Iterator get_iterator(List*);
Get an iterator to an list. when initialized will have a pointer to the first element of the list.
eg:
Iterator ite=get_iterator(&list);
Error next(Iterator*);
Get the next element of the list.
eg:
//How to iterate an list of integers
Iterator itr;
for(itr=get_iterator(&list); ite.content!=NULL; next(ite))
printf("%d",*(int*)ite.content);
https://github.com/malayh/C-List
i need in double linked list in C, but it must be for different types. In C++ we use templates for it. Where can i find example in C for double linked list with abstract types items.
Thank you
There are a few approaches you can take, one of which involves storing a void* in your ADT.
I've always found this to be a bit of a pain in a linked list since you have to manage it's allocation separately to the list itself. In other words, to allocate a node, you need to alocate both the node and its payload separately (and remember to clean them both up on deletion as well).
One approach I've used in the past is to have a 'variable sized' structure like:
typedef struct _tNode {
struct _tNode *prev;
struct _tNode *next;
char payload[1];
} tNode;
Now that doesn't look variable sized but let's allocate a structure thus:
typedef struct {
char Name[30];
char Addr[50];
char Phone[20];
} tPerson;
tNode *node = malloc (sizeof (tNode) - 1 + sizeof (tPerson));
Now you have a node that, for all intents and purposes, looks like this:
typedef struct _tNode {
struct _tNode *prev;
struct _tNode *next;
char Name[30];
char Addr[50];
char Phone[20];
} tNode;
or, in graphical form (where [n] means n bytes):
+------------+
| prev[4] |
+------------+
| next[4] |
+------------+ +-----------+
| payload[1] | | Name[30] | <- overlap
+------------+ +-----------+
| Addr[50] |
+-----------+
| Phone[20] |
+-----------+
That is, assuming you know how to address the payload correctly. This can be done as follows:
node->prev = NULL;
node->next = NULL;
tPerson *person = &(node->payload); // cast for easy changes to payload.
strcpy (person->Name, "Richard Cranium");
strcpy (person->Addr, "10 Smith St");
strcpy (person->Phone, "555-5555");
That cast line simply casts the address of the payload character (in the tNode type) to be an address of the actual tPerson payload type.
Using this method, you can carry any payload type you want in a node, even different payload types in each node, if you make the structure more like:
typedef struct _tNode {
struct _tNode *prev;
struct _tNode *next;
int payloadType; // Allows different payload type at each node.
char payload[1];
} tNode;
and use payloadType to store an indicator as to what the payload actually is.
This has the advantage over a union in that it doesn't waste space, as can be seen with the following:
union {
int fourBytes;
char oneHundredBytes[100];
} u;
where 96 bytes are wasted every time you store an integer type in the list (for a 4-byte integer).
The payload type in the tNode allows you to easily detect what type of payload this node is carrying, so your code can decide how to process it. You can use something along the lines of:
#define PAYLOAD_UNKNOWN 0
#define PAYLOAD_MANAGER 1
#define PAYLOAD_EMPLOYEE 2
#define PAYLOAD_CONTRACTOR 3
or (probably better):
typedef enum {
PAYLOAD_UNKNOWN,
PAYLOAD_MANAGER,
PAYLOAD_EMPLOYEE,
PAYLOAD_CONTRACTOR
} tPayLoad;
The only thing you need to watch out for is to ensure that the alignment of the payload is correct. Since both my payload placeholder and the payload are all char types, that's not an issue. However, if your payload consists of types with more stringent alignment requirements (such as something more strict than the pointers, you may need to adjust for it).
While I've never seen an environment with alignments more strict than pointers, it is possible according to the ISO C standard.
You can usually get the required alignment simply by using a data type for the payload placeholder which has the strictest alignment requirement such as:
long payload;
In retrospect, it occurs to me that you probably don't need an array as the payload placeholder. It's simple enough to just have something you can take the address of. I suspect that particular idiom of mine hearkens back to the days where I just stored an array of characters (rather than a structure) and referenced them directly. In that case, you could use payload[] on its own without casting to another type.
Handling arbitrary data in C is usually done by using pointers - specifically void * in most cases.
Obviously, the linux kernel uses linked lists in many, many places both in the kernel itself and in the many device driver modules. Almost all of these are implemented using the same a set of macros defined in linux/list.h
See http://isis.poly.edu/kulesh/stuff/src/klist/ or http://kernelnewbies.org/FAQ/LinkedLists for a good explanation.
The macros look a bit strange at first but are easy to use and soon become second nature. They can trivially be adapted for use in user space (see list.h).
The closest think in C to an "object" base class or templated types is a void pointer. A void * represents a pointer to something, but it does not specify what type of data is being pointed to. If you want to access the data, you need to use a cast.
A doubly linked list node could look like this:
struct DoubleLinkedListNode {
struct DoubleLinkedListNode *previous, *next;
void *data;
};
To assign a node a string, for example, you could do:
char myString[80] = "hello, world";
struct DoubleLinkedListNode myNode;
myNode.data = myString;
To get the string back from a node, you use a cast:
char *string = (char *)myNode.data;
puts(string);
To store a non-pointer, you need to make a pointer from the data. For structures, you may be able to simply dereference the instance if its lifetime is long enough (similar to the above example). If not, or if you're dealing with a primitive type (e.g. an int or float), you need to malloc some space. Just be sure to free the memory when you're done.
You could use macros as demonstrated here (this particular example implements generic hash-tables).