Validation Error

Hello all, I am having trouble with the following code. It should be validating whether or not the first letter of a name is alphabetic. However, when I enter an invalid name twice in a row, it accepts the answer the second time, but ignores the first letter.

Heres my output:

What would you like to do? 
1. Enter Person information 
1
What is person #1's name? 
(enter the full name)
8l
Name may not start with non-alphabetic letter. Try again: 
!l
What is l's age? 


It is disregarding the ! in the name for some reason.

Here's my code:
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include <iostream>
#include <cstring>
#include <cctype>
using namespace std;

class Person
{
    public:
        Person();
        Person(string pname, int page);
        string getName() const;
        void setName(string& pname);
        void setAge(int& page);
        int getAge() const;
    
    private:
        string name;
        int age;
};

bool validateString (const string & s);

int main()
{
    int input, count = 0, age;
    Person person[30];
    string name;
    bool didPrint = false;
    
    do
    {
        cout << "What would you like to do? " << endl;
        cout << "1. Enter Person information " << endl;
        
        if (count >= 1)
        {
            cout << "2. Print person information " << endl;
            cout << "3. Exit " << endl;
        }
        
        cin >> input;
        
        if (input == 3 && count >= 1)
            break;
        
        while (input != 1 && input != 2)
        {
            cin.clear();
            cin.ignore('1000', '\n');
            cout << "Invalid input. ";
            
            cout << "What would you like to do? " << endl;
            cout << "1. Enter Person information " << endl;
            
            if (count >= 1)
            {
                cout << "2. Print person information " << endl;
                cout << "3. Exit " << endl;
            }
            
            cin >> input;
            
            if (input == 3 && count >= 1)
                break;
        }
        
        if (input == 1)
        {
            cout << "What is person #" << count + 1 << "'s";
            person[count].setName(name);
            
            cout << "What is " << person[count].getName() << "'s age? " << endl;
            person[count].setAge(age);
        }
        
        else if (input == 2 && count >= 1)
        {
            for (int i = 0; i < count; i++)
            {
                cout << "Person #" << i + 1 << ": " << endl;
                cout << "Name: " << person[i].getName() << ". " << endl;
                cout << "Age: " << person[i].getAge() << "\n" << endl;
            }
            didPrint = true;
        }
        
        count++;
    } while (input != 3 && count <= 30);
    
    if (count == 30 || !didPrint)
    {
        for (int i = 0; i < count; i++)
        {
            cout << "Person #" << i + 1 << ": " << endl;
            cout << "Name: " << person[i].getName() << ". " 
                 << endl;
            cout << "Age: " << person[i].getAge() << ". \n" 
                 << endl;
        }
    }
    
    cout << "Bye! " << endl;
}

int Person::getAge() const
{
    return age;
}

string Person::getName() const
{
    return name;
}

void Person::setName(string& pname)
{
    cout << " name? " << endl;
    cout << "(enter the full name)" << endl;
    cin.ignore();
    getline(cin, pname);
    
    while (validateString(pname)==false)
    {
        cout << "Name may not start with non-alphabetic letter." 
             << "Try again: " << endl;
        cin.ignore();
        getline(cin, pname);
    }
    
    name = pname;
}

void Person::setAge(int& page)
{
    cin >> page;
    
    while (cin.fail() || page < 0 || page > 140)
    {
        cin.clear();
        cin.ignore('1000', '\n');
        cout << "Invalid. Try again: " << endl;
        cin >> page;
    }
    
    age = page;
}

Person::Person()
{
    age = 0;
    name = "noname";
}

Person::Person(string pname, int page)
{
    name = pname;
    age = page;
}

bool validateString (const string & s)
{
    if (!isalpha(s[0]))
        return false;
    
    else
        return true;
}
Line 119:
119
120
    cin.ignore();
    getline(cin, pname);

Line 126:
126
127
        cin.ignore();
        getline(cin, pname);

The use of ignore() before getline() is not recommended.
That code is dependent on the existing state of the input buffer, which is here assumed to contain a trailing newline '\n' as a result of some previous cin >> operation.

It would be better to remove the cin.ignore() from here, and instead apply it at the point in the program where the newline was put into the buffer. That is to say, in main().
Ok, it is fixed. What else am I doing wrong?
What else am I doing wrong?
Is there a specific malfunction which you are asking about? Or is it a request for an assessment/review of the code?
Actually, I wanted to know how I can make the first letters of the first and last name uppercased. I know I can do

 
name[0] = toupper(name[0]);


But that only changes the first name to uppercase. How about the last name? I would change the name string into a first name string and last name string, but we are supposed to store it in one string.

I think you could search for the letter after the space and change it to uppercase, but I don't have the experience to do this.

Thanks,
VX
search for the letter after the space

A combination of finding the first space, then finding the first non-space after that, could work.
http://www.cplusplus.com/reference/string/string/find_first_of/
http://www.cplusplus.com/reference/string/string/find_first_not_of/
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
std::string adjust_case( std::string name )
{
    bool in_word = false ;

    for( char& c : name ) // for each character in name
    {
        if( std::isalpha(c) ) // if alphabet
        {
            if(in_word) c = std::tolower(c) ; // if already in a word, convert to lower case

            else // beginning of a new word
            {
                c = std::toupper(c) ; // convert to upper case
                in_word = true ; // we are in a word now
            }
        }

        else in_word = false ; // not alpha, we are not in a word now
    }

    return name ;
}

http://coliru.stacked-crooked.com/a/bb97aa7db3da12fc
Thank you both, Chervil and JLBorges. Great inputs!

-VX
Use std::sregex_token_iterator to tokenize the std::string using whitespace (and any others) as delimiter(s). Manipulate the iterator returned by the std::sregex_token_iterator ctor to uppercase first letters:
(http://en.cppreference.com/w/cpp/regex/regex_token_iterator)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <regex>
#include <string>
#include <cctype>
#include <string>
#include <locale>

int main()
{
    std::string name;
    std::cout << "Enter name: \n";
    getline(std::cin, name);

    std::regex rgx("\\s+"); // tokenize string by whitespace
    std::sregex_token_iterator iter(name.begin(), name.end(), rgx, -1);
    // "-1" represents the parts that are not matched i.e. the stuff between matches
    std::sregex_token_iterator name_end;
   //An uninitialized regex iterator automatically represents the ending position
    for ( ; iter != name_end; ++iter)
    {
        std::string name =  std::toupper(iter->str()[0], std::locale()) + (iter->str()).substr(1);
        std::cout << name << '\n';
    }
}





Last edited on
Topic archived. No new replies allowed.