find() returning maximum value of unsigned int - c++

I'm finishing up a homework assignment that requires me to redirect input and output in the same command. When searching the command (that is a string) for both "<" and ">" the if statement always returns true. This is because it finds the maximum value of an unsigned int on a 64bit system.
The if (uCommand.find("<",0) && uCommand.find(">", 0)) statement will always be true. When I run the uCommand.find(">", 0) in gdb is returns 18446744073709551615.
int main(int argc, char *argv[]) {
// local variables
char **toks;
int retval;
int ii;
int redirect;
int search;
string fileName;
// initialize local variables
toks = NULL;
retval = 0;
ii = 0;
// main (infinite) loop
while (true)
{
// get arguments
toks = gettoks();
if (toks[0] != NULL)
{
for (ii = 0; toks[ii] != NULL; ii++) {
uCommand += " ";
uCommand += (string)toks[ii];
}
// Search for input, output, or dual redirection
if (uCommand.find("<", 0) && uCommand.find(">", 0))
{
redirect = dualRedirect(toks, uCommand);
addHist(uCommand);
}
else if (uCommand.find("<", 0)) {
redirect = inRedirect(toks, uCommand);
addHist(uCommand);
}
else if (uCommand.find(">", 0)) {
redirect = outRedirect(toks, uCommand);
addHist(uCommand);
}
// Look for hist or r and execute the relevant functions
if (!strcmp(toks[0], "r"))
repeatCommand(uCommand);
else if (!strcmp(toks[0], "hist")) {
addHist(uCommand);
showHist();
}
else if (redirect == 0) {
execCommand(toks);
addHist(uCommand);
}
// Increment the command count. This only runs if a something is entered
// on the command line. Blank lines do not increment this value.
commandCount++;
}
}
// return to calling environment
return(retval);
}

I'm assuming uCommand is a std::string, as you didn't include its declaration.
std::string::find returns std::string::npos when the find fails to find anything. This is normally (size_t)-1, size_t is an unsigned type, meaning that npos is an extremely large value. You can't treat this as a bool as anything non-zero is treated as true.
Your code should be
if (uCommand.find("<", 0) != std::string::npos && uCommand.find(">", 0) != std::string::npos)

Related

Palindrome but with a scentence

So writing a palindrome with pointers and boolean. I have it working with a single word but then I began building it to work with a sentence. The problem is I am unsure how to keep the new modified sentence after making it lowercase and getting rid of the spaces for it to return whether it is or isn't a palindrome. It keeps returning the palindrome as false and when I went to check why I see that the program ignores the modification and kept the original string. I can't use "&" on the parameter as I tested it out. Any hints or takes on what I can do to keep the new modified string?
int main()
{
userInput();
return 0;
}
void userInput()
{
char str[90];
std::cout<<"Please enter a string to check if it is a palindrome: ";
std::cin.getline(str, 90);
modifyString(str);
}
void modifyString(char *string)
{
int count = 0;
for (int i=0; i<strlen(string); i++)
{
putchar(tolower(string[i]));
}
for (int i = 0; string[i]; i++)
{
if (string[i] != ' ')
{
string[count++] = string[i];
}
}
string[count] = '\0';
std::cout<<string<<std::endl;
results(string);
}
bool checkPalindrome(char *string)
{
char *begin;
char *end;
begin = string;
end = (string + strlen(string)-1);
while(begin != end)
{
if ((*begin) == (*end))
{
begin ++;
end--;
}
else
{
return false;
}
}
return true;
}
void results(char *string)
{
bool isItPalindrome;
isItPalindrome = checkPalindrome(string);
if( isItPalindrome == true)
{
std::cout<<"\nCongrats, the string is a palindrome!";
}
else
{
std::cout<<"\nThis string is not a palindrome.";
}
}
For starters this definition of main
int main()
{
userInput();
return 0;
}
does not make a sense. According to the function name main the function should perform the main task that is to output whether the entered sentence is a palindrome or not.
This for loop
for (int i=0; i<strlen(string); i++)
{
putchar(tolower(string[i]));
}
does nothing useful. It just outputs the string in the lower case.
This statement
end = (string + strlen(string)-1);
can invoke undefined behavior if an empty string was passed.
This while loop
while(begin != end)
{
if ((*begin) == (*end))
{
begin ++;
end--;
}
else
{
return false;
}
}
also can invoke undefined behavior for a string containing an even number ofo characters because after this if statement
if ((*begin) == (*end))
{
begin ++;
end--;
}
if the two adjacent characters are equal then begin after incrementing will be greater than end after its decrementing. And as a result the loop will continue its iteration.
In general the approach when the original string is changed is just a bad approach.
Your program has too many functions. It is enough to write one function that will determine whether the passed string is a palindrome or not.
Here is a demonstrative program.
#include <iostream>
#include <cstring>
#include <cctype>
bool checkPalindrome( const char *s )
{
const char *t = s + std::strlen( s );
do
{
while ( s != t && std::isspace( ( unsigned char )*s ) ) ++ s;
while ( s != t && std::isspace( ( unsigned char )*--t ) );
} while ( s != t &&
std::tolower( ( unsigned char )*s ) == tolower( ( unsigned char ) *t ) &&
++s != t );
return s == t;
}
int main()
{
const size_t N = 100;
char s[N] = "";
std::cout << "Please enter a string to check if it is a palindrome: ";
std::cin.getline( s, N );
std::cout << '\n';
if ( checkPalindrome( s ) )
{
std::cout << "Congrats, the string is a palindrome!\n";
}
else
{
std::cout << "This string is not a palindrome.\n";
}
return 0;
}
Its output might look like
Please enter a string to check if it is a palindrome: 1 23 456 6 54 321
Congrats, the string is a palindrome!
Okay, I solved it!
As one of the users on here brought up a point that my lowercase did not modify the string and only prints it out. I try my best to solve the problem and I think I found the solution and everything works perfectly fine. comment back to debug it if you like to see how it looks but what I did was create a for loop again for the lower case but made another pointer with it. here how it looks.
for (char *pt = string; *pt != '\0'; ++pt)
{
*pt = std::tolower(*pt);
++pt;
}
Now that definitely changes the string into a lower case and keeps it as a lower case.
so now the modified function looks like this and ready to take any sentence palindrome you give it. Example: A nUt fOr a jAr of tUNa. We make this all lowercase and take out space and boom palindrome and return true.
void modifyString(char *string)
{
int count = 0;
for (char *pt = string; *pt != '\0'; ++pt)
{
*pt = std::tolower(*pt);
++pt;
}
for (int i = 0; string[i]; i++)
{
if (string[i] != ' ')
{
string[count++] = string[i];
}
}
string[count] = '\0';
//take out the forward slash below to see how it looks after being modified
// std::cout<<std::endl<<string<<std::endl;
results(string);
}

How scan two strings separated by `/` using sscanf?

I want to scan to separate strings separated by a / using sscanf but it doesn't work. It works fine with a space.
For example, I want to separate the string 50%/60% into two strings like 50% and 60%.
You can have a look at code here:
#include <iostream>
using namespace std;
int extract_break_rewrites(int *m, int *n, const char *arg)
{
char m_str[10];
char n_str[10];
int err;
int count = sscanf(arg, "%s %s", n_str, m_str);
printf("%s %s %d\n",n_str, m_str,count);
if (count == 0) {
count = sscanf(arg, "/%s", m_str);
if (count == 0) {
*m = 0;
*n = 0;
return -1;
}
if (sscanf(m_str, "%d%%", m) != 1)
return -1;
}
else if (count == 1) {
if (sscanf(n_str, "%d%%", n) != 1)
return -1;
}
else if (count==2) {
if (sscanf(n_str, "%d%%", n) != 1)
return -1;
if (sscanf(m_str, "%d%%", m) != 1)
return -1;
}
return 1;
}
int main() {
int n,m;
const char * command = "50% 60%";
if (extract_break_rewrites(&m,&n,command)!=-1)
cout<<"Successful. The values of m and n are "<<m<<" and "<<n<<", respectively.\n";
else
cout<<"There was error in processing, may be input was not in the correct format.\n";
return 0;
}
You don't need to worry about what the code does, the important lines are 10, 11 and main function.
Try the following (assuming from stdin):
scanf("%[^/]/%s");
Use sscanf(buf, ...); if reading from a buffer.
The issue is that %s for scanf assumes that the string is followed by a space. This approach instructs scanf to find a string delimited by /, and then match the rest as a separate string.
EDIT: accidentally dropped the / in the scan string
Use a scan set
char a[100];
char b[100];
scanf("%[^/]/%s", a, b);
This scans in everything until it gets a /, then it starts and reads in a string.
You can also use std::strings and their facilities to achieve the same result:
#include <iostream>
#include <string>
using std::string;
using std::cout;
using std::stoi;
bool extract_break_rewrites(int &m, int &n, const string &arg) {
// find position of %/ in the string
string::size_type pos_first = arg.find("%/");
// check if the return value is valid (the substring is present and there
// is something else first)
if ( pos_first == string::npos || !pos_first ) // wrong input
return false;
string::size_type pos_2 = pos_first + 2,
pos_last = arg.find("%", pos_2);
if ( pos_last == string::npos || pos_last == pos_2 )
return false;
try {
m = stoi(arg.substr(0, pos_first));
n = stoi(arg.substr(pos_2, pos_last - pos_2));
}
// invalid argument or out of range
catch (...) {
return false;
}
return true;
}
int main() {
int n = 0, m = 0;
string command = "150%/60%";
if ( extract_break_rewrites(m, n, command) )
cout << "Successful. The values of m and n are "
<< m << " and " << n << ", respectively.\n";
else
cout << "There was error in processing, "
<< "maybe input was not in the correct format.\n";
return 0;
}

Checking if argv[i] is a valid integer, passing arguments in main

I'm trying to make sure all arguments passed to main are valid integers, and if not, I'll print an error. For example, if I have an executable named total, I would enter total 1 2 3 4.
I want to print an error if there's an invalid integer, so if I enter total 1 2 3zy it will print an error message. My code is as follows.
#include <iostream>
#include<stdlib.h>
using namespace std;
bool legal_int(char *str);
int main(int argc, char *argv[])
{
//int total = 0;
for(int i = 1; i < argc; i++)
{
if( (legal_int(argv[i]) == true) )
{
cout << "Good to go" << endl;
}
else
{
cerr << "Error: illegal integer." << endl;
return 1;
}
}
// int value = atoi(argv[i]);
//cout << value << endl;
}
bool legal_int(char *str)
{
while(str != 0) // need to
if( (isdigit(str)) )// do something here
{
return true;
}
else
{
return false;
}
}
What I need to know is how can I index through all the characters in the string and make sure they are digits with the legal_int function?
When comparing every character, the logic should be if it's not legal, return false, otherwise continue:
bool legal_int(char *str)
{
while (str != 0)
{
if (!isdigit(*str))
{
return false;
}
str++;
}
return true;
}
What about:
bool legal_int(char *str) {
while (*str)
if (!isdigit(*str++))
return false;
return true;
}
It is not the best function but it should serve the purpose. The isdigit function needs a character to look at so pass in *str. The other key point is that you need to advance the pointer inside of the loop.
bool legal_int(char *str)
{
while(str != 0) // need to
if( (isdigit(str)) )// do something here
{
return true;
}
else
{
return false;
}
}
You have three mistakes:
while (str != 0) should be while (*str != 0). You want to continue until you encounter a zero in the string, not until the string itself goes away.
if( (isdigit(str)) ) should be if( (isdigit(*str++)) ). You want to look at what str points to and see if that's a digit, and you need to point to the next digit.
return true; That should not be there. You don't want to return just because you found a single digit.

How to get substring from WCHAR array

I have one array of WCHAR is like this
WCHAR Path[256];
So I'm passing this array in my function getpath(Path) and It's filling the value in path like this:
//device/systemName/
So I want to get only device from above string.
My code is here:
WCHAR *pDevName;
int i = 0;
int j = 0;
while(Path[i] != NULL){
if(0 ==(wcscmp(Path, L"/")))
{
//i = i + 2;
++i;
continue;
}
else
{
pDevName[j] = Path[i];
++i;
++j;
if (0 == wcscmp(Path, L"/")){
break;
}
}
My code is getting compiled but it's not returning for me device from WCHAR array. It's returning //devicename/systemName/, which is coming from pDevName.
I have doubt over my comparison on wcscmp(). So my question is how to compare / with remaining wchar array value.
wcscmp compares a string, not a character. You're also passing the same address to wcscmp every time - Path, which means all you're doing is comparing the whole string against "/", which will always fail.
If you want to test a single character you can simply compare its value directly, for example:
WCHAR *pDevName;
// NB: I assume you are allocating pDevName and just left that out of the code
// for brevity.
int i = 0;
int j = 0;
while(Path[i] != L'\0'){
if(Path[i] == L'/')
{
++i;
continue;
}
else
{
// NB: you should check for overflow of pDevName here
pDevName[j++] = Path[i++];
if (Path[i] == L'/')
break;
}
}
Since you specified c++, it would be easier to do something like this:
#include <string>
using namespace std;
wstring get_device_name(const wchar_t* path)
{
wstring source(path);
wstring device_name;
if (source.substr(0, 2)==L"//")
{
size_t position= source.find(L'/', 2);
if (position==wstring::npos)
device_name= source.substr(2);
else
device_name= source.substr(2, position-2);
}
return device_name;
}

recursive call overflows

On a test data set the following code works, but when I change to a second test set with a similar size it overflows.
To change a string of tokens into an associated new string of tokens I use this vector lookup function
//looks for input string in vector and returns output, 'c' is check row, 'r' is return row
string vectorSearch(string &check, int &direction, int n, int c, int r, int level)
{
if ((direction == 1 && check.length() <= 1) || n == list.size()-1 ||(direction == 0 && check.length() > 1)) { //if reading and string is 1 char then pass over
if (direction == 1){ //convert '???' into '?'
string temp = "";
bool wildToken = false;
for (unsigned int i = 0; i < check.length(); i++) {
temp+='?';
if (check.compare(temp) == 0) { check = '?'; wildToken = false; } //done,'???" case, return '?' token
else if (check[i] == '?') wildToken = true; //not done searching
}
}
return check;
} else {
if (list[n][c] == check || list[n][c] == ('0'+check)) //add dummy '0'
return list[n][r];
else
return vectorSearch (check, direction, n+1, c, r, level);
}
}
After working fine for a dozen conversions the stack overflows
vectorSearch is called from this function
//this function takes an ontology and direction==1 (default) changes from string
//to single char or if direction==0 takes single char and converts to string representation
string Lexicon::convertOntology(string input, int level, int direction, string out, string temp)
{
if (input == "" && temp == "")
return out; //check for completed conversion
else {
if (direction == 0 || input[0] == '.' || input[0] == '-' || input == "" ) { //found deliniator or end
if (temp == "") temp = input[0]; //condition for reverse w/o deleniators
if (input != "") return convertOntology(input.substr(1), level+1, direction,
out+=vectorSearch(temp, direction, 0, direction, 1-direction, level));
else {
string empty = "";
return convertOntology(empty, level+1, direction, out+=vectorSearch(temp, direction, 0, direction, 1-direction, level));
}
} else
return convertOntology(input.substr(1), level, direction, out, temp+=input[0]); //increment and check
}
}
The call stack is a finite resource and can be exhausted like any other. The larger your function is (with respect to creation of local variables you create inside it) the larger the amount of space each call uses on the stack. It is something that is unavoidable with recursion unless you can restrict the number of recursive calls in some way.
You can only go so deep with recursion before running out of stack space. Luckily, any recursive function can be re-written to be iterative. I believe the below is a correct iterative implementation of your vectorSearch, I'll leave the latter one to you.
string vectorSearch(string &check, int &direction, int n, int c, int r, int level)
{
while(true)
{
if ((direction == 1 && check.length() <= 1) || n == list.size()-1 ||(direction == 0 && check.length() > 1)) { //if reading and string is 1 char then pass over
if (direction == 1){ //convert '???' into '?'
string temp = "";
bool wildToken = false;
for (unsigned int i = 0; i < check.length(); i++) {
temp+='?';
if (check.compare(temp) == 0) { check = '?'; wildToken = false; } //done,'???" case, return '?' token
else if (check[i] == '?') wildToken = true; //not done searching
}
}
return check;
} else if (list[n][c] == check || list[n][c] == ('0'+check)) {//add dummy '0'
return list[n][r];
}
n++;
}
}
thank you to the reviews and comments.
The functions are fine - this recursive function bundle requires that the string exists in the database it acts an, and the string checks prior to these incorrectly recognized a special condition and inserted a dummy char. There is the recursive function that precedes these two - I did not correctly see that I had written a bundle of three recursive functions - and that one was searching within parameters for a string longer than what exists in the database; apparently the parameters were wider than the stack. Checked into the parameters and one was not updated and was not controlling.
I fixed the special condition, the strings are now the same length and the search parameters are fixed.
the functions posted are not too complex.