C++: Handle User Input to Points
- Defining the Point Structure
- Initial Attempt: Direct Reading
- Improving Input Validation
- Modular Approach: Function-Based
- Conclusion
Recently, I dove into a challenge from Chapter 9: Input and Output Streams - Drill [12] in Bjarne Stroustrup’s Programming Principles and Practice Using C++. The exercise was to define a Point
structure with x
and y
coordinates, prompting the user to input seven pairs and storing them in a vector<Point>
called originalPoints
.
Defining the Point Structure
First, I defined a data type Point
: point.cpp
#include <iostream>
#include <vector>
#include <string>
using namespace std;
struct Point {
int x;
int y;
Point(int xx=0, int yy=0) : x(xx), y(yy) {}
friend ostream& operator<<(ostream& os, const Point& p) {
return os << "(" << p.x << ", " << p.y << ")";
}
bool operator<(const Point& other) const {
if (x < other.x) {
return true;
} else if (x > other.x) {
return false;
} else {
return y < other.y;
}
}
};
With this, Point
objects can be effectively printed using the overloaded <<
operator.
Initial Attempt: Direct Reading
I started with the simplest approach to read input:
int main() {
vector<Point> originalPoints;
for (int i = 0; i < 7; ++i) {
Point point;
cout << "Enter x and y coordinates for point " << i + 1 << ": ";
cin >> point.x >> point.y;
originalPoints.push_back(point);
}
}
However, this method had limitations:
- It didn’t handle non-integer input well.
- It accepted more than two values without error.
Improving Input Validation
To tackle these limitations, I implemented a function to ensure inputs were integers. Additionally, I used getline()
to read an entire line and then parsed it:
bool isInteger(const string& str) {
return str.find_first_not_of("0123456789") == string::npos;
}
int main() {
vector<Point> originalPoints;
for (int i = 0; i < 7; ++i) {
Point point;
cout << "Enter x and y coordinates for point " << i + 1 << ": ";
string input;
getline(cin, input);
istringstream iss(input);
string xStr, yStr;
if (iss >> xStr >> yStr && isInteger(xStr) && isInteger(yStr)) {
char temp;
if ((iss >> temp) && (isalnum(temp))) {
cerr << "Too many inputs." << endl;
i--;
} else {
point.x = stoi(xStr);
point.y = stoi(yStr);
originalPoints.push_back(point);
}
} else {
cerr << "Invalid input. Please enter two integers separated by a space." << endl;
i--;
}
}
}
Modular Approach: Function-Based
I decided to improve modularity by using a function for input qualification, for testing input types and limiting the number of input to 2. It reduced complexity in the main logic flow:
bool assert_qualify(string cin_str) {
stringstream ss1(cin_str);
int a, b;
if (!(ss1 >> a >> b)) {
cerr << "Invalid input format." << endl;
return false;
}
char temp;
if ((ss1 >> temp) && (isalnum(temp))) {
cerr << "Too many inputs" << endl;
return false;
}
return true;
}
vector<Point> get_points_vector(int size_n) {
vector<Point> points_vector(size_n);
int i = 0;
while (i < size_n) {
string cin_str;
cout << "Enter x and y coordinates for point " << i + 1 << ": ";
cin >> cin_str;
if (assert_qualify(cin_str)) {
stringstream ss2(cin_str);
ss2 >> points_vector[i].x >> points_vector[i].y;
cout << "Point " << i + 1 << " is: " << points_vector[i] << endl;
i++;
} else {
cin.clear();
cout << i + 1 << "th point is invalid. Please enter again: " << endl;
}
}
return points_vector;
}
int main() {
vector<Point> points_vector = get_points_vector(7);
}
Conclusion
Through this exercise, It interests me in handling input validation and foreseeing potential pitfalls in user-input scenarios.
If you’re delving into C++ or similar challenges, I’d love to hear how you tackled similar problems or if you found other creative solutions!