2
\$\begingroup\$

I am writing C code that has some dynamic arrays/list that are represented with a struct that contains the number of elements and a pointer to the elements.

I have some functions that are doing some similar work with that structs, for example printing the elements. To use the same code I decided to create a struct to that holes an abstract data type and the printing function receives a pointer to that struct.

A specific struct looks like that:

typedef struct {
 int numOfElements;
 int *element;
} LIST_INT, *PLIST_INT; 

The generic struct look like that:

typedef struct {
 int numOfElements;
 void *element;
} LIST_GEN, *PLIST_GEN;

Is that the right approach?

This is the code example:

#include <stdio.h>
#include <stdlib.h>
typedef struct {
 int numOfElements;
 char *element;
} LIST_CHAR, *PLIST_CHAR;
typedef struct {
 int numOfElements;
 int *element;
} LIST_INT, *PLIST_INT;
typedef struct {
 int numOfElements;
 void *element;
} LIST_GEN, *PLIST_GEN;
typedef void(*fpPrintElement)(void *element);
void print_list(PLIST_GEN list, int elementSize, fpPrintElement printElement) {
 int i = 0;
 int num = list->numOfElements;
 for (i = 0; i < num; ++i) {
 printElement(((char *)(list->element) + i * elementSize));
 }
 return;
}
void print_int(int * element) { 
 printf("%d ", *element);
}
void print_char(char * element) {
 printf("%c ", *element);
}
void main() {
 LIST_INT list_int;
 list_int.numOfElements = 10;
 list_int.element = malloc(sizeof(list_int.element) * list_int.numOfElements);
 for (int i = 0; i < list_int.numOfElements; ++i) {
 list_int.element[i] = i * 1000;
 }
 LIST_INT list_char;
 list_char.numOfElements = 7;
 list_char.element = malloc(sizeof(list_char.element) * list_char.numOfElements);
 for (int i = 0; i < list_char.numOfElements; ++i) {
 list_char.element[i] = i + 35;
 }
 print_list((PLIST_GEN)&list_int, sizeof(*list_int.element), print_int);
 print_list((PLIST_GEN)&list_char, sizeof(*list_char.element), print_char);
 return;
}
t3chb0t
44.6k9 gold badges84 silver badges190 bronze badges
asked Jan 18, 2017 at 13:39
\$\endgroup\$
3
  • \$\begingroup\$ Is printElement going to work as expected if you pass in a pointer to an int, a float, a different structure? It's unclear how it's going to know how big the element it's printing is. \$\endgroup\$ Commented Jan 18, 2017 at 14:10
  • \$\begingroup\$ printElement is a pointer to a function that is given by the user. The user should know which elements he wants to print and there for supply the right function to do so. My main dilemma is should I use PLIST_GEN or just a VOID * as an input parameter to the abstract array \$\endgroup\$ Commented Jan 18, 2017 at 14:12
  • \$\begingroup\$ I have rolled back the last edit. Please see What should I do when someone answers my question? \$\endgroup\$ Commented Jan 22, 2017 at 6:00

2 Answers 2

1
\$\begingroup\$

Your code is valid. However note that

sizeof(list_int.element)

and

sizeof(list_chat.element)

return the size of a pointer, but it is not the de size of the type of elements into array. So, for instance, you need to write

sizeof(*list_int.element)
answered Jan 19, 2017 at 21:35
\$\endgroup\$
0
1
\$\begingroup\$

I don't like it that one has to pass the size of the elements to the print_list function. Rather than print_list I would define:

genlist_foreach(&list_int, print_int);

To make this work, the list needs to know the size of its elements beforehands, therefore I would add that as a third field into the struct.

I would further drop the LIST_INT and LIST_CHAR types and only keep the generic list type. Just to keep the code simple.

When the list already knows its element size, it becomes possible to define this:

int genlist_add(PLIST_GEN list, const void *pelem) {
 if (list->numOfElements + 1 >= list->capacity) {
 reallocate more memory and return -1 in case of error
 }
 void *dst = ((char *)list->element) 
 + list->numOfElements * list->elementSize;
 memcpy(dst, pelem, list->elementSize);
 return 0;
}

You can then use the code like this:

int value = 3;
genlist_add(&list_int, &value);
value = 17;
genlist_add(&list_int, &value);
answered Jan 20, 2017 at 7:46
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.