No Matching Function Call To:

Hello fellow programmers,

I am making a program to input a student's information (name and birthday) and his/her grade in percent, and will display it, including letter grade. It was working fine before I wanted to verify if the person's name had a number. The errors I am getting occur on line 45 and 63. The error is
"No matching function for call to 'verifyString'"

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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#include <iostream>
#include <cstring>
#include <cctype>
using namespace std;

struct Person
{
    string lastName, firstName;
};

struct GradeRec
{
    float percent;
    char grade;
};

struct Student
{
    Person name;
    int birthYear, birthMonth, birthDay;
    GradeRec courseGrade;
};

void printStudent (Student student[], int count);
void assignGrade (Student student[], int count);
bool verifyString (char *);

int main()
{
    int count = 0, i;
    
    struct Student person[30];
    

    do
    {
        for (i = 0; i < 30; i++)
        {
            cout << "What is student #" << count + 1 << "'s first name? (q to quit if you are done entering at least one student)" << endl;
            cin >> person[i].name.firstName;
            count++;
            
            const char *firstName = person[i].name.firstName.c_str();
            
            while (!verifyString(firstName))
            {
                cout << "Not a valid name. Try again: ";
                cin >> person[i].name.firstName;
                firstName = person[i].name.firstName.c_str();
            }
        
            if ((person[i].name.firstName == "q" || person[i].name.firstName == "Q") && count >= 1)
            {
                count--;
                goto stop;
            }
            
            cout << "What is " << person[i].name.firstName << "'s last name? " << endl;
            cin >> person[i].name.lastName;
            
            const char *lastName = person[i].name.lastName.c_str();
            
            while (!verifyString(lastName))
            {
                cout << "Name can not contain numbers. Try again: ";
                cin >> person[i].name.lastName;
                lastName = person[i].name.lastName.c_str();
                cout << endl;
            }
            
            cout << "What is " << person[i].name.firstName << "'s grade? (in percent)?" << endl;
            cin >> person[i].courseGrade.percent;
            
            while (cin.fail())
            {
                cout << "Not a valid grade. Try again: ";
                cin >> person[i].courseGrade.percent;
                cout << endl;
            }
            
            cout << "What is " << person[i].name.firstName << "'s birthday? (enter as mm dd yyyy, eg 7 26 2004) " << endl;
            cin >> person[i].birthMonth >> person[i].birthDay >> person[i].birthYear;
            
            while (cin.fail())
            {
                cout << "Not a valid birth date. Try again: ";
                cin >> person[i].birthMonth >> person[i].birthDay >> person[i].birthYear;
                cout << endl;
            }
            
            cout << "Thank you.\n" << endl;
        }
    } while ((person[i].name.firstName != "q" || person[i].name.firstName != "Q") && count <= 30);
    
    stop:
    assignGrade(person, count);
    printStudent(person, count);

    cout << "Thanks for using this application! " << endl;
}

void assignGrade (Student student[], int count)
{
    for (int i = 0; i < count; i++)
    {
        if (student[i].courseGrade.percent > 89)
            student[i].courseGrade.grade = 'A';
    
        else if (89 >= student[i].courseGrade.percent && student[i].courseGrade.percent > 79)
            student[i].courseGrade.grade = 'B';
    
        else if (79 >= student[i].courseGrade.percent && student[i].courseGrade.percent > 69)
            student[i].courseGrade.grade = 'C';
    
        else if (69 >= student[i].courseGrade.percent && student[i].courseGrade.percent > 59)
            student[i].courseGrade.grade = 'D';
    
        else
            student[i].courseGrade.grade = 'F';
    }
}

void printStudent (Student student[], int count)
{
    for (int j = 0; j < count; j++)
    {
        cout << "Student #" << j + 1 << ": " << endl;
        cout << "Name: " << student[j].name.firstName << " " << student[j].name.lastName << endl;
        cout << "Birthdate: " << student[j].birthMonth << "/" << student[j].birthDay << "/"
             << student[j].birthYear << endl;
        cout << "Grade (percent): " << student[j].courseGrade.percent << "%" << endl;
        cout << "Grade (letter): " << student[j].courseGrade.grade << endl << endl;
    }
}

bool verifyString (char *pass)
{
    bool isDigit = false;
    int i = 0;
    int length = strlen(pass);
    
    for (i = 0; i < length; i++)
    {
        if (isdigit(pass[i]))
            isDigit = true;
    }
    
    return isDigit;
}


Thanks,
VX

PS
I'm also getting an error Implicit conversion loses integer precision: 'size_t' (aka 'unsigned long') to 'int' on line 140

PPS
I'm running in XCode
Last edited on
Line 43, you declare a variable of type const char *, but the function verifyString has a parameter of type char *.

Since the function does not modify the string, you can make that clear in the function declaration, by making the parameter a const.

Change lines 26 and 136
 
bool verifyString (const char *)


Implicit conversion loses integer precision: 'size_t' (aka 'unsigned long') to 'int'

This is usually harmless, it is a warning that the signed integer uses one less bit of precision than an unsigned integer (the most significant bit is used for the sign). A simply fix is to change lines 139, 140
1
2
    int i = 0;
    int length = strlen(pass);
to
1
2
    size_t i = 0;
    size_t length = strlen(pass);


size_t is defined in one of the header files, usually an alias for an unsigned integer large enough to hold any required value, it is used to represent values which are the size of something.
There is redundancy in the use of nested loops and testing the same things more than once.

At line 37:
 
    for (i = 0; i < 30; i++)

At line 52:
 
    if ((person[i].name.firstName == "q" || person[i].name.firstName == "Q") && count >= 1)

That's all ok.

However, at line 93
 
     } while ((person[i].name.firstName != "q" || person[i].name.firstName != "Q") && count <= 30);

Some of those same things are tested for all over again. See the "Q", "q" and 30.

You can remove the outer loop and those extra tests. Incidentally that also makes the goto redundant too.
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include <iostream>
#include <string>
#include <cctype>

using namespace std;

struct Person
{
    string lastName, firstName;
};

struct GradeRec
{
    float percent;
    char grade;
};

struct Student
{
    Person name;
    int birthYear, birthMonth, birthDay;
    GradeRec courseGrade;
};

void printStudent (Student student[], int count);
void assignGrade (Student student[], int count);
bool verifyString (const std::string & s);

int main()
{
    const int size = 30;            
    struct Student person[size];

    int count = 0;
    
    for (count = 0; count < size; count++)
    {
        Student & stu = person[count];
        
        cout << "What is student #" << count + 1 << "'s first name?" 
             << "(q to quit if you are done entering at least one student)" << endl;
        cin >> stu.name.firstName;
       
        if ((stu.name.firstName == "q" || stu.name.firstName == "Q") && count >= 1)
            break;
                    
        while (verifyString(stu.name.firstName))
        {
            cout << "Name can not contain numbers. Try again: ";
            cin >> stu.name.firstName;
        }
            
        cout << "What is " << stu.name.firstName << "'s last name? " << endl;
        cin >> stu.name.lastName;
                
        while (verifyString(stu.name.lastName))
        {
            cout << "Name can not contain numbers. Try again: ";
            cin >> stu.name.lastName;
        }
            
        cout << "What is " << stu.name.firstName << "'s grade? (in percent)?" << endl;
        while (!(cin >> stu.courseGrade.percent))    
        {
            cin.clear();
            cin.ignore(1000, '\n');
            cout << "Not a valid grade. Try again: ";
        }
            
        cout << "What is " << stu.name.firstName << "'s birthday?" 
             << "(enter as mm dd yyyy, eg 7 26 2004) " << endl;
        while (!(cin >> stu.birthMonth >> stu.birthDay >> stu.birthYear))
        {
            cin.clear();
            cin.ignore(1000, '\n');
            cout << "Not a valid birth date. Try again: ";
        }
            
        cout << "Thank you.\n" << endl;   
    }
    
    assignGrade(person, count);
    printStudent(person, count);

    cout << "Thanks for using this application! " << endl;

}

void assignGrade (Student student[], int count)
{
    for (int i = 0; i < count; i++)
    {
        if (student[i].courseGrade.percent > 89)
            student[i].courseGrade.grade = 'A';
    
        else if (89 >= student[i].courseGrade.percent && student[i].courseGrade.percent > 79)
            student[i].courseGrade.grade = 'B';
    
        else if (79 >= student[i].courseGrade.percent && student[i].courseGrade.percent > 69)
            student[i].courseGrade.grade = 'C';
    
        else if (69 >= student[i].courseGrade.percent && student[i].courseGrade.percent > 59)
            student[i].courseGrade.grade = 'D';
    
        else
            student[i].courseGrade.grade = 'F';
    }
}

void printStudent (Student student[], int count)
{
    for (int j = 0; j < count; j++)
    {
        cout << "Student #" << j + 1 << ": " << endl;
        cout << "Name: " << student[j].name.firstName << " " << student[j].name.lastName << endl;
        cout << "Birthdate: " << student[j].birthMonth << "/" << student[j].birthDay << "/"
             << student[j].birthYear << endl;
        cout << "Grade (percent): " << student[j].courseGrade.percent << "%" << endl;
        cout << "Grade (letter): " << student[j].courseGrade.grade << endl << endl;
    }
}

bool verifyString (const std::string & s)
{
    for (char c : s)
        if (isdigit(c))
            return true;
    return false;
}
Last edited on
Wow, thanks! That helped a lot. Now I want to verify that the name doesn't contain special characters (!, @, #, etc.). How can I do that?

Thanks,
VX
Last edited on
verify that the name doesn't contain special characters

Would it be correct to assume that only alphabetic characters (a-z and A-Z) are permitted? What about spaces? Are any other characters allowed?

If it is just alphabetic, then use the isalpha() function. The logic will be the opposite though, since that would be a switch from checking what is not wanted , to checking what is wanted.

1
2
3
4
5
6
7
bool verifyString (const std::string & s)
{
    for (char c : s)
        if (!isalpha(c))  // note the ! (not)
            return true;
    return false;
}


Wow! Thanks for the reply. Now, it works perfectly fine, but I was just curious about one thing.
On line 38, you write this:

 
Student & stu = person[count];


What is the & symbol for and what does it do?

Thanks,
VX
What is the & symbol for and what does it do?

The & operator here is used to declare a reference.
Effectively it makes the variable an alias for another variable.

In the example above, it is entirely optional, I was trying to make the code a little shorter and more readable, it simply allows in this case something with a long and cumbersome name to be given a shorter name, purely for convenience.
Here's a brief example. Below there is an integer variable a. The variable c is not really a separate integer, it is another way of referring to a.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>

using namespace std;

int main()
{
    int a = 4;
    int &c = a;
    
    cout << "a = " << a << "\nc = " << c << "\n\n";
    
    c = 16;
    
    cout << "a = " << a << "\nc = " << c << "\n\n";
    
    a = 3;
    
    cout << "a = " << a << "\nc = " << c << "\n\n";
    
}
a = 4
c = 4

a = 16
c = 16

a = 3
c = 3


See tutorial

http://www.cprogramming.com/tutorial/references.html

Note, there is another somewhat different use of the & operator when using pointers, but I won't go into that here, it could add confusion.

One other part which could be improved:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void assignGrade (Student student[], int count)
{
    for (int i = 0; i < count; i++)
    {
        if (student[i].courseGrade.percent > 89)
            student[i].courseGrade.grade = 'A';
    
        else if (89 >= student[i].courseGrade.percent && student[i].courseGrade.percent > 79)
            student[i].courseGrade.grade = 'B';
    
        else if (79 >= student[i].courseGrade.percent && student[i].courseGrade.percent > 69)
            student[i].courseGrade.grade = 'C';
    
        else if (69 >= student[i].courseGrade.percent && student[i].courseGrade.percent > 59)
            student[i].courseGrade.grade = 'D';
    
        else
            student[i].courseGrade.grade = 'F';
    }
}


At line 5 the if tests for percent > 89. If the condition is true, the grade is set to 'A'.
If it is false, we know that percent is <= 89. Hence in the else condition at line 8, the test for
 
89 >= student[i].courseGrade.percent
is unnecessary duplication - and can even be a cause of errors, sometimes this style of coding can leave gaps where some values are not accounted for.

It is good practice to remove those extra checks, the code will look like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void assignGrade (Student student[], int count)
{
    for (int i = 0; i < count; i++)
    {
        if (student[i].courseGrade.percent > 89)
            student[i].courseGrade.grade = 'A';
    
        else if (student[i].courseGrade.percent > 79)
            student[i].courseGrade.grade = 'B';
    
        else if (student[i].courseGrade.percent > 69)
            student[i].courseGrade.grade = 'C';
    
        else if (student[i].courseGrade.percent > 59)
            student[i].courseGrade.grade = 'D';
    
        else
            student[i].courseGrade.grade = 'F';
    }
}

Ok, thanks!
Looks like the date entry section has grown a bit complex. There are error messages issued in three different places, lines 97, 104, 111, and no less than three while loops. That suggests something could be simplified. There are a couple of minor issues, the call to isleapyear() at line 101 doesn't do anything useful (nothing is done with the result).

Another problem there are two sets of cin >> statements here:
105
106
107
            cin >> stu.birthMonth >> stu.birthDay >> stu.birthYear;
            
            while (!(cin >> stu.birthMonth >> stu.birthDay >> stu.birthYear)) 
That actually means the program doesn't lock up. What happens is the user enters the date at line 105, and the program sits there waiting for it to be entered all over again at line 107.

The logic needs a bit of a rethink, there are two main situations which need to be tested
1. invalid input such as alphabetic character when number is expected.
2. valid input but the date itself is not valid

This should work:
89
90
91
92
93
94
95
96
97
        cout << "What is " << stu.name.firstName << "'s birthday?" 
             << "(enter as mm dd yyyy, eg 7 26 2004) " << endl;
        while ( !(cin >> stu.birthMonth >> stu.birthDay >> stu.birthYear) 
            || (cin && !valid_date(stu.birthYear, stu.birthMonth, stu.birthDay)) )
        {
            cin.clear();
            cin.ignore(1000, '\n');
            cout << "Not a valid birth date. Try again: ";
        }
Thank you for all you have done on this topic Chervil! I turned in this assignment yesterday and my teacher was very impressed!

Thanks,
VX
Last edited on
Thanks. Though my goal here is to try to help you learn some of this stuff, if your teacher is pleased but you are still confused then I failed. Time will tell I suppose...
No, no, no, you did very well Chervil. You have helped so much.
Topic archived. No new replies allowed.