C Generic Print Array function - printing String Array - c

I'm trying to write a generic printing arrays function in C and somehow it doesn't work well with a String array.
Here's the main:
#define LEN 20
typedef struct {
char name[LEN]; // worker's name
int salary; // worker's salary
char **childArr; // array of children names
int numChildren; // number of children
} Worker;
void printArray(void* arr, int size, int typeSize, void (*print)(void*));
void printString(void* s);
void printWorker(void* worker);
void main() {
// arrays of children's names
char *chBamba[] = { "Bambale1", "Bamb2", "Bamb3", "Bambook4", "Bambookle5" };
char *chBisli[] = { "Bislile1", "Bischick2", "Bislile3", "Bis4"};
int nBamba = sizeof(chBamba) / sizeof(*chBamba);
int nBisli = sizeof(chBisli) / sizeof(*chBisli);
// array of workers
Worker a[] = { {"Printf", 10, NULL, 0}, {"Bisli", 20, chBisli, nBisli},
{"TapooChips", 3, chBamba, nBamba}, {"Bamba", 19, chBamba, nBamba} };
printArray(a, sizeof(a)/sizeof(Worker), sizeof(Worker), printWorker);
}
And the functions:
void printArray(void* arr, int size, int typeSize, void (*print)(void*)) {
int i;
for (i = 0; i < size; i++) {
print((char*)arr+i *typeSize);
}
printf("\n");
}
void printString(void* s) {
char* str = (char*)s;
printf("[ %s ]", *str);
}
void printWorker(void* worker) {
Worker* w = (Worker*)worker;
printf("%s\t %d...(%d) ", w->name, w->salary, w->numChildren);
if (w->numChildren != 0)
printArray(w->childArr, w->numChildren, LEN, printString);
printf("\n");
}
After printing the data of the second worker and going to the "children" array, the code breaks...
any idea why? and how can i fix it?
after editing this: printArray(w->childArr,w->numChildren,sizeof(w->childArr[0]),printString);
and this: printf("[ %s ]",str);
i now have the following print:
img1

This line here:
printArray(w->childArr,w->numChildren,LEN,printString);
You pass LEN as the size of the element in the array, which is probably way bigger than the size of an array element. This makes the loop in printArray go outside the array boundaries, where any access is undefined behavior.
Your array contains pointers to strings. You need to pass sizeof(char*). Or, in a more D.R.Y manner:
printArray(w->childArr, w->numChildren, sizeof w->childArr[0], printString);
Your printString function does the wrong type conversion. You must remember that printArray passes a pointer to the current element into the callback. Since your iterate over an array of char*, it will pass a char**. With that in mind:
void printString(void *vpStr) {
char **pStr = vpStr;
printf("[ %s ]", *pstr);
}

Just for reference, the method you are using is how this is traditionally done in C. But in modern C you can write such generic functions in a better way: type safe and without the need for function pointers:
#include <stdio.h>
#include <string.h>
#define print_array(data, n) \
_Generic((*data), \
int: print_int, \
char: print_char)(data,n) \
void print_int (const int* data, size_t n)
{
for(size_t i=0; i<n; i++)
{
printf("%d ", data[i]);
}
}
void print_char (const char* data, size_t n)
{
for(size_t i=0; i<n; i++)
{
printf("%c ", data[i]);
}
}
int main (void)
{
int int_array [3] = {1, 2, 3};
const char* char_array = "hello world";
print_array(int_array, 3);
printf("\n");
print_array(char_array, strlen(char_array));
printf("\n");
}

Related

two functions (read and display an array) using pointers to structures

I just start to learn pointers to structures and I'm confused.I have to create a type of data ARRAY (which is associated with an array which contains integers.) like a structure which contains: numbers of array's elements and the array's elements stored in a part of memory(heap), dynamically allocated.
So I wrote:
typedef struct ARRAY
{
int nrElem; // number of elements
int *v[100];
};
Now I need to create 2 functions, one for reading an array from keyboard and the second one to display it using the structure I declared.
I tried but I get stuck.
void arrayDisplay(ARRAY *ps)
{
int i;
for(i=0;i<pd->nrElem;++i)
{
printf("%d",)
}
}
void readArray(ARRAY *ps)
{
int i;
for(i=0;i<pd->nrElem;++i)
{
printf("%d",)
scanf("%d",&);
}
}
How to continue?
Instead of an array of pointers int *v[100]; you need an array of ints int v[100]; in your data structure.
See code below:
#include <stdio.h>
#include <stdlib.h>
typedef struct ARRAY
{
int nrElem; // number of elements
int v[100];
} ARRAY;
void arrayDisplay(ARRAY *ps)
{
int i;
for(i=0;i<ps->nrElem;++i)
{
printf("%d\n", ps->v[i]);
}
}
void readArray(ARRAY *ps)
{
int i;
for(i=0;i<ps->nrElem;++i)
{
printf("%d: ", i);
scanf("%d",&ps->v[i]);
}
}
int main()
{
ARRAY a;
a.nrElem = 5;
readArray(&a);
arrayDisplay(&a);
return 0;
}
If you really want to use an array of int pointers you need to allocate the array first. And a different level of redirection for printf and scanf. But I'm not sure why you want to allocate memory for an integer array like this.
typedef struct ARRAY
{
int nrElem; // number of elements
int *v[100];
} ARRAY;
void arrayDisplay(ARRAY *ps)
{
int i;
for(i=0;i<ps->nrElem;++i)
{
printf("%d\n", *ps->v[i]);
}
}
void readArray(ARRAY *ps)
{
int i;
for(i=0;i<ps->nrElem;++i)
{
printf("%d: ", i);
scanf("%d",ps->v[i]);
}
}
int main()
{
ARRAY a;
int i;
a.nrElem = 5;
for(i=0;i<a.nrElem;++i) {
a.v[i] = (int*)malloc(sizeof(a.v[i]));
}
readArray(&a);
arrayDisplay(&a);
return 0;
}

when compiling I get this error, I do not know what is wrong

I'm passing a matrix to a text file
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int llenarMatriz() {
int matriz[3][3]={1,2,3,4,5,6,7,8,9};
return matriz[3][3];
}
void guardarMatriz(int matriz[3][3]) {
char direccion[]="C:\\Users\\Usuario\\Desktop\\DIBU.txt";
FILE *archivo = fopen(direccion, "w");
if (archivo == NULL) {
exit(EXIT_FAILURE);
}
char linea[20];
sprintf(linea, "%d %d\n", 3, 3);
fputs(linea, archivo);
for (int i = 0; i < 3; i++) {
linea[0] = '\0';
for (int j = 0; j < 3; j++){
char buffer[10];
sprintf(buffer, "%d ", matriz[3][3]);
strcat(linea, buffer);
}
int len = strlen(linea);
linea[len - 1] = '\n';
fputs(linea,archivo);
}
fclose(archivo);
}
int main() {
llenarMatriz();
guardarMatriz(int matriz[3][3]);
system("pause");
return 0;
}
Error message;
In function 'main':
error: expected expression before 'int'
guardarMatriz(int matriz[3][3]);
You have two problems in your code. First you don't initialize a 2-D array correctly. It should look like this:
int matriz[3][3]={{1,2,3},{4,5,6},{7,8,9}};
second, you don't pass a type name to the function call to declare your variable, so it should look like this:
int matriz[3][3];
llenarMatriz();
guardarMatriz(matriz);
guardarMatriz(int matriz[3][3]);
Don't include the type and the dimensions when passing parameters to a function.
Also, when you call a function returning something, you should use the correct type (an int is not able to return a 2D array of int), and you must store the return somewhere.
In this case you can return a compound literal:
void *llenarMatriz(void)
{
return (int [][3]){{1,2,3},{4,5,6},{7,8,9}};
}
and in main:
int main(void) /* void is the correct argument for `main` */
{
int (*matriz)[3] = llenarMatriz(); /* A pointer to an array of int 3 */
guardarMatriz(matriz);
system("pause");
return 0;
}
If you don't want to declare the array inside main you can use the result of the first function as the argument of the second one:
guardarMatriz(llenarMatriz());
or you can pass the compound literal directly:
guardarMatriz((int [][3]){{1,2,3},{4,5,6},{7,8,9}});

Trouble assigning value of array element via pointers

I'm having trouble with a certain "program flow" that I'm trying to implement.
The output in the following MWE is supposed to say "Sum: 10" but it says "Sum: 0" because the function set_array_element does not set array elements. Why doesn't it?
#include <stdio.h>
#include <stdlib.h>
typedef struct example example;
struct example {
int nrOf;
double a[];
};
void initialize_example_array(example *e);
void set_array_element(double *el);
example new_example(int nrOf)
{
example *e = malloc(sizeof(example) + nrOf*sizeof(double));
e->nrOf = nrOf;
initialize_example_array(e);
return *e;
}
void initialize_example_array(example *e)
{
printf("%d\n", e->nrOf);
for(int i=0; i<e->nrOf; i++)
{
set_array_element(&e->a[i]);
}
}
void set_array_element(double *el)
{
*el = 1;
}
int main(int argc, const char * argv[]) {
example e = new_example(10);
printf("%d\n", e.nrOf);
int i, s=0;
for(i=0; i<e.nrOf; i++)
{
printf("%f\n", e.a[i]);
s+= e.a[i];
}
printf("Sum: %d\n", s);
return 0;
}
The flexible array member, this is the member a of struct example, is not a pointer. It's address is calculated using the address of the struct.
A struct with a flexible array member cannot be assigned using the simple assignment operator, like it is done in your example:
example e = new_example(10);
where the function returns:
return *e;
You will have to return the pointer:
example* new_example(int nrOf)
{
example *e = malloc(sizeof(example) + nrOf*sizeof(double));
e->nrOf = nrOf;
initialize_example_array(e);
return e;
}
example* e = new_example(10);
printf("%d\n", e->nrOf);
...

Can we use void pointer of arrays

I am just working on a liberty functions in which we define our own datatypes for student and book I have to write a code which finds student by id and book by id these are the two functions. In this functions the pointers which I pass are different but the logic is the same so I got a though that why can't we write one function and pass which thing we want. I mean when we pass the student list it will return the index of student when we pass the book list it will return the book index of the book. Can we use void pointers for that??? Thank you everyone!!!
int findBookId(Book* booklist,int* bcount,unsigned int* tbid)
{
int i;
for (i=0; i<*bcount; i++)
{
if (booklist[i].id==*tbid)
{
return i;
}
}
return NOT_FOUND;
}
int findStuId(Student* stulist,int* scount,unsigned int* tsid)
{
int i;
for (i=0; i<*scount; i++)
{
if (stulist[i].id==*tsid)
{
return i;
}
}
return NOT_FOUND;
}
Assuming you have a student structure:
struct student {
int id;
char name[20];
};
You can imitate qsort() function, to design a parameter to receive a callback function and to receive the size and size of each element if you'd like use void *.
int find_ele(void *base, size_t num, size_t width,
int (*equal)(const void *, const void *),
void *param)
{
int i;
for (i = 0; i < num; ++i) {
if (equal((char *) base + i * width, param)) {
return i;
}
}
return -1;
}
Then, define a "tester":
int student_tester(const void *p1, const void *p2)
{
struct student *sp = (struct student *) p1;
int id = *(int *) p2;
return sp->id == id;
}
In main() function:
int main(void)
{
struct student student_list[] = {
0, "A",
1, "B",
2, "C"
};
int id = 2;
int index = find_ele(student_list, sizeof student_list,
sizeof(struct student), student_tester, &id);
if (index != -1) {
printf("find_ele(id=2) = student_list[%d]; name = %s. \n",
index, student_list[index].name);
} else {
printf("Not found. \n");
}
return 0;
}
This is a bit complicated. You can create macros to simplify it if you don't care.
Rename find_ele to _find_ele, and create a macro:
#define find_ele(base, num, compare, param) _find_ele(base, \
num / sizeof base[0], \
sizeof base[0], \
compare, param)
And create another macro to define a "tester":
#define define_tester(name, type, type_to_find, code) \
int name(const void *_p, const void *param) { \
type *p = (type *) _p; \
type_to_find value = *(type_to_find *) param; \
return (code); \
}
Now you can define a "tester" like this:
define_tester(student_tester, struct student, int,
p->id == value);
Complete code:
#include <stdio.h>
int _find_ele(void *base, size_t num, size_t width,
int (*equal)(const void *, const void *),
void *param)
{
int i;
for (i = 0; i < num; ++i) {
if (equal((char *) base + i * width, param)) {
return i;
}
}
return -1;
}
#define find_ele(base, num, compare, param) _find_ele(base, \
num / sizeof base[0], \
sizeof base[0], \
compare, param)
#define define_tester(name, type, type_to_find, code) \
int name(const void *_p, const void *param) { \
type *p = (type *) _p; \
type_to_find value = *(type_to_find *) param; \
return (code); \
}
struct student {
int id;
char name[20];
};
define_tester(student_tester, struct student, int,
p->id == value);
int main(void)
{
struct student student_list[] = {
0, "A",
1, "B",
2, "C"
};
int id = 2;
int index = find_ele(student_list, sizeof student_list, student_tester, &id);
if (index != -1) {
printf("find_ele(id=2) = student_list[%d]; name = %s. \n",
index, student_list[index].name);
} else {
printf("Not found. \n");
}
return 0;
}
Yes you can use void*, but while dereferencing you should know the exact type of the pointer.
So, when you can your function, add another parameter:
type = 0 for Books
= 1 for students
And then your function becomes:
int findId(void* list,int* count,unsigned int* tbid, int type)
{
Book* booklist=NULL;
Student* stulist=NULL;
int i;
if(type===0)
booklist = (Book*) list;
else if(type==1)
stulist = (Student*) list;
else
// Handle this undefined case
// And now use the same type variable to decide which pointer to use to match the values
. . . .
}
Yes you can use void pointer, if you are trying to store address of your array..Your array may contain integer types or some other datatypes stored, it doesn't matter, but right typecasting while de-referencing the void pointer is important.
I don't think you can use void* in these functions.
If you changed your functions to one and created something like:
int findObjId(void* objlist,int* count, unsigned int* objid)
{
int i;
for (i=0; i<*scount; i++)
{
if (objlist[i].id==*objid)
{
return i;
}
}
return NOT_FOUND;
}
you won't be able to extract the data from objlist. Neither *objlist, nor objlist[i] can be dereferenced to evaluate to an object. The compiler will definitely stop you from using any such statement.
If you have the option, switch to C++. Using templates, you can accomplish your goal without breaking a sweat.

Why can't function access generic parameter

I am slowly learning how to program generic functions in C and get into trouble now and so often. I am making a program that makes a union of two arrays, in this implementation two int arrays. The first problem, which also leads to the second one, is that the compareints (function) does not access one of the passed arguments (void *): I can't figure out why? I been staring at the screen for to long time now...
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//makes union of two generic arrays and eliminates duplicates if there are some...
void **
unite(int (*comp)(void *f, void *s), void **first, void **second, int f_size, int s_size, int bytes, int *x)
{
int i;
void **arr=malloc(bytes*(f_size+s_size));
for(i=0; i<f_size+s_size; i++)
{
/* first bigger */
if(((*comp)(*first, *second))>0)
{
*(arr+i)=*(first++);
}
/* second bigger */
else if(((*comp)(*first, *second))<0)
{
*(arr+i)=*((second++));
}
/* equal => just one copy */
else
{
*(arr+i)=*(first++);
second++;
}
}
*x=i;
return arr;
}
int
compareints(void *first, void *second)
{
if(*((int *)first)>*((int *)second)) //can't access the memoryloc in second...
return 1;
else if(*((int *)first)<*((int *)second))
return -1;
else
return 0;
}
int main(int argc, const char * argv[])
{
int arr[10]={1, 2, 4, 12, 22, 29, 33, 77, 98};
int arr2[5]={3, 5, 7, 8, 9};
void **first=malloc(sizeof(int *)*10);
void **second=malloc(sizeof(int *)*5);
//make pointers to static arrays in dynamic arrays
int f_ind, s_ind;
for(f_ind=0; f_ind<10; f_ind++)
first[f_ind]=&arr[f_ind];
for(s_ind=0; s_ind<5; s_ind++)
second[s_ind]=&arr2[s_ind];
int i;
//make union of the two arrays and print out the result
void **ret=unite(&compareints, first, second, 10, 5, sizeof(int), &i);
for(int k=0; k<i; k++)
printf("%d ", *((int *)ret[k]));
return 0;
}
Why can't function access generic parameter ?
Simple answer to this question is function can access but further manipulation on void * is not possible.
Elements are accessed using pointer arithmetic (which needs size of individual element) since the pointer which is void * pointing to the address you passed but doesn't know about the size of each field in that array or memory location. so accessing or dereferencing will lead you to Undefined Behaviour.
If you want to access each element of that type inside the function then , pass the size of individual element to that function and on that basis make pointer to that same type , then access using new pointer of that type.
For more read this
I tried an approach thanks to #WhozCraigs post about the index going out of bounds. So I made some small mods and now the program does what it intends to.
void **
unite(int (*comp)(void *f, void *s), void **first, void **second, int f_size, int s_size, int bytes, int *x)
{
int i;
int f_ind=0, s_ind=0;
void **arr=malloc(bytes*(f_size+s_size));
for(i=0; i<f_size+s_size; i++)
{
/* first bigger */
if(((*comp)(*first, *second))>0)
{
s_ind++;
if(s_ind<s_size)
*(arr+i)=*(second++);
else
{
f_ind++;
if(f_ind<f_size)
*(arr+i)=*(first++);
else
break;
}
}
/* second bigger */
else if(((*comp)(*first, *second))<0)
{
f_ind++;
if(f_ind<f_size)
*(arr+i)=*(first++);
else
{
s_ind++;
if(s_ind<s_size)
*(arr+i)=*(second++);
else
break;
}
}
/* equal => just one copy */
else
{
f_ind++;
s_ind++;
if(f_ind<f_size && s_ind==s_size)
{
*(arr+i)=*(first++);
}
else if(f_ind==f_size && s_ind<s_size)
{
*(arr+i)=*(second++);
}
else
{
*(arr+i)=*(first++);
second++;
}
}
}
*x=i;
return arr;
}

Resources