Number guesser using function and midpoint [duplicate] - c++

This question already has an answer here:
Number Gusser in c++ using function and midpoint
(1 answer)
Closed 8 years ago.
I am writing a program for number guesser using function and midpoint to find out the number that been chosen. I have a problem compiling and I can't figure out the problem ????
The description of my problem:
The playOneGame function should have a return type of void. It should
implement a complete guessing game on the range of 1 to 100.
The shouldPlayAgain function should have a boolean return type. It
should prompt the user to determine if the user wants to play again,
read in a character, then return true if the character is a ‘y’, and
otherwise return false.
In addition, you should implement the helper functions
getUserResponseToGuess, and getMidpoint. They should be invoked inside
your playOneGame function.
getUserResponseToGuess. This function should prompt the user with the
phrase “is it ? (h/l/c): “ with the value replacing the token
. It should return a char. The char should be one of three
possible values: ‘h’, ‘l’, or ‘c’. It should have the following
signature: char getUserResponseToGuess(int guess)
getMidpoint. This function should accept two integers, and it should
return the midpoint of the two integers. If there are two values in
the middle of the range then you should consistently chose the smaller
of the two. It should have the following signature: int getMidpoint(int low, int high)
My code:
#include<iostream>
using namespace std;
void playOneGame;
char getUserResponseToGuess(int guess);
int getMidpoint ( int low, int high);
int main() {
do
{
playOneGame();
} while (shouldPlayAgain());
return 0;
}
void playOneGame
{
int a = 100;
cout << "\nGuess a number between 1 and 100. " <<endl;
getUserResponseToGuess ( a);
}
char getUserResponseToGuess(int guess)
{
while (true)
{
int guess = getMidpoint(minimum, maximum);
std::cout << "\nIs it [h]igher/[l]ower/[e]qual to " << guess << "? ";
char answer;
if (!(std::cin >> answer))
{
std::cerr << "error reading user input, program exiting\n";
exit(1);
}
if (answer == 'h')
minimum = guess + 1;
else if (answer == 'l')
maximum = guess - 1;
else if (answer == 'e')
{
std::cout << "Well, isn't that nice.\n";
return;
}
if (minimum > maximum)
{
std::cerr << "hey, you lied to me!\n";
exit(1);
}
}
}
int getMidpoint ( int low, int high)
{
int mid;
mid = (low + high) / 2;
return mid;
}

void playOneGame; is not a function forward declaration. void playOneGame(); is. Also the same applies for the function definition.
Also, you should define shouldPlayAgain() and include <stdlib.h> for exit() to work.
And getUserResponseToGuess() has just a return instead of returning something useful and it does not return anything on the default branch.

Related

How to get a large decimal array working in binary search

I am currently trying to complete a project. This code is just a binary search algorithm that i have been using. This is my first search algorithm i have ever done, as i am a self learning programmer i need some advice on how to get this too work. I am using QT creator as an IDE.
I do not get any errors in my code. However, when i run the code the answer is always "No Match Found". Im thinking it has something to do with the array itself as i tested it with 10 integers before and worked perfectly fine.
I know im not very good at explaining this as my english is poor. But if you have any questions please get back to me.
Code Written in C++
#include <iostream>
using namespace std;
float binarySearch(float arr[], int left, int right, float x)
{
while (left <= right)
{
int mid = left + (right - left) / 2;
if (arr[mid] == x)
{
return mid;
}
else if (arr[mid] < x)
{
left = mid + 1;
}
else
{
right = mid - 1;
}
}
return -1;
}
int main()
{
float num;
float output;
float myarr[100] = {44.64978683, 44.62352548, 44.5972165, 44.57086043, 44.54445783,
44.51800925, 44.49151522, 44.46497629, 44.43839299, 44.41176587,
44.38509546, 44.35838228, 44.33162687, 44.30482976, 44.27799146,
44.25111251, 44.22419342, 44.1972347, 44.17023688, 44.14320046,
44.11612596, 44.08901388, 44.06186473, 44.03467901, 44.00745722,
43.98019985, 43.95290742, 43.9255804, 43.89821929, 43.87082457,
43.84339674, 43.81593628, 43.78844366, 43.76091937, 43.73336389,
43.70577768, 43.67816122, 43.65051497, 43.62283941, 43.595135,
43.56740221, 43.53964148, 43.51185328, 43.48403806, 43.45619628,
43.42832838, 43.40043481, 43.37251603, 43.34457246, 43.31660456,
43.28861275, 43.26059748, 43.23255917, 43.20449827, 43.17641519,
43.14831036, 43.12018421, 43.09203716, 43.06386963, 43.03568203,
43.00747477, 42.97924828, 42.95100295, 42.92273919, 42.89445742,
42.86615803, 42.83784141, 42.80950798, 42.78115811, 42.75279222,
42.72441067, 42.69601387, 42.6676022, 42.63917604, 42.61073577,
42.58228177, 42.55381441, 42.52533407, 42.49684112, 42.46833593,
42.43981886, 42.41129027, 42.38275054, 42.35420001, 42.32563904,
42.29706799, 42.26848721, 42.23989705, 42.21129785, 42.18268996,
42.15407372, 42.12544947, 42.09681755, 42.06817829, 42.03953203,
42.01087909, 41.98221981, 41.9535545, 41.9248835, 41.89620711};
while(true)
{
cout << "Please enter an element to search" << endl;
cin >> num;
output = binarySearch(myarr, 0, 100, num);
if (output == -1)
{
cout << "No Match Found" << endl;
}
else
{
cout << "Match found at position: " << output << endl;
}
}
}
The elements of your array myarr is sorted in decending order, so left should be set to mid+1 when current element is larger than target, not smaller.
Wrong:
else if (arr[mid] < x)
Correct:
else if (arr[mid] > x)
Also the array has only 100 elements, so the initial right should be 99, not 100.
Wrong:
output = binarySearch(myarr, 0, 100, num);
Correct:
output = binarySearch(myarr, 0, 99, num);

Returning the complete value in recursions

I've written a C++ code to convert a base 10 number into base two, but don't want the function to print it, but to return the value since I'll later need to use it in another function. The problem with returning is that the first time it returns it'll break out of the function, so it won't finish the process of converting and instead of returning '101' for '5', it will simply return '1' and that's it. Any ideas to fix this? I appreciate in advance.
Here's also my code:
int two;
int base(int a)
{
if(a==1)
{
two=a%2;
}
else
{
base(a/2);
two=a%2;
}
return two;
}
Note: Of course the code works pretty well if I change the return type into void and simply print the value. But I want to RETURN the value.
Implementation of summing up (in fact it can be implemented iteratively but it seems you need to apply recursion so I provided recursive solution):
int baseHelper(int a, int factor)
{
int returnedValue = 0;
if(a==0 || a==1)
returnedValue = factor * a;
else
{
int addend = factor * (a%2);
returnedValue = addend + baseHelper(a/2, factor*10);
}
return returnedValue;
}
int base(int a)
{
return baseHelper(a, 1);
}
int main()
{
for(int i=0; i<=256; i++)
cout << "i=" << i << " " << base(i) << endl;
return 0;
}
If you want to use recursion, you can return std::string like this:
std::string base(int a)
{
if (a == 0)
return "0";
else if (a == 1)
return "1";
else
return base(a / 2) + ((a % 2) ? "1" : "0");
}
Using std::to_chars or std::from_chars from <charconv> is also an alternative.

C++ “add explicit braces to avoid dangling else”

bool isPalindromeIterative(const char *s1){
int len=strlen(s1)-1;
if(len>0)
if(s1[0]==s1[len]){
len-=2;
isPalindromeIterative(s1+1);
}
else
return false;
return true;
}
I am writing about Palindrome.
And when I run it, it appears warning like this:
":79:13: warning: add explicit braces to avoid dangling else
[-Wdangling-else]"
Please help me ! Thanks!
There is formally nothing wrong with the code, unless you wanted the else to match the outer if. A common mistake.
If you add braces everywhere, it will be clear what you intended:
if(len>0)
{
if(s1[0]==s1[len])
{
len-=2;
isPalindromeIterative(s1+1);
}
else
{
return false;
}
}
When you write,
if(len>0)
if(s1[0]==s1[len]){
// This has no effect on the recursive call.
len-=2;
// You missed the return in your post.
return isPalindromeIterative(s1+1);
}
else
return false;
it's most likely that you meant to associate the else with the second if.
if(len>0)
{
if(s1[0]==s1[len])
{
return isPalindromeIterative(s1+1);
}
else
return false;
}
However, the compiler does not use the indent to figure that out. It's possible that, from the compiler writer's point of view, you meant to associate the else with the first if:
if(len>0)
{
if(s1[0]==s1[len])
{
return isPalindromeIterative(s1+1);
}
}
else
{
return false;
}
Since this is common mistake made by developers, the compiler warns you and hopes that you will update the code so that it's less likely to turn into a runtime error.
I want to point out that the recursion logic you are using to detect whether a string is palindrome is wrong.
Let's say your string is "abxba".
In the first iteration, you compare 'a' with 'a'.
In the next iteration, you compare 'b' with 'a', which is incorrect. You end up with the wrong answer.
You have to change your strategy a bit. Use:
bool isPalindromeIterative(const char *s1, int start, int end)
{
if ( start >= end )
{
return true;
}
if ( s1[start] == s1[end] )
{
return isPalindromeIterative(s1, start+1, end-1)
}
return false;
}
The start of the iterative call has to be made as:
isPalindromeIterative(s1, 0, strlen(s1)-1);
It is a style warning against reading the if clauses wrong.
if(len>0) {
if(s1[0]==s1[len]){
len-=2;
isPalindromeIterative(s1+1);
}
} else {
return false;
}
is better to read and less error-prone.
We have similar coding guidelines in our company; for an if, which has bracket clauses, all else branches and all other ifs within the if of the highest order have to have brackets.
Else your example could too easily be misread as e.g.
if(len>0)
if(s1[0]==s1[len]){
len-=2;
isPalindromeIterative(s1+1);
}
else
return false;
Your original post headline mentioned iterative, and 'Iterative' is still part of your function name (even though it is recursive).
You marked this post as c++, but did not use classes.
The other answers addressed your specific questions about your error messages.
For your consideration, and because you have already selected a recursive answer, here is a possible C++ iterative solution and tail-recursive solution using std::string&.
#include <iostream>
#include <string>
class T589_t
{
public:
int exec(int argc, char* argv[])
{
if (argc < 2)
{
std::cerr << "\n please provide one or more string(s) to test"
<< std::endl;
return -1;
}
for (int i = 0; i < argc; ++i)
{
std::string s = argv[i];
{
std::string yesno = (isPalindromeIterative(s) ? " is" : " is not");
std::cout << "\n '" << s << "'" << yesno << " a palindrome (iterative)" << std::flush;
}
std::cout << std::endl;
{
std::string yesno = (isPalindromeRecursive(s) ? " is" : " is not");
std::cout << " '" << s << "'" << yesno << " a palindrome (recursive)" << std::endl;
}
} // for 0..argc
return 0;
}
private: // methods
bool isPalindromeIterative(const std::string& s1)
{ // ^^^^^^^^^
bool retVal = false; // guess s1 is not palindrome
int left = 0; // index of left most char
int right = static_cast<int>(s1.size()) - 1; // index of right most char
do { // iterative loop
if (s1[left] != s1[right]) break; // when not equal, is not palindrome
left += 1; right -= 1; // iterate!
if (left >= right) // all chars tested?
{
retVal = true; // confirm palindrome
break; // exit
}
} while (true);
return retVal;
}
// Notes './dumy589' // odd length 9
// ^-------^ [0] vs [8]
// ^-----^ [1] vs [7]
// ^---^ [2] vs [6]
// ^-^ [3] vs [5]
// ^ [4] == [4] // left >= right, break
// Notes 'abccba' // even length 6
// ^----^ [0] vs [5]
// ^--^ [1] vs [4]
// ^^ [2] vs [3]
// [3] vs [2] // left >= right, break
// Notes 'abcba' // odd length 5
// ^---^ [0] vs [4]
// ^-^ [1] vs [3]
// ^ [2] vs [2] // left >= right, break
// and bonus: tail recursion based on above iterative
// vvvvvvvvv
bool isPalindromeRecursive(const std::string& s1)
{
// index of left most char
int left = 0;
// index of right most char
int right = static_cast<int>(s1.size()) - 1;
return (isPalindromeRecursive(s1, left, right));
}
bool isPalindromeRecursive(const std::string& s1, int left, int right)
{
if (s1[left] != s1[right]) return false;
left += 1; right -= 1;
if ( left >= right ) return true;
return (isPalindromeRecursive(s1, left, right));
}
}; // class T589_t
int main(int argc, char* argv[])
{
T589_t t589;
return t589.exec(argc, argv);
}
On Linux, argv[0] is the executable name.
environment:
Lubuntu 17.10,
g++ (Ubuntu 7.2.0-8ubuntu3.2) 7.2.0
With invocation:
./dumy589 aba abccba tx s
This code reports:
'./dumy589' is not a palindrome (iterative)
'./dumy589' is not a palindrome (recursive)
'aba' is a palindrome (iterative)
'aba' is a palindrome (recursive)
'abccba' is a palindrome (iterative)
'abccba' is a palindrome (recursive)
'tx' is not a palindrome (iterative)
'tx' is not a palindrome (recursive)
's' is a palindrome (iterative)
's' is a palindrome (recursive)

How can I trace back the error

I was assigned to create an array check (to see if the array is increasing, decreasing, or neither [then exiting if neither]) and a recursive binary search for one of my assignments. I was able to do these things after some help from my peers, but I need help in finding what seems to be causing the error
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct null not valid
Aborted
when running the code. I Googled this error and this error seems to be vague or I just am not understanding. It compiles without errors, but I need help in what finding what I did wrong. It is able to run without the binarySearchR function and its associating code, as the array check on its own was the previous assignment. Below is the code, and I thank you so much in advance!
#include <iosteam>
#include <string>
#include <cstdlib>
#include <fstream>
using namespace std;
int checkArraySort (string *fileLines, int numberOfLines);
int binarySearchR (string *fileLines, string searchKey, int iMin, int iMax);
int main ()
{
int numberOfLines = 0;
string searchKey = 0;
cout << "Input search key: ";
cin >> searchKey;
ifstream fileIn;
fileIn.open("words_in.txt");
string line;
if (fileIn.eof()) /* Checks file to see if it is blank before proceeding */
{
exit (EXIT_SUCCESS);
}
else
{
while(!(fileIn.eof()))
{
fileIn >> line;
numberOfLines++;
}
fileIn.close(); /* closes fileIn, need to reopen to reset the line location */
fileIn.open("words_in.txt");
string *fileInLines;
fileInLines = new string[numberOfLines];
for (int i = 0; i < numberOfLines; i++)
{
fileIn >> line;
fileInLines[i] = line;
}
fileIn.close(); /* closes fileIn */
int resultingCheck = checkArraySort(fileInLines, numberOfLines);
if (resultingCheck == -1)
{
cout << "The array is sorted in descending order." << endl;
}
else if (resultingCheck == 1)
{
cout << "The array is sorted in ascending order." << endl;
}
else
{
cerr << "ERROR: Array not sorted!" << endl;
exit (EXIT_FAILURE);
}
int searchResult = binarySearchR (fileInLines, searchKey, 0, numberOfLines);
if (!searchResult == -1)
{
cout << "Key found at index " << searchResult << "." << endl;
}
else
{
cout << "Key not found at any index." << endl;
}
exit (EXIT_SUCCESS);
}
}
int checkArraySort (string *fileLines, int numberOfLines)
{
int result = 1; /* Ascending by default */
for (int i = 1; i < numberOfLines; i++) /* Checks if decending */
{
if (fileLines[i] < fileLines[i-1])
{
result = -1;
}
}
if (result == -1) /* Makes sure it is descending (or if it is neither) */
{
for (int i = 1; i < numberOfLines; i++)
{
if (fileLines[i] > fileLines[i-1])
{
result = 0;
}
}
}
return result;
}
int binarySearchR (string *fileLines, string searchKey, int iMin, int iMax)
{
// so, its gotta look at the center value and each times, it discards half of the remaining list.
if (iMax < iMin) /* If the minimum is greater than the maximum */
{
return -1;
}
else
{
int iMid = (iMin + iMax) / 2;
if (fileLines[iMid] > searchKey) /* If the key is in the lower subset */
{
return binarySearchR (fileLines, searchKey, iMin, iMid - 1);
}
else if (fileLines[iMid] < searchKey) /*If the key is in the upper subset */
{
return binarySearchR (fileLines, searchKey, iMin, iMid + 1);
}
else /*If anything else besides the two */
{
return iMid;
}
}
}
The easy way: add a bunch of cout s to see where you program goes and what the values are.
Pros
Easy to do
Cons
Requires a recompile each time you want to add more info
The hard way: Learn to use a debugger
Pros
Can inspect "on the fly"
Don't need to rebuild
Can use what you learn in every other C++ program
Cons
Requires a bit of research to learn how to do it.

Learning recursion: How can I locate a substring index within a string without using find?

I have a recursive function to find the starting index of a substring within a string. I am learning to use recursion, so the find function is not allowed. I believe I have met most of the conditions. This function is supposed to find the correct index in the string. If it is blank it returns -1.
Here is the real problem. If I enter a string "nothing" and search for "jax" it doesn't return -1. I don't understand why. Any help please? Here is the code:
The user would enter string s and t passed into below:
int index_of(string s, string t)
{
int start = 0;
int len2 = t.length();
int index = 0;
if (s == "")
{
return -1;
}
else if (s.substr(1).length() <= t.length())
{
return -1;
}
else if ( s.substr(start, len2) == t)
{
return index;
}
else
{
index ++;
return index + index_of(s.substr(1), t);
}
return -1;
}
There are several problems -- some minor ones, and some quite important ones.
You have two variables, start and index, to indicate "the current position", but one would be enough.
index can only be 0 or 1. Therefore, the way it is currently written, you could easily get rid of index and start altogether.
Important: When, during the final recursion, the end of the string is reached, you return -1 to the previous recursive call. Then, because of the way the recursive calls are done, you add 1 and return that to the previous call, and so forth. The value finally returned is the -1 plus the length of the string. That is why you get strange results.
This comparison
if (s.substr(1).length() <= t.length())
does not make much sense.
Taking all of this into account, here is an improved version:
#include <iostream>
#include <string>
int index_of(
const std::string &s,
const std::string &t,
const size_t index)
{
int len2 = t.length();
if ((s.length() - index) < t.length())
return -1;
else if (s.substr(index,len2) == t)
return index;
else
return index_of(s,t,index + 1);
return -1;
}
/** Overloading, so you can call index_of with just
two arguments */
int index_of(const std::string &s, const std::string &t)
{
return index_of(s,t,0);
}
/** Some test cases. */
int main()
{
std::cout << index_of("hello","ello") << std::endl;
std::cout << index_of("nothing","jax") << std::endl;
std::cout << index_of("hello","llo") << std::endl;
std::cout << index_of("hello","lo") << std::endl;
std::cout << index_of("hello","o") << std::endl;
std::cout << index_of("hello","hel") << std::endl;
}
The best way to learn how to debug problems like this is to work them out on paper. Your example is small enough that it shouldn't take too long. It's pretty clear that you're going to fall into your else case in the first few steps because the strings don't match. So we have:
index_of("nothing", "jax"):
index++; // index is now 1
return 1 + index_of("othing", "jax");
index_of("othing", "jax"):
index++; // index is now 1
return 1 + index_of("thing", "jax");
etc.
Does that help?