Why is isdigit() not working? - c++

Code:
#include <iostream>
#include <string>
using namespace std;
string s1,s2,s3,s4,s5;
int ex(string s){
int i;
if(isdigit(s)){
i = atoi(s.c_str);
}
else
return -1;
return i;
}
int main(){
int t;cin>>t;int v1,v2,v3;
while(t--){
cin>>s1>>s2>>s3>>s4>>s5;
v1=ex(s1);
v2=ex(s2);
v3=ex(s3);
if(v1<0) v1=v3-v2;
if(v2<0) v2=v3-v1;
if(v3<0) v3=v1+v2;
cout<<v1<<" + "<<v2<<" = "<<v3;
}
}
return 0;
}
Error:
error: no matching function for call to 'isdigit(std::string&)'
if(isdigit(s)){
I tried searching all the previous posts regarding this but still could not figure out why isdigit(s) function is not working.
And the question is there will be input of the form
47 + machula = 53, where machula is some word
and output should be 47 + 6 = 53.

isdigit is meant to check whether a single character is a digit or not, not a string. That's why the call isdigit(s) fails to compile.
You could use std::stoi. However, keep in mind that it will throw an exception if no conversion could be performed by the function.
try
{
i = std::stoi(s);
}
catch ( ... )
{
// Deal with the exception
}
You could also check whether the first character of the string is a digit before attempting to use std::stoi.
if ( !(s.empty()) && isdigit(s[0]) )
{
i = std::stoi(s);
}
NB
From the comment by #RemyLebeau:
The above check because that does not guarantee that all characters in the string are digits. std::stoi() parses the entire string and then reports the index of the first non-digit character, even if that is the null terminator. It also skips leading whitespace, so checking the first character may cause a false result where std::stoi() would have normally succeeded.

Related

How do I properly parse substrings so that they can be effective for my newbie calculator?

Please ELI5 if possible, since i've only been coding for a few days and this is my first program! Below is a portion of my script that is supposed to interpret a single line of input that somebody enters (like "5+5" or something).
I have other operations that I want to add later that are formatted differently, which is why I'm using string instead of a switch function or something.
Anyways.. this isn't working :( So below is my logical process and maybe somebody can point out where I messed up? :)
Thank you in advance!
if (fork.find("+" && "-" && "x" && "/"))
{
size_t pos = fork.find("+" && "-" && "x" && "/"); // Defines a position at the operator symbol
string afterfork = fork.substr(pos + 1); // Cuts a substring at the operator symbol + 1
size_t beforepos = fork.find_first_of(fork); // Defines a position at the beginning of the string
string beforefork = fork.substr(beforepos); // cuts a substring at the begninning of the string
string atfork = fork.substr(pos); // cuts a substring that only has one char (the operator +, -, x, etc)
int x = stoi(beforefork.c_str()); // converts the first substring to an integer
int y = stoi(afterfork.c_str()); // converts the third substring to an integer
string operation = atfork; // converts the middle substring that only has one char to a different name.
return input(x, operation, y); // will send this information to the input function (which will do the math for the calculator).
}
To search the string for one of a list of characters, you can use find_first_of. This function returns npos if it didn't find anything.
const size_t operatorPos = input.find_first_of("+-*/");
if (operatorPos == std::string::npos) {
std::cout << "Couldn't find an operator!\n";
return;
}
To split the string into two sub-strings, you can use substr. To get a character at a position, use operator[].
const std::string left = input.substr(0, operatorPos);
const std::string right = input.substr(operatorPos + 1);
const char operation = input[operatorPos];
To convert a string to an integer, well, there are a lot of options. I'll use std::stoi for this answer. This function throws an exception that we need to catch when it can't convert the string to an integer.
int leftInt;
try {
leftInt = std::stoi(left);
} catch (...) {
std::cout << '"' << left << "\" is not a valid integer!\n";
return;
}
int rightInt;
try {
rightInt = std::stoi(right);
} catch (...) {
std::cout << '"' << right << "\" is not a valid integer!\n";
return;
}
If exceptions are really confusing (it took me ages to get my head around exceptions!) then you can try another function. My favourite (and IMO best) is std::from_chars. Another option is to just not catch the exception.
const int leftInt = std::stoi(left);
const int rightInt = std::stoi(right);
In that case, you won't get a nice error message like "five" is not a valid integer!. You'll get something like:
libc++abi.dylib: terminating with uncaught exception of type std::invalid_argument: stoi: no conversion
Abort trap: 6
Try running std::stoi("five") and see for yourself!
Please, don't use using namespace std;. Just don't!

I have made a program in C++ to separate words from a line by spacebar and display those words as an array. What's wrong in my code?

Please help me to find a bug in this program.It separates a line into words by spacebar. And display as a list.
If the first char of a word is in lower case, it is converted to uppercase.
#include <iostream>
#include <string>
using namespace std;
int main()
{
char line[30]="Hi there buddy",List[10][20];
unsigned int i=0,List_pos=0,no;
int first=0,last;
while(i!=sizeof(line)+1)
{
if(line[i]==' ' or i==sizeof(line))
{
last=i;
no=0;
for(int j=first;j<last;++j)
{
if(no==0)
List[List_pos][no]=toupper(line[j]);
else
List[List_pos][no]=line[j];
++no;
}
++List_pos;
first=last+1;
}
++i;
}
for(unsigned int a=0;a<List_pos;++a)
cout<<"\nList["<<a+1<<"]="<<List[a];
return 0;
}
Expected Output:
List[1]=Hi
List[2]=There
List[3]=Buddy
Actual Output:
List[1]=Hi
List[2]=ThereiXŚm
List[3]=Buddy
I suggest you use a string, as you already included it. And 'List is not really necessary in this situation. Try making a single for loop where you separate your line into words, in my opinion when you work with arrays you should use for loops. In your for loop, as you go through the line, you could just add a if statement which determines whether you're at the end of a word or not. I think the problem in your code is the multiple loops but I am not sure of it.
I provide you a code which works. Just adapt it to your display requirements and you will be fine
#include <iostream>
#include <string>
using namespace std;
int main()
{
string line = "Hi there buddy";
for (int i = 0; i < line.size(); i++) {
if (line[i] == ' ') {
line[i + 1] = toupper(line[i+1]);
cout<<'\n';
} else {
cout<<line[i];
}
}
return 0;
} ```
Challenged by the comment from PaulMcKenzie, I implemented a C++ solution with 3 statements:
Define a std::string, with the words to work on
Define a std::regex that finds words only. Whitespaces and other delimiters are ignored
Use the std::transform to transform the input string into output lines
std::transform has 4 parameters.
With what the transformation should begin. In this case, we use the std::sregex_token_iterator. This will look for the regex (so, for the word) and return the first word. That's the begin.
With what the transformation should end. We use the empty std::sregex_token_iterator. That means: Do until all matches (all words) have been read.
The destination. For this we will use the std::ostream_iterator. This will send all transformed results (what the lambda returns) to the given output stream (in our case std::cout). And it will add a delimiter, here a newline ("\n").
The transormation function. Implemented as lambda. Here we get the word from the std::sregex_token_iterator and transform it into a new word according to what we want. So, a word with a capitalized first letter. We add a little bit text for the output line as wished by the OP.
Please check:
#include <string>
#include <iostream>
#include <regex>
#include <iterator>
int main()
{
// 1. This is the string to convert
std::string line("Hi there buddy");
// 2. We want to search for complete words
std::regex word("(\\w+)");
// 3. Transform the input string to output lines
std::transform(
std::sregex_token_iterator(line.begin(), line.end(), word, 1),
std::sregex_token_iterator(),
std::ostream_iterator<std::string>(std::cout, "\n"),
[i = 1](std::string w) mutable {
return std::string("List[") + std::to_string(i++) + "]=" + static_cast<char>(::toupper(w[0])) + &w[1];
}
);
return 0;
}
This will give us the following output:
List[1]=Hi
List[2]=There
List[3]=Buddy
Please get a feeling for the capabilities of C++
Found a solution for your next problem (when the user inputs a sentence only the first word it displayed). When you input a "space", the cin just thinks you are done. You need to use the getLine() to get the whole sentence.
getline(cin, line);
Instead of
cin>>line;

12 hour to 24 hour time conversion

I am trying to write this c++ program from hackerrank but in my output all I am getting is a blank space.
The input string is in the form of HH:MM:SSpp where HH is an hour on two digits with leading zero, MM the minutes, SS the seconds and pp is either AM or PM.
#include <bits/stdc++.h>
#include<iostream>
#include<string>
using namespace std;
string timeConversion(string s)
{
string p;
int i,j;
if(s[8]==80){ // checking if it is AM or PM
int x = s[0]*10 + s[1] +12;
int y = x%10;
int z = x/10;
s[0]= z;
s[1]= y;
for(i=0;i<10;i++){
p[i]=s[i];
}
}
string newt= p.substr(0, p.size()-2); //removing last two characters
return newt;
}
int main()
{
ofstream fout(getenv("OUTPUT_PATH"));
string s;
getline(cin, s);
string result = timeConversion(s);
fout << result << "\n";
enter code here
fout.close();
return 0;
}
Is there some logical error? I know the other approach for this question but it would be great if anyone could help me with it.
The problem is with treating character digits (e.g. s[0]) as integer digits.
If you are certain you are dealing with digits, the way to do arithmetic with the characters is by subtracting the value of the character '0', like so: s[0] - '0'. The result will be the integral digit.
The main problem
In your timeConversion() function, you define a string p, which is initialized by the string default constructor to "".
Now for AM times, you skip the if and go directly to string newt= p.substr(0, p.size()-2);, which on an empty p will just create an empty newt string. So you return an empty value. Every time !
For PM times, you go into the if to do some transformations. Unfortunately p[i]=s[i]; doesn't do what you think. In fact it is out of bound access in the empty p string. And in the end, the length of p will still be 0 which will cause an empty value to be returned (in the best case).
The start of a solution
Initialize p at construction:
string p=s;
The code will then immediately work for AM strings. For PM strings, you still need to take into account uv_ 's answer related to ascii vs. binary math.
Here the result:
string timeConversion(string s)
{
string p=s;
int i,j;
if(s[8]=='P'){ // checking if it is AM or PM
int x =(s[0]-'0')*10 + (s[1]-'0') +12;
p[0]= x/10 +'0';
p[1]= x%10 +'0';
}
return p.substr(0, p.size()-2); //removing last two characters
}
Note: this assumes that the entry format will always be valid, and no space will be used instead of a leading 0.
Important Note: This code will fail on hackerrank, because it transforms 12:15:00pm into 24:15:00 and not in 12:15:00. Furthermore 12:00:00am will be tranformed in 12:00:00 instead of 00:00:00. More on wikipedia. Online demo about how to address these special cases
This code will work considering all test cases, just added two more conditions.
string timeConversion(string s)
{
string ans=s;
if(ans[8]=='P')
{
int x = (ans[0]-'0')*10+(ans[1]-'0')+12;
//cout<<x;
if(x!=24)
{
ans[0]=x/10+'0';
ans[1]=x%10+'0';
}
}
if(ans[8]=='A')
{
int y=(ans[0]-'0')*10+ans[1]-'0';
if(y==12)
{
ans[0]='0';
ans[1]='0';
}
}
return ans.substr(0, ans.size()-2);
}

vector subscript out of range C++ (substring)

So I'm having this problem with substrings and converting them into integers. This will probably be an easy-fix but I'm not managing to find the answer.
So I receive this string "12-12-2012" and i want to split it, convert into integers and call the modifications methods like this:
string d = (data.substr(0,data.find("-")));
setDia(atoi(d.c_str()));
But it gives me the error mentioned in the title when I try to comvert into an integer.
EDIT:
Turns out that the string doesn't actually contain a '-' but this is really confusing since the string in the parameter results from this : to_char(s.diaInicio,'dd-mm-yyyy')
More information: I used the debugger and it's making the split correctly since the value that atoi receives is 12 (the first split). But I don't know why the VS can't convert into an integer even though the string passed is "12".
This code is not save in the sense that it fails when data does not contain a -.
Try this:
std::size_t p = data.find("-");
if(p == std::string::npos) {
// ERROR no - in string!
}
else {
std::string d = data.substr(0,p);
setDia(atoi(d.c_str()));
}
Please duplicate the problem with a very simple program. If what you say is correct, then the following program should also fail (taken from Danvil's example, and without calling the unknown (to us) setDia() function):
#include <string>
#include <cstdlib>
using namespace std;
int main()
{
string data = "12-12-2012";
std::size_t p = data.find("-");
if(p == std::string::npos) {
// ERROR no - in string!
}
else {
std::string d = data.substr(0,p);
atoi(d.c_str());
}
}

string::find returning a value of -1 when it's expected to return a value of 0 [C++]

I have the following code that doesn't work:
string line;
string line_sub;
size_t open_tag_start;
const string open_tag = "<image>";
const int open_len = open_tag.length() + 1;
open_tag_start = line.find(open_tag);
line_sub = line.substr(open_tag_start, open_len);
When I try to run this code, I get the following error:
terminate called after throwing an instance of 'std::out_of_range'
what(): basic_string::substr
Aborted (core dumped)
I've figured out that this error is occurring because the line.find line is returning a value of -1 to the variable open_tag_start. I can rectify the problem by hard coding a value of 0 into the variable open_tag_start, but I need this to a generic algorithm that will be able to find the tag at any point in the line, so it has to be a variable. Can anyone see what I'm doing wrong here?
Here's some more info.
My goal with this code if to extract a string line_sub from string line, which does indeed contain a string, and when I set size_t open_tag_start = 0, I am able to compile and execute the code and observe the expected output. line is not empty and my problem is that when I replace
line_sub = line.substr(open_tag_start, open_len);
with
line_sub = line.substr(0, open_len);
my problem goes away and I can compile and execute the code.
This is a short version of my program that contains only the parts that are causing the problems. Attempting to compile this code will yield the error message detailed above. The file rss.xml is the RSS feed for engadget.com http://www.engadget.com/rss.xml
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <cstring>
using namespace std;
void get_tag_contents(ifstream& rssfile, string line, string open_tag);
int main()
{
const string open_tag = "<image>";
ifstream rssfile;
rssfile.open("rss.xml");
string line;
getline(rssfile, line, '\n');
get_tag_contents(rssfile, line, open_tag);
return 0;
}
void get_tag_contents(ifstream& rssfile, string line, string open_tag)
{
const int open_len = open_tag.length() + 1;
size_t open_tag_start;
string line_sub;
open_tag_start = line.find(open_tag);
line_sub = line.substr(open_tag_start, open_len);
}
Unless you've left out some code, line is an empty string, so of course find fails. It is your expectation that is in error, not the find function—that's all!
As a side note, you don't need to compensate for '\0' when using C++ strings. Get rid of the + 1.
If the substring isn't found in the string, then the find() method will return std::string::npos, which is a size_type of value -1. When you call substr() with open_tag_start equalling -1, then this is what throws the out_of_range error.
As others have noted, you must check the return value of find() in case the search fails.
std::string line("this is <image> a test");
std::string line_sub;
const std::string open_tag = "<image>";
size_t open_tag_start = line.find(open_tag);
if (open_tag_start != std::string::npos)
{
line_sub = line.substr(open_tag_start, open_tag.length());
}
std::cout << line << "\n" << line_sub << "\n";
Well, are you sure that line contains <image> ?? One thing to consider is that <ImaGe> may be capitalized in some way. Also, i dont quite see what you're trying to do, because line_sub (given that your code works) will just return enter code here and the next character after that. What are you trying to accomplish?
Remember to sanitize your return values. If find returns -1, deal with the problem or throw an error.