Just on a starting note, Please excuse the lack of c++ conventions and logic shown in this code. I'm still trying to get around formatting syntax for c++..
With this small part of a larger application building project, I am trying to create a 'data validation' type subroutine with integers and strings being the main test cases, the input coming from the intended user.
The problem is that each character of the variable input is being iterated over, even if the 'if statements' are outside of the 'for loop' (or in some other cases while loops).
An example of the error being:
Enter a value:f1o2o3
Your value is a string
Your value is a integer
Your value is a string
Your value is a integer
Your value is a string
Your value is a integer
The extra lines after the first Your value is a string and
Your value is a integer are unwanted.
I know that I could just instead return the boolean variable letexists or intexsits, with them both being iterated without a problem.
However this 'character iterating' problem has been a nuisance in other parts too and I cannot seem to find a definite, understandable fix anywhere.
I am used to using python so this 'iterating over every character while passing parameters' is quite new to me.
I have tried looking into what it could be for multiple days now. Both: searching online and asking others (in person showing them code that has problems) about the 'iteration over each character' problem, however, none seem to know why this happens.
I have solved this problem in the past by breaking a while(true) loop after the intended data value has been received, however I understand this is really bad practice and therefore want to figure out how I can improve data validation.
#include <iostream> // for std::cin, std::cout
#include <string> // for string datatype
#include <algorithm> // for std::find
#include <iterator> // for std::begin, std::end
using namespace std;
// If the 'cout's are changed to returning functions I will change this to a function itself (using int datacheck(...){...})
void datacheck(string &i) {
const char nums[] = { '0','1','2','3','4','5','6','7','8','9','\0' };
const char alph[] = { 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','\0' };
for (char& c : i) {
bool intexists = find(begin(nums), end(nums), c) != end(nums);
bool letexists = find(begin(alph), end(alph), c) != end(alph);
if (letexists || (letexists && intexists))
cout << "Your value is a string" << endl;
// This will be changed for a return value
else if (!letexists && intexists)
cout << "Your value is a integer" << endl;
// This will be changed for a return value
else
cout << "Your value has an erogenous input (Special characters or non-letter/ number related stuff.";
}
}
int main(void) {
string checkedvalue;
cout << "Enter a value: ";
cin >> checkedvalue;
cin.clear();
cin.ignore(512, '\n');
datacheck(checkedvalue);
return 0;
}
I have realised that it may be because each character is being sent through individually into the subroutine, however, if this is the case I am still unsure how to fix this.
Just to end off...
Overall, an explained solution for why the iterating happens and how it can be fixed will be greatly appreciated. If possible for general cases, however, just this case will be extremely helpful nonetheless.
Thank you.
I have to admit, i dont understand all of what you write. What I did understnad is
The problem is that each character of the variable input is being
iterated over, even if the 'if statements' are outside of the 'for
loop'
And that is wrong!
for (char& c : i) {
bool intexists = find(begin(nums), end(nums), c) != end(nums);
bool letexists = find(begin(alph), end(alph), c) != end(alph);
if (letexists || (letexists && intexists))
cout << "Your value is a string" << endl;
// This will be changed for a return value
else if (!letexists && intexists)
cout << "Your value is a integer" << endl;
// This will be changed for a return value
else
cout << "Your value has an erogenous input (Special characters or non-letter/ number related stuff.";
}
All this above is "the for loop". In simple terms the syntax for a (ranged based) for loop is
for (char& c : i) {
// body of the loop
}
Your code will be more clear and readable if you use {} also for the if, even if not needed and proper intendation:
for (char& c : i) {
bool intexists = find(begin(nums), end(nums), c) != end(nums);
bool letexists = find(begin(alph), end(alph), c) != end(alph);
if (letexists || (letexists && intexists)) {
cout << "Your value is a string" << endl;
} else if (!letexists && intexists) {
cout << "Your value is a integer" << endl;
} else {
cout << "Your value has an erogenous input (Special characters or non-letter/ number related stuff.";
}
}
In C++, the standard provides different ways to checks if an string contains alpha/numeric values:
Check if all characters are numeric: std::isalnum
Check if all characters are alpha: std::isalpha
So you can replace part of your code with:
const all_numeric = std::all_of(std::begin(str), std::end(str), [](const auto c) {
return std::isalnum(c);
})
const all_alpha = std::all_of(std::begin(str), std::end(str), [](const auto c) {
return std::isalpha(c);
})
So to solve your problem, you can start by creating a helper function that checks if a string is a number by using standard functions like strtool or recycle what we did later:
bool is_number(const std::string& s) {
return !s.empty() && std::find_if(s.begin(),
s.end(), [](char c) { return !std::isdigit(c); }) == s.end();
}
Now that you know if the string is a number or not, you can check if your string contains any weird character, and discard it.
Updates:
void datacheck(string &i) {
const auto intexists = is_number(i);
if (intexists) {
// do whatever
return;
}
const all_alpha = std::all_of(std::begin(str), std::end(str), [](const auto c) {
return std::isalpha(c);
});
if (all_alpha) {
// do whatever
return;
}
}
Related
So while working through a course on Udemy over C++ one of the challenges was to check a string to see whether it was a palindrome or not. I completed the task successfully but went about it a different way than the instructor. I understand there are a multitude of ways to complete a task but I am wondering which is more efficient and why? It may seem stupid to be wondering about this while reteaching myself coding but I feel this is something I should be keeping in mind.
//Instructors code//
# include<iostream>
using namespace std;
/*program for reverse a string and check a string is a palidrome
*/
int main()
{
string str="MADAM";
string rev="";
int len=(int)str.length();
rev.resize(len);
for(int i=0, j=len-1; i<len; i++, j--)
{
rev[i]=str[j];
}
rev[len]='\0';
if(str.compare(rev)==0)
cout<<"palindrome"<<endl;
else
cout<<"not a pallindrome"<<endl;
return 0;
}
My Approach
#include <iostream>
using namespace std;
int main(){
string str1="test";
// cout << "Enter a string to check if it is a Palindrome: ";
// getline(cin,str1);
string str2;
string::reverse_iterator it;
for(it=str1.rbegin(); it!= str1.rend(); it++)
{
str2.push_back(*it);
}
if(!str1.compare(str2))
cout << "\nPalindrome";
else
cout << "\nNot a Palindrome";
return 0;
}
Thank you in advance.
In theory the code from your instructor is more efficient, but both examples have issues.
With your instructors code the main issue is the use of
int len=(int)str.length();
In this example, it is okay because we know the size of the string will fit in a int, but if you were getting a string from an outside source, this could be a problem. A std::string using an unsigned integer type to store the size of the string and that means you can have a string who's size is larger then what can fit in an int. If that were to happen, then code is not going to work correctly.
With your code you a avoid all that, which is great, but you also leave some performance on the table. In theory your code of
for(it=str1.rbegin(); it!= str1.rend(); it++)
{
str2.push_back(*it);
}
is going to cause str2 to have multiple buffer allocations and copies from the old buffer to the new buffer as it grows. This is a lot of extra work that you don't need to do since you already know how much space you need to allocate. Having
str2.reserve(str1.size() + 1);
before the loop pre-allocates all the space you need so you don't have those potential performance hits.
Then we come to the fact that both of your examples are using a second string. You don't need another string to check for a palindrome. What you can do is just check and see if the first and last characters are the same, and if they are move on to the first+1 and last-1 character and so on until you reach the middle or they don't match. You can do that using a construct like
bool is_palindrome = true;
for (auto start = str.begin(), end = str.end() - 1;
start < end && is_palindrome;
++start, --end)
{
if (*start != *end)
is_palindrom = false
}
if (is_palindrome)
std::cout << "palindrome\n";
else
std::cout << "not a pallindrome\n";
The simplest and most efficient way (no copying required) would be something like this:
inline bool is_palindrome(const std::string& u) {
return std::equal(u.begin(), std::next(u.begin(), u.length() / 2), u.rbegin());
}
I would say that both are almost the same, but as mentioned in the comments, the line:
str2.push_back(*it);
Is actually very inefficient, since std::string may copy the existing string to a new location in the memory, and then append the next char to the string, which is wasteful.
But I am wondering, why to create the copy in the first place?
It is very simple to run both from start to end, and from end to start to check it out, meaning:
bool is_polindrom(const std::string& str)
{
for (std::size_t idx = 0, len = str.length(); idx < len / 2; ++idx)
{
if (str[idx] != str[len - 1 - idx])
{
return false;
}
}
return true;
}
Running the code with:
int main()
{
const std::string right1 = "MADAM";
const std::string right2 = "MAAM";
const std::string wrong1 = "MADAAM";
const std::string wrong2 = "MEDAM";
std::cout << "MADAM result is: " << is_polindrom(right1) << std::endl;
std::cout << "MAAM result is: " << is_polindrom(right2) << std::endl;
std::cout << "MADAAM result is: " << is_polindrom(wrong1) << std::endl;
std::cout << "MEDAM result is: " << is_polindrom(wrong2) << std::endl;
}
Will yield:
MADAM result is: 1
MAAM result is: 1
MADAAM result is: 0
MEDAM result is: 0
You don't need extra memory in this case, since it is possible to iterate over a string from the end to the beginning, and you need to run on it exactly once (and notice that I stop when idx >= len / 2 since you don't really need to check each letter twice!).
At first this seemed easy to do but I was mistaken. I want to 'replace' a char (a variable) in a string with a int (value). But how?
I tried replace() because I'm working with a string and it worked but it will not work if I wish to change the value of the variable again to another
value because then the original variable will not be found. I have been struggling with this for the passed 2 days. Any help will be much appreciated on how to do this.
changeVar(string startingExpr, char var, int val)
{
for(int i = 0; i < startingExpr.length(); i++)
{
if(startingExpr[i] == var)
{
cout << "I found x! Now to replace it!";
startingExpr[i] = val; //'Replace' x with 5, but x but how?
}
}
}
Your help on this one will be much appreciated.
J
If you want to be able to replace the "variable" by the "value" as many times as you want, you should keep a copy of the original string and do the replacement from there only.
Another option is to undo the replacement (replace the value by the variable) and redo with another value, provided the undo can be done unambiguously.
I am sorry to hear this problem wasted your more than 2 days. You shouldcarefully read a basic C++ textbook. As your problem is a very basic one. If you understand the arguments passing for function, you will sort this out!
More specific, you function is not wrong, but just did not deliver the results you want. Because your function using argument, which will make a copy of argument startingExpr inside the function body, when you make replacement using "startingExpr[i] = val", the replacement is happened on the copy of startingExpr (which is a local variable just visible inside the function), your original startingExpr does change at all.
The solution is very simple, change argument passing with its reference, just add &, now the declaration your function should be: "changeVar(string startingExpr, char var, int val)"
Try the following code, which will demonstrate my explanation:
#include <iostream>
#include <string>
using namespace std;
//the original function which was reported had problem
// This because the function using parameter not reference
void changeVar(string startingExpr, char var, int val)
{
for(int i = 0; i < startingExpr.length(); i++)
{
if(startingExpr[i] == var)
{
cout << "I found x! Now to replace it!(But the replace is happend inside the function, the original string is not changed!)"<<endl;
startingExpr[i] = val; //'Replace' x with 5, but x but how?
}
}
}
// updating using the reference
//void changeVar(string & startingExpr, char var, int val)
void changeVar_refe(string & startingExpr, char var, int val)
{
for(int i = 0; i < startingExpr.length(); i++)
{
if(startingExpr[i] == var)
{
cout << "I found x! Now to replace it!(Now using reference, the replace is happend inside the original string, which will be changed!)"<<endl;
startingExpr[i] = val; //'Replace' x with 5, but x but how?
}
}
}
int main()
{
//lets test the original function
string my_name="Hi there, I am C++ taoism .";
cout<<"The original string is: "<<my_name<<endl;
//lets change a to A
changeVar(my_name,'a',65);
cout<<"The changed string is: "<<my_name<<endl;
cout<<endl;
cout<<"Using the reference to test ... "<<endl;
cout<<endl;
cout<<"The original string is: "<<my_name<<endl;
//lets change a to A
changeVar_refe(my_name,'a',65);
cout<<"The changed string is: "<<my_name<<endl;
//cout <<"Char A is int 65:"<<int('A')<<endl;
}
Your mistake is to assign the number that is different from the ASCII character represntation. In ASCII table characters '0', '1' .. '9' goes one after another. So you can rewrite your code as:
startingExpr[i] = '0' + val;
But please aware that this is good for one character case only. If you need to replace multiple chars then your solution without need for a function is that:
#include <iostream>
#include <string>
int
main()
{
std::string a("SomeVar1"), b("SomeVar356");
std::string::size_type index = std::string::npos;
std::cout << "Before: " << a << std::endl;
if ((index = a.rfind("1")) != std::string::npos)
a.replace(index, 1, std::to_string(2));
std::cout << "After: " << a << std::endl;
std::cout << "Before: " << b << std::endl;
if ((index = b.rfind("356")) != std::string::npos)
b.replace(index, 3, std::to_string(673));
std::cout << "After: " << b << std::endl;
return 0;
}
This is slightly optimized since it is using rfind (search from the end of the string).
P.S. As the comments suggested - you can use std::replace with reverse iterators and lambda for condition. Since it is available in C++11 I wrote a small example in universal style.
I am looking for some quick tips on a homework assignment. We are given a few problems and have to write two quick programs on how to solve the problems with one each of iteration and recursion. I'm sure this is easier than I think, but I am getting easily confused over the two. By no means do I want anyone to fully solve the problems for me, I won't learn anything! But if you could look at what I have so far and let me know if I am heading in the right direction. Also, the code does not need to compile, our professor wants us to have a general idea of the differences of iteration vs. recursion.
Problem: check a string to see if it is a palindrome.
My solution- I think it is the iterative solution:
bool iterative_palindrome (const string& str) {
string line, result;
stack <char> stack_input;
//user enters string, program takes it
cout << "Enter string: " << endl;
while (getline (cin, line) && (line != "")) {
//push string into stack
for (size_t i = 0; i < line.size(); i++) {
stack_input.push(line[i]);
//create reverse of original string
while (!stack_input.empty()) {
result += stack_input.top();
stack_input.pop();
return result;
}
//check for palindrome, empty string
if (line == result || line = "0" || line.empty()) {
return true;
cout << line << " is a palindrome!" << endl;
} else {
return false;
cout << line << " is NOT a palindrome." << endl;
cout << "Enter new string: " << endl;
}
}
}
}
I remind everyone, I am pretty new to this stuff. I've read a few things already, but am still having a hard time wrapping my head around this.
Here's the general idea:
Iterative:
Initialize two pointers one pointer to the start and end of the string.
Compare the characters pointed, if different -> not palindrome.
Increase the start pointer and decrease the end pointer.
Repeat until start pointer >= end pointer.
Recursive (more difficult than iterative in this case):
End condition: A string of length zero or one is a palindrome.
A string is a palindrome if the first and last characters are the same and if the string without the first and last characters is a palindrome.
You can implement this recursive algorithm more efficiently by passing pointers to the first and last character in the string instead of copying the string between recursions.
Hope this helps :-)
I figure writing code is the best way to explain the two approaches. Is this code understandable?
bool iterative_palindrome(const string& str) {
int size = str.size();
for (int i=0; i<str.size()/2; i++) {
if (str[i] != str[size-i-1])
return false;
}
return true;
}
You call this like recursive_palindrome(str, 0).
bool recursive_palindrome(const string& str, int index) {
int size = str.size();
if (index >= size/2)
return true;
if (str[index] == str[size-index-1])
recursive_palindrome(str, index+1);
else
return false;
}
I'm working on a program that takes elements from a user and sorts them. For this program, I have to use a vector as the size of the element list is unknown prior to user input. Our instructions were:
Write a program in C++ to implement sorting of a list of elements.
Elements can be of any type but will all be of same type, like all
integers or all floats or all chars or all strings (strings shall be
sorted like in a dictionary). You can implement any sorting algorithm
of your choice.
Ask the user how many elements will be there
Ask the user to input elements
Ask the user to choose the sorting order: ascending or descending or both
Print both input and output lists
User will not provide any information regarding the type of elements
I'm not very familiar with vectors (teacher basically skimmed topic in class) and my book isn't giving me a whole lot of information on the subject. The problem I'm running into is that I don't know the type of the element list until the user begins input. So far, I have tried:
creating a void type vector (obviously not allowed now that I've researched it, oops)
overloading a function called insertInVector by sending the first element to the function and letting the function determine which vector type to create based on the type of the first element (which seemed like my best option when I thought of it, except I need access to the vector after the function terminates, so that ended up being a no go, too)
#include <typeinfo> in program, finding the type of the first element, and then
creating a vector using vector<typeid(firstElement).name()> and honestly I'm not
sure why that didn't work, but it didn't.
Like I said I have EXTREMELY limited experience with vectors as this is my first time using them. I'm also a fairly new programmer so a lot of the research I've done on this has gone over my head. Any help that could be given in this would be GREATLY appreciated!
C++ is a language statically typed. It means that all the types should be determined during compilation: you cannot introduce new types when running the program.
creating a void type vector (obviously not allowed now that I've researched it, oops)
void is actually quite a strange type, mostly a placeholder for when you would expect a type (like a function return type) and have none to provide. void* is used as a pointer to an unknown type (mostly in C) but this is quite a hack, because the information about the original is discarded (as far as the language is concerned) so this causes issues to actually do things with the value so obtained.
overloading a function called insertInVector by sending the first element to the function and letting the function determine which vector type to create based on the type of the first element
#include <typeinfo> in program, finding the type of the first element, and then creating a vector using vector<typeid(firstElement).name()> and honestly I'm not sure why that didn't work, but it didn't.
Unfortunately neither is possible: since you cannot declare a variable without a type, what would be the type of firstElement to begin with ?
The problem you are describing is difficult in general. Basically it means that you will have to accept a string of characters, and then code a set of rules to determine how to interpret those characters. This is done generically by using a grammar to encode those rules; but grammars might way complicated for what is probably a simple task.
Let me put together a small example:
class Input {
public:
enum Type {
Int,
Double,
String
};
static Input Parse(std::string const& s);
Input(): _type(Int), _int(0), _double(0.0) {} // need to define a default...
Type type() const { return _type; }
int asInt() const {
assert(_type == Int && "not an int");
return _int;
}
double asDouble() const {
assert(_type == Double && "not a double");
return _double;
}
std::string const& asString() const {
assert(_type == String && "not a string");
return _string;
}
private:
Type _type;
int _int;
double _double;
std::string _string;
};
Obviously, the real challenge is to correctly Parse the input.
The idea is to use a set of rules, for example:
an int is composed exclusively of digits, optionally prefixed by -
a double is composed exclusively of digits, with at most one . and optionally prefixed by -
a string can be anything, therefore is our catch-all
Then we can write the recognition part of the Parse method:
static bool isInt(std::string const& s) {
if (s.empty()) { return false; }
// The first character may be among digits and '-'
char const first = s.at(0);
if (not isdigit(first) and first != '-') { return false; }
// Subsequent characters may only be digits
for (char c: s.substr(1)) {
if (not isdigit(c)) { return false; }
}
// Looks like it is an int :)
return true;
} // isInt
// Note: any int could be interpreted as a double too
static bool maybeDouble(std::string const& s) {
if (s.empty()) { return false; }
// The first character may be among digits, '.' and '-'
char const first = s.at(0);
if (not isdigit(first) and first != '.' and first != '-') { return false; }
// There may only be one dot
bool hasSeenDot = s.at(0) == '.';
// Subsequent characters may only be digits and a dot now
for (char c: s.substr(1)) {
if (not isdigit(c) and c != '.') { return false; }
if (c == '.') {
if (hasSeenDot) { return false; } // no second dot allowed
hasSeenDot = true;
}
}
// Looks like it could be a double
return true;
} // maybeDouble
static Input::Type guessType(std::string const& s) {
if (isInt(s)) { return Input::Int; }
// Test double after we ensured it was not an int
if (maybeDouble(s)) { return Input::Double; }
return Input::String;
} // guessType
And with the guessing logic together, finally the parse comes:
Input Input::Parse(std::string const& s) {
Input result;
result._type = guessType(s);
switch(result._type) {
case Input::Int: {
std::istringstream stream(s);
s >> result._int;
return result;
}
case Input::Double: {
std::istringstream stream(s);
s >> result._double;
return result;
}
case Input::String:
result._string = s;
return result;
}
// Unreachable (normally)
abort();
} // Input::Parse
Phew!
So ? Almost there. Now we need to determine how to compare two inputs. It's easy if they all have the same type, if not you will need to determine an arbitrary logic. You can transform an input Int in an input Double easily enough, but for string it's a bit weirder.
// define < for comparing two instance of "Input",
// assuming they both have the same type
bool operator<(Input const& left, Input const& right) {
assert(left.type() == right.type() && "Different Types!");
switch(left.type()) {
case Input::Int: return left.asInt() < right.asInt();
case Input::Double: return left.asDouble() < right.asDouble();
case Input::String: return left.asString() < right.asString();
}
} // operator<
And finally, the program:
int main(int argc, char* argv[]) {
// parse command line
std::vector<Input> inputs;
// by convention argv[0] is the program name, it does not count!
for (int i = 1; i != argc; ++i) {
inputs.push_back(Input::Parse(argv[i]));
// Detect that the type is the same as the first input
if (inputs.size() >= 2) {
if (inputs.back().type() != inputs.front().type()) {
std::cerr << "Please only use one type among Int, Double and String\n";
return 1; // non-0 is an error
}
}
}
// sort
std::sort(inputs.begin(), inputs.end());
// echo back to the user
for (Input const& i: inputs) {
switch(i.type()) {
case Input::Int: std::cout << i.asInt() << "\n"; break;
case Input::Double: std::cout << i.asDouble() << "\n"; break;
case Input::String: std::cout << i.asString() << "\n"; break;
}
}
// End of the program
return 0;
}
Of course as I don't know the types you wish to deal with.. I've decided an arbitrary set ;) However this should give you a skeleton to base yourself on.
Looking at the actual requirements of the problem as stated in the comments, I suggest you store all the inputs in an std::vector<std::string> and sort the vector using std::sort. So, instead of worrying about different types, you can specify the sorting logic depending on what you interpret the strings in your vector to represent. So
Implement sorting functions for strings depending on what the strings represent (more later)
store inputs as strings in a vector.
Determine which type the strings represent
select the sorting function based on this type
Sort the vector using std::sort and the appropriate sort function.
Concerning the sorting function, std::sort accepts a binary functor or function that applies a "less-than" comparison to two elelemts, so your functors or functions should look something like
bool foo(const std::string& rhs, const std::string& lhs) {
// implement the logic
}
Edit: Looking at more recent comments, it seems that the main purpose if the exercise might have been to implement sorting algorithms for different types. In that case, I would suggest following the approach taken by the C++ standard library, that is, to implement sorting in terms or a less-than comparison between two types, thereby decoupling the sorting logic from the types to be sorted. So you would want a template sorting function, templated on iterator type and comparison function/functor.
If you know what are the types the user may input, you can use templates and inheritance:
class Generic {
public:
virtual void process_input() = 0; // Handles the next input from user
virtual void process_output() = 0; // Processes the data inserted
};
template <typename T>
class HandleInput : public Generic {
private:
std::vector<T> storage;
public:
HandleInput(T first)
{
storage.push_back(first);
}
void process_input()
{
// do whatever you want
}
void process_output()
{
// do whatever you want
}
};
int main(int argc, char **argv)
{
// Get first input
Input i = input();
Generic *g;
// Instantiate the "right" generic with a switch
switch (i.type) {
case T:
g = new HandleInput<T>(i.value);
}
// Use Generic from here onwards
}
That's just an idea (Input cannot be implemented like that, you need to change that part with the logic that gets something from the user and determines its type), but it has the benefit of masking the type into a generic class, so you can factor your code around the interface provided by Generic.
Another idea (easier, probably) is using a std::vector<void*> and an enum that tells you what the type of the data stored in the vector is. When you need to process that data somewhere in the future, you can switch on the enum to appropriately cast the vector elements to the correct type and dispatch them to the appropriate code.
EDIT: another idea is to define a templatized function that takes the input and sorts the array using standard comparators:
#include <iostream>
#include <vector>
#include <algorithm>
#include <boost/lexical_cast.hpp>
template <typename T>
void print_v(std::vector<T> &v)
{
typename std::vector<T>::iterator it;
for (it = v.begin(); it != v.end(); it++)
std::cout << *it << " ";
std::cout << std::endl;
}
template <typename T>
void sort_and_print(T first, size_t n, bool asc)
{
std::vector<T> v;
v.push_back(first);
for (size_t i = 0; i < n; i++) {
std::string s;
std::cin >> s;
T e = boost::lexical_cast<T>(s);
v.push_back(e);
}
print_v(v);
if (asc)
std::sort(v.begin(), v.end(), std::greater<T>());
else
std::sort(v.begin(), v.end());
print_v(v);
}
int main(int argc, char **argv)
{
std::string s = "test";
sort_and_print(s, 2, true);
unsigned int j = 3;
sort_and_print(j, 2, true);
return 0;
}
The logic to determine the type of the first input is up to you (maybe you can open another question) ;)
There are two aspects to this question: parsing & sorting.
You can use regular expressions to check the user-input data-types.
You can use cin to parse the data.
First: realise that you cannot necessarily know the type of your
users input until you have received all of it
~eg: consider a list of user names :
728278243
390349346
495045594
elizabeth
Hence, best not to assume to know best about the incoming data (can lead to a frustrating user-experience) but instead, prefer to treat everything as potentially a string. Store all raw input as strings so you can output in same format as input.
you can use say, an enumerated type to switch inside a sort comparator
or consider using a mutliset/multimap. here you will be
building an ordered set. so there is no need to sort.
NB: the complexity for constructing an ordered set of N elements or, for a single sort on N unsorted list elements, is roughly equivalent ~> NlogN
For your task-in-hand, it hardly matters but in reality depending upon upon how the list is used, one or other approach will be far more appropriate in performance terms.
If you have already used the likes of std::vector then std::multimap shouldn't be too scary. Loosely, it is an associated array of key-value pairs. the multi here meaning it can store multiple elements with the same key (which here, you want).
In this example i am using the boost regex library in order to determine some funky input data-types.
(eg: sudo apt-get install libboost-regex1.46-dev)
This regex might seem arcane but there are many examples on the i/web for practically every conceivable pattern.
[NB: C++11 regex is pretty-much a drop-in replacement for boost regex. ie: boost regex should be forward-compatible with the emerging C++11 standard]
blah.cpp:
#include <iostream>
#include <sstream>
#include <string>
#include <list>
#include <map>
#include <set>
#include <boost/regex.hpp>
//NB: GNU gcc added *experimental support for regular expressions in TR1 v 4.3.0.
// compile with: -std=c++0x
using namespace std;
using namespace boost;
//some example input data-types (perhaps notably missing a date!)
const regex re_char("[^0-9]", regex_constants::extended); //non numeric chars
const regex re_digit("[[:digit:]]+", regex_constants::extended); //a string of only digits in range [0..9] ~ie: Z+
const regex re_xdigit("0[xX][[:xdigit:]]+", regex_constants::extended); //support hex iff starts with '0x' or '0X'
const regex re_float("[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?", regex_constants::extended); //all kinds of numbers
int main(int argc, char** argv)
{
int i, countc=0;
double d;
string str;
int element_count;
do
{
cout << "how many elements will there be? ";
if (cin >> element_count) break;
cin.clear();
cin >> str;
cout << "\033[A\033[2K" << flush;
}
while(13);
cin.ignore(128,'\n');
multimap<double, string> list_num;
multimap<double, string> list_fp;
//NB: below, by way of example, construction using the 'greater<int>' comparison class achieves _descending_ order
multimap<int, string, greater<int> > list_int;
list<string> list_str;
for (int next=0; next < element_count; next++)
{
cout << "\033[A\033[2K" << flush;
cout << "enter next element in list ["<< next+1 << "/" << element_count << "] : ";
getline (cin,str);
if (regex_match(str, re_xdigit))
{
//see all about manipulators here:
//http://www.cplusplus.com/reference/iostream/istream/operator%3E%3E/
stringstream(str) >> hex >> i;
list_int.insert(pair<int, string>(i, str));
list_num.insert(pair<double, string>(i, str));
}
else if (regex_match(str, re_digit))
{
stringstream(str) >> i;
list_int.insert(pair<int, string>(i, str));
list_num.insert(pair<double, string>(i, str));
}
else if (regex_match(str, re_float))
{
stringstream(str) >> d;
list_fp.insert(pair<double, string>(d, str));
list_num.insert(pair<double, string>(d, str));
}
if (regex_match(str, re_char)) countc++;
list_str.push_back(str);
}
cout << "\033[A\033[2K" << flush;
cout << "input: unsorted list:" << endl;
for (list<string>::iterator it=list_str.begin(); it!=list_str.end(); it++)
cout << *it << endl;
if (list_int.size() == element_count)
{
cout << endl << "output: sorted list of Z+ types:" << endl;
for (multimap<int, string>::iterator it=list_int.begin() ; it != list_int.end(); it++ )
cout << (*it).second << endl;
}
else if (list_fp.size() == element_count)
{
cout << endl << "output: sorted list of fp types:" << endl;
for (multimap<double, string>::iterator it=list_fp.begin() ; it != list_fp.end(); it++ )
cout << (*it).second << endl;
}
else if (list_num.size() == element_count)
{
cout << endl << "output: sorted list of numeric types:" << endl;
for (multimap<double, string>::iterator it=list_num.begin() ; it != list_num.end(); it++ )
cout << (*it).second << endl;
}
else //output as sorted strings ~but in _descending_ order, using reverse iterator, by way of example
{
list_str.sort(); //but best to use list_str.sort(greater<string>()); with forward iterators
cout << endl << "output: sorted list of " << (countc == element_count ? "non numeric char" : "string") << " types:" << endl;
for (list<string>::reverse_iterator it=list_str.rbegin(); it!=list_str.rend(); ++it)
cout << *it << endl;
}
return 0;
}
Example was compiled & run on Ubuntu. Commandline stuff:
$
$ lsb_release -d
Description: Ubuntu 11.10
$ g++ --version
g++ (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1
$ g++ --pedantic -oblah blah.cpp -lboost_regex
$ ./blah
input: unsorted list:
4.77
2.0e+2
-.3
11
0x10
output: sorted list of numeric types:
-.3
4.77
11
0x10
2.0e+2
$
NB: This is example code:
There are many optimisations that can be made here. You clearly
don't need so many stl containers as i am using.
I do not strictly deal with the direction of the sort (but show a couple of ways it may be achieved).
It might also be nice to encapsulate the type-specific functionality
in C++ objects; have a base class & then derived classes for each type you wish
to support ~but this homework right? -so probably not worth going over-board then
;)
So I am currently learning C++ and decided to make a program that tests my skills I have learned so far. Now in my code I want to check if the value that the user enters is a double, if it is not a double I will put a if loop and ask them to reenter it. The problem I have is how do I go about checking what type of variable the user enters, ex- if a user enters a char or string, I can output an error message. Here is my code:
//cubes a user entered number
#include <iostream>
using namespace std;
double cube(double n); //function prototype
int main()
{
cout << "Enter the number you want to cube: "; //ask user to input number
double user;
cin >> user; //user entering the number
cout << "The cube of " << user << " is " << cube(user) << "." << endl; //displaying the cubed number
return 0;
}
double cube (double n) //function that cubes the number
{
return n*n*n; // cubing the number and returning it
}
Edit: I would have to say I just started and don't have the slightest of clue about your code, but I will check out your link. By the way, I haven't learned how to work with templates yet,I am learning about dealing with data, only Chapter 3 in my C++ Primer Plus 5th edition.
Safe C++ Way
You can define a function for this using std::istringstream:
#include <sstream>
bool is_double(std::string const& str) {
std::istringstream ss(str);
// always keep the scope of variables as close as possible. we see
// 'd' only within the following block.
{
double d;
ss >> d;
}
/* eat up trailing whitespace if there was a double read, and ensure
* there is no character left. the eof bit is set in the case that
* `std::ws` tried to read beyond the stream. */
return (ss && (ss >> std::ws).eof());
}
To assist you in figuring out what it does (some points are simplified):
Creation of a input-stringstream initialized with the string given
Reading a double value out of it using operator>>. This means skipping whitespace and trying to read a double.
If no double could be read, as in abc the stream sets the fail-bit. Note that cases like 3abc will succeed and will not set the fail-bit.
If the fail-bit is set, ss evaluates to a zero value, which means false.
If an double was read, we skip trailing whitespace. If we then are at the end of the stream (note that eof() will return true if we tried to read past the end. std::ws does exactly that), eof will return true. Note this check makes sure that 3abc will not pass our check.
If both cases, right and left of the && evaluate to true, we return true to the caller, signaling the given string is a double.
Similar, you check for int and other types. If you know how to work with templates, you know how to generalize this for other types as well. Incidentally, this is exactly what boost::lexical_cast provides to you. Check it out: http://www.boost.org/doc/libs/1_37_0/libs/conversion/lexical_cast.htm.
C Way One
This way has advantages (being fast) but also major disadvantages (can't generalized using a template, need to work with raw pointers):
#include <cstdlib>
#include <cctype>
bool is_double(std::string const& s) {
char * endptr;
std::strtod(s.c_str(), &endptr);
if(endptr != s.c_str()) // skip trailing whitespace
while(std::isspace(*endptr)) endptr++;
return (endptr != s.c_str() && *endptr == '\0');
}
strtod will set endptr to the last character processed. Which is in our case the terminating null character. If no conversion was performed, endptr is set to the value of the string given to strtod.
C Way Two
One might thing that std::sscanf does the trick. But it's easy to oversee something. Here is the correct way to do it:
#include <cstdio>
bool is_double(std::string const& s) {
int n;
double d;
return (std::sscanf(s.c_str(), "%lf %n", &d, &n) >= 1 &&
n == static_cast<int>(s.size()));
}
std::sscanf will return the items converted. Although the Standard specifies that %n is not included in that count, several sources contradict each other. It's the best to compare >= to get it right (see the manpage of sscanf). n will be set to the amount of the processed characters. It is compared to the size of the string. The space between the two format specifiers accounts for optional trailing whitespace.
Conclusion
If you are a beginner, read into std::stringstream and do it the C++ way. Best not mess with pointers until you feel good with the general concept of C++.
There is no suitable way to check if a string really contains a double within the standard library. You probably want to use Boost. The following solution is inspired by recipe 3.3 in C++ Cookbook:
#include <iostream>
#include <boost/lexical_cast.hpp>
using namespace std;
using namespace boost;
double cube(double n);
int main()
{
while(true)
{
cout << "Enter the number you want to cube: ";
string user;
cin >> user;
try
{
// The following instruction tries to parse a double from the 'user' string.
// If the parsing fails, it raises an exception of type bad_lexical_cast.
// If an exception is raised within a try{ } block, the execution proceeds
// with one of the following catch() blocks
double d = lexical_cast <double> (user);
cout << "The cube of " << d << " is " << cube(d) << "." << endl;
break;
}
catch(bad_lexical_cast &e)
{
// This code is executed if the lexical_cast raised an exception; We
// put an error message and continue with the loop
cout << "The inserted string was not a valid double!" << endl;
}
}
return 0;
}
double cube (double n)
{
return n*n*n;
}
sscanf can do what you want; it returns the number of arguments properly processed. This should get you started:
//cubes a user entered number
#include <iostream>
#include <cstdio>
using namespace std;
double cube(double n); //function prototype
int main()
{
cout << "Enter the number you want to cube: "; //ask user to input number
string user;
cin >> user; //user entering the number
// Convert the number to a double.
double value;
if(sscanf(user.c_str(), "%lf", &value) != 1)
{
cout << "Bad! " << user << " isn't a number!" << endl;
return 1;
}
cout << "The cube of " << user << " is " << cube(user) << "." << endl; //displaying the cubed number
return 0;
}
double cube (double n) //function that cubes the number
{
return n*n*n; // cubing the number and returning it
}
Other methods posted in other answers have their advantages and disadvantages. This one has issues with trailing characters and isn't "C++"-y.
I would have to say I just started and don't have the slightest of clue about your code, but I will check out your link. By the way, I haven't learned how to work with templates yet,I am learning about dealing with data, only Chapter 3 in my C++ Primer Plus 5th edition.
You can fall back on C and use strtod
You program reads in a string and then passes it to a function that attempts to convert the string into double.
bool is_double(const char* strIn, double& dblOut) {
char* lastConvert = NULL;
double d = strtod(strIn, &lastConvert);
if(lastConvert == strIn){
return false;
} else {
dblOut = d;
return true;
}
}