c printf function dynamic type determination - c

I am trying to implement a generic stack in c using void pointer to point to the data. the structure looks like this
struct record{
void* data;
struct record* previousRecord;
};
where void pointer data is a pointer to the data a stack position will hold. If I implement a push function like this
struct record* push(struct record* tos, void* data){
struct record* newtos = (struct record*)malloc(sizeof(struct record));
newtos->data = data;
newtos->previousRecord = tos;
return newtos;
}
and push a couple of integer pointers and string pointers into the stack, is there any way I can print the values referenced by these pointers. My problem is that I have to specify the data type of value to print in the code if I use a printf function but the values stored in the stack can only be determined at run time

If you want to print a data in the correct format, you must know what is its type.
#include <stdio.h>
enum datatype
{
DATATYPE_STRING, DATATYPE_INTEGER
};
struct record
{
enum datatype type;
void *data;
struct record *next;
};
void print_record(struct record *p)
{
switch (p->type)
{
case DATATYPE_STRING:
printf("%s\n", (char *)p->data);
break;
case DATATYPE_INTEGER:
printf("%d\n", *(int *)p->data);
break;
}
}

With address how would you know the type of data, it can be string or an integer address:
But you can keep an extra field in your record definition about type of value stored in data part, like below:
typedef enum { STRING, INT, CHAR} type;
struct record{
type t;
void* data;
struct record* previousRecord;
};
and write a common print function :
int print(struct record *r){
switch(r->t){
case CHAR: return printf("%c", *((char*)(r->data)));
case INT: return printf("%d", *((int*)r->data));
case STRING: return printf("%s", (char*)r->data);
default: return printf("Error");
}
}
Here is a Project/A book that can be very helpful to write generic code in C.

Related

Pass an array of pointers to function argument

I am trying to construct a bus network using adjacent linked list graph data structure.
A simplified code is shown below:
typedef struct BusNetwork
{
struct AdjStopList *stopsArray; //defing the array of pointers
} BusNetwork;
typedef struct Node
{
int stopID;
struct Node *next;
} Node;
typedef struct AdjStopList
{
char stopName[20];
int numOfAdjStp;
struct Node *first;
} AdjStopList;
void insertStopAtLast(AdjStopList *L, int stopID)
{
//add stopID to the last node of the list
return;
}
void addBusRoute(AdjStopList *L[], int from, int to)
{
if (from == to)
return;
insertStopAtLast(L[from], to);
return;
}
void main(BusNetwork *BN, int from, int to)
{
addBusRoute(BN->stopsArray, from, to);
}
The problem is with addBusRoute(BN->stopsArray, from, to); It seems I didn't pass the same type of value as function argument. But my understanding of BN->stopsArray is an array of pointers, which should be the same as AdjStopList L[]. What went wrong?
The argument AdjStopList *L[] has the same meaning as AdjStopList **L.
On the other hand, what is passed BN->stopsArray is struct AdjStopList *.
The argument is a pointer to a pointer to AdjStopList, but what is passed is a pointer to AdjStopList.
Therefore, the type differs.

Trying to set a pointer to a struct

I have a function called SemCreate that takes a name an int and a pointer as parameters. I want the pointer to point to a new struct and I want to return an int, 0 if it went okay.
int P1_SemCreate(char *name, unsigned int value, P1_Semaphore *sem){
USLOSS_Console("Create a semaphore\n");
if(!verifyKernel()) {
//USLOSS_Console("ERROR: Not currently in Kernel mode\n");
USLOSS_Halt(1);
}
if(numSems>= P1_MAXSEM){
//USLOSS_Console("ERROR: MAX semaphore already exist\n");
return -2;
}
if(name == NULL){
return -3;
}
interruptsOff();
int i;
for (i = 0; i < P1_MAXSEM; i++) {
if (semTable[i].inUse == 0) {
semTable[i].value = value;
semTable[i].list = NULL;
semTable[i].name = malloc(sizeof(char));
strcpy(semTable[i].name, name);
semTable[i].inUse = 1;
semaphore *temp = NULL;
temp = malloc(sizeof(semaphore));
temp->value = value;
temp->list = NULL;
temp->name = malloc(sizeof(char));
strcpy(temp->name, name);
*sem = temp;
break;
}
}
numSems++;
interruptsOn();
return 0;
}
Right now the pointer is fine within the function but once I return the pointer is null
EDIT: The array semTable is an array of semaphores
typedef struct semaphore{
int value;
char * name;
struct node *list;
int checkPoint;
int inUse;
}semaphore;
typedef struct PCB {
USLOSS_Context context;
int (*startFunc)(void *); /* Starting function */
void *startArg; /* Arg to starting function */
int pid;
int status;
int killedStatus;
int state;
int priority;
char name[50];
int parentPID;
int numOfChild;
int blockFlag;
struct sempahore *blockSem;
char *stack;
struct node *children;
struct node *zombiList;
int cpuTime;
int startTime;
struct semaphore *childSem;
} PCB;
typedef struct node {
PCB *pcb;
struct node *next;
} Node;
Your question is not perfectly clear as to what you are trying to do. So, this answer addresses the following general topics in hopes they will assist:
1) Passing the address of a struct via a function, changing the values of the struct members, and accessing changed values in calling function. (It is not the same as the one you show, but illustrates what you want to do.)
2) Creating instances and pointers to instances of a struct, then initializing.
3) Contains link to tutorial on self referencing structs. (as you are doing in your posted code)
typedef struct {//struct definition created in global space, typedef'ed
char line[80]; //to read in the line
int slot;
char type[20]; //long enough for any types listed
int position;
}SLOT;
int modifyStruct(SLOT *slot);//prototype of demonstration function
int main(void)
{
SLOT s;//create instance of SLOT local to main
int ret = modifyStruct(&s);pass address of SLOT instance to change member values
printf("Line: %s\n", s.line);//show changed values
printf("Slot: %d\n", s.slot);
printf("type: %s\n", s.type);
printf("position: %s\n", s.position);
return 0;
}
int modifyStruct(SLOT *slot)
{
strcpy(slot->line, "lineA");
slot->slot = 2;
strcpy(slot->type, "large");
slot->position = 20;
return 0;
}
EDIT - To address question in comment asking how to set a struct pointer to point to a struct.
First, it appears from viewing the code you have posted, that you are using self referencing structs. (i.e. a struct that contains a member that is a pointer instance to itself) Here is a link to a good tutorial dealing with Linked Lists in C, which use self referencing structs.
Regarding you comment: _I guess I should have made it more clear. P1_Semaphore is different to semaphore. I need P1_semaphore to point to the semaphore_.:
If P1_Semaphore is different than semaphore, then one should not be set to point to the address of the other. And your compiler will not let you do that anyway.
As I stated in the comments, a struct pointer should only point to a place in memory that contains an instance of that struct. For example consider the two structs A & B:
typedef struct {
int iNum;
float fNum;
char cStr[80];
}A;
A a, *pA; //create an instance, and pointer to an instance of A
typedef struct {
int iNum1;
int iNum2;
int iNum3;
}B;
B b, *pB; //create an instance, and pointer to an instance of B
A & B are obviously different, and will occupy a different size and shape in memory, so if the pointer to B, *pB was set to point to anything but B, it would be incorrect. It needs to point to B
Correct:
pA = &a //set pointer to A equal to the address of A
pB = &b //set pointer to B equal to the address of B
Incorrect:
pA = &b //set pointer to A equal to the address of B
pB = &a //set pointer to B equal to the address of A
(typical compiler error - Operands of = have types pointer to B and pointer to A)
In C/C++, all parameters are passed by value, not by reference. To get the struct pointer in parameter, you need to use pointer to pointer as the parameter. Like this:
int P1_SemCreate(char *name, unsigned int value, P1_Semaphore **sem){
...
*sem = temp;
...
}

Single function to work on two types of linked lists

I have two linked lists :-
struct Struct_A_s {
int a;
struct Struct_A_s *next;
}Struct_A;
struct Struct_B_s {
int a;
int b;
int c;
int d;
struct Struct_B_s *next;
}Struct_B;
I already have several functions which operate on Struct_A.
Things like :
"Add_tail (Struct_A *)", "Remove_tail(Struct_B *)","Add_node(Struct_A *,int pos),Add_head, etc. etc are in place.
The requirement for me is that I should modify the existing functions so that they can operate on both Struct_A and Struct_B.
In C, is there a way to pass void pointer (or something similar) and write some generic code to work on both Struct_A and Struct_B.
The code size is a big concern here. Currently the only option I see is to rewrite all the code (the linked list operations) from scratch for Struct_B.
There are a few ways that you could go about it. And I'm sure others more skilled than I may have others to suggest.
Option A: pass a void pointer and some sort of indication of the data type then cast it.
Option B: combine the two pointers into a union and pass that.
Option C: combine the type and the union into a struct and pass that
Option D: use a more deferenced alternative to a union
Some example code...
enum DataType { TYPE_1, TYPE_2 };
struct Type1 { ... };
struct Type2 { ... };
union Data
{
void* addr;
struct Type1* type1;
struct Type2* type2;
}
struct Object
{
DataType type;
union Data data;
}
struct Thing
{
DataType type;
void* data;
}
void someFunc1( void* data, DataType type )
{
switch( type )
{
case TYPE_1:
{
struct Type1* type1 = (struct Type1*)data;
...
break;
}
case TYPE_2:
{
struct Type2* type2 = (struct Type2*)data;
...
break;
}
}
}
void someFunc2( union Data* data, DataType type )
{
switch( type )
{
case TYPE_1:
{
struct Type1* type1 = data->type1;
...
break;
}
case TYPE_2:
{
struct Type2* type2 = data->type2;
...
break;
}
}
}
void someFunc3( struct Object* object )
{
switch( object->type )
{
case TYPE_1:
{
struct Type1* type1 = object->data.type1;
...
break;
}
case TYPE_2:
{
struct Type2* type2 = object->data.type2;
...
break;
}
}
}
void someFunc4( struct Thing* thing )
{
switch( thing->type )
{
case TYPE_1:
{
struct Type1* type1 = (struct Type1*)thing->data;
...
break;
}
case TYPE_2:
{
struct Type2* type2 = (struct Type2*)thing->data;
...
break;
}
}
}
Looking at this another way... if you have a method that only takes a then you can do something like this...
void myFunc( int a ) { ... };
void someFunc3( struct Object* object )
{
myFunc( object->type == TYPE_1 ? object->data.type1->a : object->data.type2->a );
}
Yet better still... modify the function to accept the object and only differentiate at the bottom...
void myFunc( struct Object* object )
{
int* a;
switch( object->type )
{
case TYPE_1:
{
a = &object->data.type1->a
break;
}
case TYPE_2:
{
a = &object->data.type2->a;
break;
}
default:
{
abort();
}
}
// do work with a as though it were passed in as a pointer to int
if( object->type == TYPE_2 )
{
// do additional work with the b, c, d elements, etc.
}
}
Yes, you can use void * where you'd otherwise use either Struct_A * or Struct_B *. You will need to design your APIs carefully. Typically, you'll end up working a bit like bsearch() and qsort() taking one or more function pointers that do the structure-specific operations (comparisons in the case of bsearch() and qsort()).
Note that traversing your linked lists will be hard because the next pointer is at different offsets in the structure. You might do better with a fixed generic list structure that contains a next pointer and a void * to the actual structure.
typedef struct List List;
struct List
{
List *next;
//List *prev; // Doubly-linked lists
void *data;
};
This is the difference between 'intrusive' and 'non-intrusive' list structures. Your existing design uses intrusive list structures; the structure in the list is modified to include the pointer. The alternative suggested design is non-intrusive; you can create a list of any structure type without modifying the structure type.
You can redefining the structures as below. You have to do a lot of casting based on the type to modify all your earlier functions to work for both. You need to use Struct_A * for both.
struct Struct_A_s {
int type;
Struct_A_s *next;
int a;
}Struct_A;
struct Struct_B_s {
int type;
Struct_A *next;
int a;
int b;
int c;
int d;
}Struct_B;

access element of struct passed into a void* pointer

I'm working with a binary search tree data structure to sort a series of structs with the type definitions:
typedef struct {
char c;
int index;
} data_t;
typedef struct node node_t;
typedef node {
void *data;
node_t *left;
node_t *right;
}
The node_t typedef is from a library provided to me for this purpose, presumably with a void* pointer to ensure polymorphism. node will be passed into the function:
static void
*recursive_search_tree(node_t *root,
void *key, int cmp(void*,void*))
Within the recursive_search_tree function, I want to be able to modify the code to use the index element as a condition to find the match closest to the index of the linear pass over an array of characters, which would ultimately involve a data_t being passed into *key and key->index being accessed within the function.
The Question
Is it possible to access key->index where key is a void* pointing to a data_t struct, or would this only be possible if data_t was declared as the type for key? I have tried to do the latter, however even casting the pointer to an int doesn't seem to pass the compiler.
Sure it's possible, you'd cast key as type *data_t. (As long as that's really what key points to!)
key /* argument of type void* */
(data_t*)key /* cast as type data_t* */
((data_t*)key)->index /* dereferenced */
Here is a simple example:
#include <stdlib.h>
#include <stdio.h>
typedef struct {
char c;
int index;
} data_t;
typedef struct node {
void *data;
struct node *left;
struct node *right;
} node_t;
static int cmp(void *lhs, void *rhs)
{
return ((data_t *)lhs)->index - ((data_t *)rhs)->index;
}
int main(void)
{
data_t d0;
data_t d1;
d0.c = 'A';
d0.index = 1;
d1.c = 'B';
d1.index = 2;
printf("d0 < d1? %s\n", (cmp((void *)&d0, (void *)&d1) < 0 ? "yes" : "no"));
printf("d1 < d0? %s\n", (cmp((void *)&d1, (void *)&d0) < 0 ? "yes" : "no"));
return EXIT_SUCCESS;
}
This is type unsafe, as is any use of void. The use of void is generally because the intermediate is holding onto something it doesn't use for someone else's convenience.
This is a C function to let you hold whatever you want in a tree.
All it does is return whatever pointer you give it.
In your search function
int cmp(void* dt1, void* dt2)
{
data_t* data1 = (data_t*)dt1;
data_t* data2 = (data_t*)dt2;
/* Do what you need with data1 and data2 here */
}
Should let you do whatever you need. The problem you have is you need to cast your values inside the function. The parameters to cmp should exactly match the API for the library you are using, which says void* for the parameters.

how to access the struct?

struct result {
int number;
int length;
};
struct result findLongestSeq(int intarray[], int size) {
result->number // undefined symbol
}
how to access the struct result inside the function findLongestSeq?
thanks
struct result {
int number;
int length;
};
struct result findLongestSeq(int intarray[], int size) {
struct result result;
result.number = 0;
result.length = 42;
return result;
}
If you are dealing with struct result foo then you access its members via foo.number.
If however you are dealing with a pointer to foo (struct result *foo) then you access its members via foo->number.
If you were to manually allocate your result struct via
struct result *result = (struct result *)malloc(sizeof (struct result));
Then you'd have to access its members via result->number (and would be responsible for freeing it once not used anymore).
Further more I'd rather use this for the sake of better readability:
typedef struct {
int number;
int length;
} ResultStruct;
This way you can then use ResultStruct result; instead of redundant and verbose struct result result;.
You have to keep in mind that by simply typing
struct result {
int number;
int length;
};
you only define how a struct with name result actually looks like, i.e. of what parts it is made up. This is a general definition, but you have variable of that type yet.
To access values of this struct you have to create a variable by
struct result myResult;
or however you want to call it. At this point you are able to access the members of this struct with myResult.number

Resources