2

I want to create an array of structs based on one struct definition, and initialize each one with a different int value.

Then, I want to print this value, using a function pointer that points to a print function.

  • Define a struct (includes an int and a function pointer).

  • create an array of 10 structs of the same definition.

  • set different values for each one of them.

  • send this value for a function that is pointed to by a function
    pointer that is also located in the struct

This is my code:

#include <stdio.h>
#include <stdlib.h>
#define ARRAY_SIZE 10

void Print(int num);

typedef struct print_me
{
    int x;
    void (*Print)(int x);
};
    
struct print_me my_prints[ARRAY_SIZE];

int main()
{
    size_t i = 0;
    for (i = 0; i < ARRAY_SIZE; ++i)
    {
        my_prints[i].x = i;
        my_prints[i].Print(my_prints[i].x);
    }
    return 0;
}

void Print(int num)
{
    printf("%d\n",num);
}

I'm still learning the ideas of function pointer and structs , so I'll be glad to get some tips and suggestions that will help me to understand my mistakes here.

Thanks.

NoobCoder
  • 513
  • 3
  • 18

2 Answers2

2

As with usual pointers, you have to set a pointer value before you can use it. So that it points somewhere.

Add:

my_prints[i].Print = &Print;
// or, it means the same, & is optional
// my_prints[i].Print = Print;
my_prints[i].Print(my_prints[i].x); // now ok

before calling my_prints[i].Print() so that the pointer will point to function Print before calling it.

Side note with a fun fact: because of the strange C rules, dereferencing the function pointer is not needed, and you can even like "dereference" the function pointer multiple times, like (****my_prints[i].Print)(). See ex this question.

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
2

For starters there is no any sense to use the typedef specifier in this declaration

typedef struct print_me
{
    int x;
    void (*Print)(int x);
};

without specifying a typedef name. You could write for example

typedef struct print_me
{
    int x;
    void (*Print)(int x);
} print_me;

In the for loop you need to initialize the data member Print with the address of the function Print. For example

for (i = 0; i < ARRAY_SIZE; ++i)
{
    my_prints[i].x = i;
    my_prints[i].Print = Print;
}

then in a second for loop you could call the function like

for (i = 0; i < ARRAY_SIZE; ++i)
{
    my_prints[i].Print( my_prints[i].x );
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Thanks. Why won't it work if i'll add the `my_prints[i].Print( my_prints[i].x );` right after the 2 initializing lines, and sum it up with only one loop? **EDIT**: it worked with only one loop by adding the printing line after the first initializing lines – NoobCoder Feb 25 '21 at 10:17
  • @NoobCoder You can do it. But it is better when code is logically separated into parts that perform one task. In this case the code will be more readable compared with a code where all the logic is placed in one heap. – Vlad from Moscow Feb 25 '21 at 10:19
  • Thanks. Could I use instead of `for loop` a `while (*my_prints)` ? – NoobCoder Feb 25 '21 at 10:22
  • @NoobCoder The array does not contain a sentinel value. You could use for example a while loop like while ( i < ARRAY_SIZE ) and within the loop increase the variable i. – Vlad from Moscow Feb 25 '21 at 10:32