Infinite While Loop Issue

Well, I took a few days break from programming and I somehow managed to forget like 40% of basic C++ info.. And am struggling to do basic things.

In short, I want my program to ask a user various details about themselves (full name, hair color, DOB, etc.) then after it has finished with the questions it will ask if they'd like to add another person's data. User can choose yes or no then it will either repeat or not based on their answer.

The issue (in functions.cpp line 57+) is that when I try to add more than 2 people's information, it stops asking for input and starts spamming console with the questions. I tried a while loop and do while loop. Neither seemed to work.

Could you please tell me what's wrong with my code? Also, if you notice anything that could be improved, please let me know. :)

Main.cpp
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
/*
Please Note: I came up with this problem to practice working with C++17's
 filesystem feature. It is not complete and please do not give me the answer to 
parts I have not completed yet.

My Practice Problem:
  Molly hires you to make a program that will ask users their name, DOB, eye 
color, hair color, height (in inches) and shoe size. Then will create a directory (if it 
doesn't already exist) called "userdata" and will then create a new text file for 
each user. Each file will contain all user data stored in a nice format. Be sure to 
avoid memory leaks and use static analyzers.
*/
#include <iostream>
#include <string>
#include <vector>
#include <filesystem>
#include "User.h"


void askUsers(std::vector<struct User> &allUsers);
void storeData(std::vector<struct User> &allUsers);

int main() {
	// Need to figure out how to make this loop and work for many people. Maybe add to a vector of objects (struct)
	std::vector<struct User> allUsers;
	
	askUsers(allUsers);
	
    storeData(allUsers);

	return 0;
}


Functions.cpp:
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
// Functions.cpp
#include <iostream>
#include <string>
#include <vector>
#include <filesystem>
#include <fstream>
#include "User.h"

namespace fs = std::filesystem;

// function references
std::string replaceSpaces(const std::string &name); // Used in storeData() to convert spaces to '_'


// functions
void askUsers(std::vector<struct User> &allUsers) {
    char answer = 'n';
	do {
		// Creates object
		User temp;
		
		// Asks for user input
		std::cout << "Hello. Ready for your online checkup? Today we're going to ask you a few questions.\n";
		std::cout << "What is your full name? ";
		std::cin >> temp.fullName;

		std::cout << "What is your Date Of Birth? (Format: MM/DD/YYYY) - Example: 01/15/1998\n";
		std::cout << "Your DOB: ";
		std::cin >> temp.DOB;
		
		std::cout << "Eye Color: ";
		std::cin >> temp.eyeColor;
		
		std::cout << "Hair Color: ";
		std::cin >> temp.hairColor;
		
		std::cout << "Height: ";
		std::cin >> temp.height;	
		
		std::cout << "Shoe Size: ";
		std::cin >> temp.shoeSize;
		
		// Adds the object to vector of objects (all users).
		allUsers.push_back(temp);

        std::cout << "Thank you!\n\n";

        std::cout << "Would you like to input another user's data? (y/n): ";
        std::cin >> answer;
    } while (answer == 'y' || answer == 'Y');
}


// - Checks if the folder: "userdata" exists. If not, it will create one.
// - Next it will create a file for each user and store the data on each line (Format: "Hair-Color: Brown").
// - Then will close each file and open the next.
void storeData(std::vector<struct User> &allUsers) {
    fs::path userDataPath(fs::current_path() /= "userdata");

    // If the "userdata" folder doesn't already exist, create it.
    if (!fs::exists(userDataPath)) {
        fs::create_directory("userdata");
        std::cout << "The " << std::quoted("userdata") << " directory didn't already exist so one was created.\n";
    }

    const int vecSize = allUsers.size();
    std::ofstream outFile;
    // For the entire list of users:
    for (int i = 0; i < vecSize; i++) {
        std::string fullName = allUsers[i].fullName;
        std::string fileName = replaceSpaces(fullName);

        // Opens file to prep for writing.
        outFile.open(fileName);

        outFile << "Full-Name: " << allUsers[i].fullName;
        outFile << "Date-Of-Birth: " << allUsers[i].DOB;
        outFile << "Eye-Color: " << allUsers[i].eyeColor;
        outFile << "Height: " << allUsers[i].height;
        outFile << "Shoe-Size: " << allUsers[i].shoeSize;
       
        // Closes file.
        outFile.close();
    }
    std::cout << "Saving user data to file has been completed. Check the " << std::quoted("userdata") << " directory.\n";
}

// Sub-Function of storeData()
// Converts the spaces in a user's name to '_' so it will work properly
// as a file name.
std::string replaceSpaces(const std::string &name) {
    std::string nameToFile = name;

    // Will go through every character in each name and replace spaces
    // with '_' so the file name is correct.
    for (char c : nameToFile) {
        if (c == ' ') {
            c = '_';
        }
    }
    return nameToFile;
}


User.h:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef USER_H
#define USER_H

#include <iostream>
#include <string>

struct User {
	std::string fullName;
	std::string DOB; // Date of Birth (Format: MM/DD/YYYY)
	std::string eyeColor;
	std::string hairColor;
	double height = 0; // inches
	double shoeSize = 0; // inches
};

#endif 


There are no compiler errors.

Help would be greatly appreciated. Thanks!


----
Edit: Unrelated to the original post questions but I've been having trouble with static analyzers and C++17 line: namespace fs = std::filesystem. If anyone knows how to get Clang's static Analyzer & cppcheck to work with namespace fs = std::filesystem then I'd greatly appreciate an explanation!
Last edited on
What is your input? If you're trying to type in multiple words for the full name, you need to use getline instead. cin >> can't handle spaces.

Also, your replaceSpaces function's for loop doesn't modify the string.
You need to use & to get a reference to each character
for (char& c : nameToFile)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <string>

std::string replaceSpaces(std::string name) {

    // Will go through every character in each name and replace spaces
    // with '_' so the file name is correct.
    for (char& c : name) {
        if (c == ' ') {
            c = '_';
        }
    }
    return name;
}

int main()
{
    std::cout << replaceSpaces("h el lo") << '\n';
}


https://stackoverflow.com/a/53694161/8690169
Future tip in case you run into other problems while looping with getline+cin: if you then use getline after using std::cin, you should cin.ignore(); before hand to remove the remaining return key in cin's buffer.
Last edited on
Ganado wrote:
What is your input? If you're trying to type in multiple words for the full name, you need to use getline instead. cin >> can't handle spaces.

Oh right I totally forgot about getline. Thank you for bringing that up. I've fixed it.

Ganado wrote:
Also, your replaceSpaces function's for loop doesn't modify the string.
You need to use & to get a reference to each character
for (char& c : nameToFile)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <string>

std::string replaceSpaces(std::string name) {

    // Will go through every character in each name and replace spaces
    // with '_' so the file name is correct.
    for (char& c : name) {
        if (c == ' ') {
            c = '_';
        }
    }
    return name;
}

int main()
{
    std::cout << replaceSpaces("h el lo") << '\n';
}

Oh, thank you for pointing that out!

Ganato wrote:
https://stackoverflow.com/a/53694161/8690169
Future tip in case you run into other problems while looping with getline+cin: if you then use getline after using std::cin, you should cin.ignore(); before hand to remove the remaining return key in cin's buffer.

Thank you for the reminder (I forgot)! Not to mention explaining it in such an easy to understand way. :D This appears to be the missing piece of the puzzle. In other words, problem solved. Thank you!


Post Solved/Closed. :)
Topic archived. No new replies allowed.