pointers to function in a struct and functions calls (display info about student struct)

So I have an exercise in C++. I have a structure student with the following members: 1 int, 2 char, 1 float and (I write the lines from the exercise): "two pointers on functions for reading data void (*read)(student*st) and one pointer for displaying data void (*write)(student*st) "

I have to read from keyboard the number of students and then to allocate memory for an array with students.

Then I have to define 2 functions: void readData(student* st) and void writeData(student* st) which read and display the members of one student structure. I have to go through students array and to initialize the pointers to functions void (*read)(student*st) and void (*write)(student*st) with void readData(student* st) and void writeData(student* st). Here I am a little bit confused.

The last thing I need to do is to go through students array and to call the functions v[i].read(&v[i]) and v[i].write(&v[i]) to read and display data.

Here is my code:

HEADER
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 #pragma once

struct student {
	int nrID;
	char name[100];
	char gender[20];
	float mark;
	void(*read)(student* st);
	void(*write)(student* st);
};

void readStudents(int n);
void readData(student* st);
void writeData(student* st);


FUNCTIONS FILE

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
#include "header.h"

using namespace std;

void readStudents(int n) {
	cout << "Number of students: ";
	cin >> n;
	student *v;
	v = new student[n]; // here I allocate the students array
	/*
	for(int i=0; i<n; ++i) {
		v[i].read(??) = readData(&v[i]);
		v[i].write(??) = writeData(&v[i]);
	}
	*/ // Here I am confused. I'm not sure if I initialized the pointers to function in a right way.
	
	for (int i = 0; i<n; ++i) {
		v[i].read(&v[i]);
		v[i].write(&v[i]);
	}
}
// below I created 2 functions which read and display the members of one student struct.
void readData(student* st) {
	cout << "Enter the nrId: ";
	cin >> st->nrID;

	cout << "Enter the name: ";
	cin >> st->name;

	cout << "Enter the gender: ";
	cin >> st->gender;

	cout << "Enter the mark: ";
	cin >> st->mark;
}

void writeData(student* st) {
	cout << "Id number: " << st->nrID << endl;
	cout << "Name: " << st->name << endl;
	cout << "Gender: " << st->gender << endl;
	cout << "Mark: " << st->mark << endl;
}


MAIN FILE
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include "header.h"

using namespace std;

int main()
{
	int n;
	readStudents(n);
	return 0;
}


I compile the code in Code Block and all I have is "Number of students:" the the program crashes.
How to fix those pointers initializations?
Last edited on
First, a suggestion: n should not a parameter of your readStudents function, because you only use it as a local variable. Just declare the variable locally within the function.
1
2
3
4
void readStudents() {
    int n;
    // ...
}

or, ask for user input via cin >> in main, and then pass the n value, but don't ask again within your function.

Additionally, you used new[] to allocate an array, but you never called delete[] on that memory. You have a memory leak. Consider using std::vector in the future; it is essentially an array but will manage the memory for you.

To assign to a variable that holds a function pointer, you'd do something like:
1
2
    	v[i].read = readData;
    	v[i].write = writeData;
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
struct Student {
    int age;
    std::string name;
    void (*DoWork)(Student* student) = nullptr;
    static void (*Info)(Student* student); // Caution: The function assigned will be shared by ALL instances of Student
                                           // Caution: This is a declaration. You must provide a definition for the function pointer. 
                                           //          See https://stackoverflow.com/a/24622465/3396951
};

// Define the function pointer for Student class; Here it's initialized to nullptr.
// Remember to initialize the class function pointer before invoking it!
void (*Student::Info)(Student* student) = nullptr; 

void DoMath(Student* student)
{
    std::cout << student->name << ": Doing Math. y=mx+b.\n";
}

void DoPhysics(Student* student)
{
    std::cout << student->name << ": Doing Physics. E=mc^2.\n";
}

void DoHistory(Student* student)
{
    std::cout << student->name << ": Doing History. ZZZzzzz.\n";
}

void ShowFullInfo(Student* student)
{
    std::cout << "ShowFullInfo: Student Name: " << student->name << "\n";
    std::cout << "ShowFullInfo: Student  Age: " << student->age << "\n";
}

void ShowName(Student* student)
{
    std::cout << "ShowName: Student Name: " << student->name << "\n";
}

void InitStudentsArray()
{
    Student classroom[3]; // An array of 3 Student objects

    // Initialize members of each Student object
    classroom[0].name = "Alice";
    classroom[0].age = 20;
    classroom[1].name = "Bob";
    classroom[1].age = 21;
    classroom[2].name = "Cathy";
    classroom[2].age = 22;

    // Initialize each Student's function pointer (the work they do)
    classroom[0].DoWork = DoMath;   
    classroom[1].DoWork = DoPhysics;
    classroom[2].DoWork = DoHistory;

    // Invoke the function pointer
    classroom[0].DoWork(&classroom[0]);
    classroom[1].DoWork(&classroom[1]);
    classroom[2].DoWork(&classroom[2]);

    // Alice now decides to do history
    classroom[0].DoWork = DoHistory;
    classroom[0].DoWork(&classroom[0]);

    // Specify that the class method should display the name and age of each student
    Student::Info = ShowFullInfo; 

    Student::Info(&classroom[0]);  // Calls ShowFullInfo(Alice)
    Student::Info(&classroom[2]);  // Calls ShowFullInfo(Cathy)

    // Reassign what the class method should do; in this case, only display the name of the student passed as the argument
    Student::Info = ShowName; 

    Student::Info(&classroom[0]);  // Calls ShowName(Alice)
    Student::Info(&classroom[2]);  // Calls ShowName(Cathy)
   
    // You can't return classroom since it's a local array
}


Output:
1
2
3
4
5
6
7
8
9
10
Alice: Doing Math. y=mx+b.
Bob: Doing Physics. E=mc^2.
Cathy: Doing History. ZZZzzzz.
Alice: Doing History. ZZZzzzz.
ShowFullInfo: Student Name: Alice
ShowFullInfo: Student  Age: 20
ShowFullInfo: Student Name: Cathy
ShowFullInfo: Student  Age: 22
ShowName: Student Name: Alice
ShowName: Student Name: Cathy


This should show you how to assign a function to a function pointer and how to invoke the function pointer. DoWork() makes more sense as a member function to avoid passing the address of each Student.

The read and write function pointers look like they should be static (unless there is a reason you need each Student object to specify a different behavior of read/write).
Last edited on
Very nice, I was considering building an example like that, too, but didn't have the motivation. The history class is accurate.
Last edited on
Topic archived. No new replies allowed.