Why is my array always giving a true answer? - c++

My code here says that all values are true even if they aren't in the array. What am I doing wrong? For instance, I could input Chicago, and it will say "City found." I have tried to change the order around and change the "if(foundIt) to if(foundIt = true). It will still do the same.
// MichiganCities.cpp - This program prints a message for invalid cities in Michigan.
// Input: Interactive
// Output: Error message or nothing
#include <iostream>
#include <string>
using namespace std;
int main()
{
// Declare variables
string inCity; // name of city to look up in array
const int NUM_CITIES = 10;
// Initialized array of cities
string citiesInMichigan[] = {"Acme", "Albion", "Detroit", "Watervliet", "Coloma", "Saginaw", "Richland", "Glenn", "Midland", "Brooklyn"};
bool foundIt = false; // Flag variable
int x; // Loop control variable
// Get user input
cout << "Enter name of city: ";
cin >> inCity;
// Write your loop here
for(int i = 0; i < NUM_CITIES; i++){
if (x = i)
foundIt = true;
}
// Write your test statement here to see if there is
// a match. Set the flag to true if city is found.
if (foundIt)
cout << "City found." << endl;
else cout << "Not a city in Michigan." << endl;
// Test to see if city was not found to determine if
// "Not a city in Michigan" message should be printed.
return 0;
} // End of main()

This loop
for(int i = 0; i < NUM_CITIES; i++){
if (x = i)
foundIt = true;
}
does not make sense. There is used an assignment in the if statement of the control variable i to the variable x.
if (x = i)
It seems you mean at least
for(int i = 0; !foundIt && i < NUM_CITIES; i++){
if ( inCity == citiesInMichigan[i] )
foundIt = true;
}
If you need the index of the found city then the loop can look like
size_t i = 0;
while ( i < NUM_CITIES && inCity != citiesInMichigan[i] ) i++;
if ( i != NUM_CITIES )
{
// the city is found at position i
}
else
{
// the sity is not found
}

Related

Trying to compare a randomly generated array to user filled array

I am currently working on a project to create a game of Mastermind. The user must input 3 colors and the program will compare which are the correct color and in the proper place,which are the correct color but in the wrong place, and which are the wrong color. All seems well except I'm unable to properly compare the info within the randomly generated array with the user filled array. I'm sure I'd have to use a loop to accomplish this.
-Things that I feel may be the issue:
*The information within both arrays are not being stored properly.
*conflicting types.
void gameS() {
int close, right, attempts = 0;
string choice[3],code; // holds user input
const int arrySize = 5;
srand(time(0)); //random numbers
string ranColor[arrySize] = { "R", "B", "W", "Y", "G" }; // possible color options
for (int i = 0; i < arrySize - 2; i++) //generat random colors
{
int rcolor = rand() % arrySize;
code = ranColor[rcolor];
cout << code << endl;
}
while (attempts < 10) {
cout << "You should input your color choices below. Your options are - R : Red, B : Blue, W : White, Y : Yellow, G : Green.\n" << "Please choose 3 for your " << attempts+1 << " attempt.\n" << "******************************************************\n\n";
cout << "\n\nPlease enter the color of the first peg: "; //user input to choice array spot : 1
cin >> choice[0];
cout << "\nPlease enter the color of the second peg: "; //user input to choice array spot : 2
cin >> choice[1];
cout << "\nPlease enter the color of the third peg: "; //user input to choice array spot : 3
cin >> choice[2];
attempts++; // proceeds to next turn/attempt
//checks for correct colors in correct places
for (int i = 0; i < 3; i++)
{
if (code == choice[i])
{
right++;
choice[i] = "X";
}
}
//Determin the number of right colors in the wrong place
for (int i = 0; i < 3; i++)
{
for (int y = 0; y < 3; y++) {
if (code[i] == choice[y]) {
close++;
choice[i] = "Y";
}
}
}
}
}
I receive errors for the following lines:
*'argument':conversion from tim_t to unsigned in' possible loss of data
srand(time(0));
*Using uninitialized memory 'right'
`if (code == choice[i])
{
right++;
choice[i] = "X";
}`
*Using uninitialized memory 'close'
`for (int i = 0; i < 3; i++)
{
for (int y = 0; y < 3; y++) {
if (code == choice[y])
{
close++;
choice[i] = "Y";
}
}
}
*no operator "==" matches these operands.
*Binary '==':o global operator found which takes type 'std::string'(or there is no acceptable conversion)
`for (int y = 0; y < 3; y++) {
if (code[i] == choice[y])
{
close++;
choice[i] = "Y";
}`
Any tips would be appreciated.
From what I can see there is some initialization problems.
First
int close, right, attempts = 0;
Will leave close and right empty, simply initialize them properly
int close = 0, right = 0, attempts = 0;
It looks like you want to use code as an array, but the problem is, it is not initialized as an array
string choice[3],code; // holds user input
A quick fix is
string choice[3],code[3]; // holds user input
Now, where you generate the answer, there is another syntax problem
code = ranColor[rcolor];
since you want to store the answer in the code array, an index must be specified, in this case
code[i] = ranColor[rcolor];
The final problem lies in
//checks for correct colors in correct places
for (int i = 0; i < 3; i++)
{
if (code == choice[i])
{
right++;
choice[i] = "X";
}
}
Since code is an array now, simply change the condition statement to
if (code[i] == choice[i])

Finding the Mode C++

How can I edit this function to find multiple modes? Right now if there are multiple, it will display the smallest.
Example
Input 5 5 2 2
Output 5 2
What it actually does
Input 5 5 1 1
Output 1
void calculateMode(int array[], int big)
{
int counter = 1;
int max = 0;
int mode = array[0];
for (int pass = 0; pass < big - 1; pass++)
{
if ( array[pass] == array[pass+1] )
{
counter++;
if ( counter > max )
{
max = counter;
mode = array[pass];
}
} else
counter = 1; // reset counter.
}
cout << "The mode is: " << mode << endl;
}
Anything helps!
I like also the stdlib option as one of the comments refers. However, I tried to solve this problem without using it as you (as an exercise). I had as a requirement to have a constant array as a function parameter, so I could not order it (nor remove the constant nor copy it in a new non-const one). In addition, if there are multiple modes or no elements, I had to return zero.
At the end a came up with something like the following. Hopefully, it might help.
#include <iostream>
#include <stdexcept>
template <typename T> T mode(const T *values, size_t length) {
// check if it has zero length
if (!length)
return 0;
if (!values)
throw std::invalid_argument{"Invalid input array"};
int count{}, maxOccurrences{};
int multipleModes{};
T mode{};
// check every element unless the mode's occurrences are greater than the
// remaining list
for (int k{}; k < length && maxOccurrences <= (length - k); ++k) {
// reset the count for every individual element
count = 0;
// count the number of occurrences
for (int i{}; i < length; ++i) {
if (values[k] == values[i])
count++;
}
if (count > maxOccurrences && mode != values[k]) {
mode = values[k];
maxOccurrences = count;
multipleModes = 0;
/*std::cout << "Count:" << count << " - MaxOccur:" << maxOccurrences
<< " - Mode:" << mode << std::endl;*/
}
if (count == maxOccurrences && mode != values[k]) {
// if the array has multiple modes
multipleModes = 1;
}
}
if (multipleModes == 1)
return 0;
else
return mode;
}
Thanks for you attention!
you can try adding this
else if (counter==max){
mode += array[pass]
}
can't test it on my own system. see if it's of any help.

C++ Making a vector from .txt file data

I'm working on another school project, in part of which I need to take the data from a .txt file and convert it to a mixed type vector... that contains two integers and a string. I've tried various ways of doing it, and I have it down to where the .txt file is inputted, and hopefully sent to vectors. My difficulty comes in when I try to do stuff with the vectors. My code segment is as follows (I'll explain what things are for with comments):
bool ReadPeopleFromFile(int argc, char* argv[], vector<Person> &people) {
Person tmpPrsn;
int tmpAge;
string tmpGender;
int tmpAnualIncome;
ifstream PeopleFile("dev_people.txt"); // Try to open file
if (!PeopleFile.is_open()) {
cout << "Could not open file.\n";
return true; // indicates error
}
cout << "Starting" << endl;
while (!PeopleFile.eof()) {
PeopleFile >> tmpAge;
PeopleFile >> tmpGender;
PeopleFile >> tmpAnualIncome;
tmpPrsn.SetData(tmpAge, tmpGender, tmpAnualIncome);
tmpPrsn.Print();
people.push_back(tmpPrsn); // Need to look at this!!!
}
PeopleFile.close();
cout << "Finished reading file." << endl;
return false;
}
//I have a function that gets the user input... I took it out for this post.
vector<Person> ptntlCstmrs;
// Return people within the given age range.
vector<Person> GetPeopleWithQualifyingCharacteristics(vector<Person> ppl, int AgelowerRange, int AgeupperRange, string DesiredGender, int YIlowerRange, int YIupperRange) {
unsigned int i = 0;
unsigned int j = 0;
unsigned int k = 0;
vector<Person> pplInRange;
int age = 0;
string gender = "";
int yearlyIncome = 0;
for (i = 0; i < ppl.size(); ++i) {
for (j = 0; j < ppl.size(); ++j) {
for (k = 0; k < ppl.size(); ++k) {
age = ppl.at(i).GetAge();
gender = ppl.at(j).GetGender();
yearlyIncome = ppl.at(k).GetYearlyIncome();
if ((age >= AgelowerRange) && (age <= AgeupperRange) && (gender == DesiredGender || gender == "Any") && (yearlyIncome >= YIlowerRange) && (yearlyIncome <= YIupperRange)) {
ptntlCstmrs.push_back(ppl.at(i));
}
}
} // I know this section is messed up... I can't figure out how to get this part to work. What I'm trying to do is take the input, and filter it based on the user-inputted criteria. Nothing that I have done has worked.
}
return pplInRange;
}
int main(int argc, char* argv[]) {
vector<Person> ptntlCstmrs;
bool hadError = false;
int ageLowerRange = 0;
int ageUpperRange = 0;
string desiredGender = "";
int yearlyIncomeLowerRange = 0;
int yearlyIncomeUpperRange = 0;
hadError = ReadPeopleFromFile(argc, argv, ptntlCstmrs);
if (hadError) {
return 1; // indicates error
}
GetUserInput(ageLowerRange, ageUpperRange, desiredGender, yearlyIncomeLowerRange, yearlyIncomeUpperRange);
ptntlCstmrs = GetPeopleWithQualifyingCharacteristics(ptntlCstmrs, ageLowerRange, ageUpperRange, desiredGender, yearlyIncomeLowerRange, yearlyIncomeUpperRange);
cout << "\nNumber of potential customers = " << ptntlCstmrs.size() << endl;
}
I included a bunch of this stuff just in case some of my references are off, but I don't think so. It also tells you what I'm working with. I would like help figuring out how to get the criteria to actually sort the vectors, and then print out how many of those vectors are going to work with the user inputted data.
Thanks in advance!
The credit really goes to #PaulMcKenzie . The problem with the above code is in the following section:
Return people within the given age range.
vector<Person> GetPeopleWithQualifyingCharacteristics(vector<Person> ppl, int AgelowerRange, int AgeupperRange, string DesiredGender, int YIlowerRange, int YIupperRange) {
unsigned int i = 0;
unsigned int j = 0;
unsigned int k = 0;
vector<Person> pplInRange;
int age = 0;
string gender = "";
int yearlyIncome = 0;
for (i = 0; i < ppl.size(); ++i) {
for (j = 0; j < ppl.size(); ++j) {
for (k = 0; k < ppl.size(); ++k) {
age = ppl.at(i).GetAge();
gender = ppl.at(j).GetGender();
yearlyIncome = ppl.at(k).GetYearlyIncome();
if ((age >= AgelowerRange) && (age <= AgeupperRange) && (gender == DesiredGender || gender == "Any") && (yearlyIncome >= YIlowerRange) && (yearlyIncome <= YIupperRange)) {
ptntlCstmrs.push_back(ppl.at(i));
}
}
} // I know this section is messed up... I can't figure out how to get this part to work. What I'm trying to do is take the input, and filter it based on the user-inputted criteria. Nothing that I have done has worked.
}
return pplInRange;
which needs to be changed to the following:
vector<Person> GetPeopleWithQualifyingCharacteristics(vector<Person> ppl, int Agelow, int Ageup, string DesGen, int YIlow, int YIup) {
unsigned int i = 0;
int age = 0;
string gender = "";
int yearlyIncome = 0;
ifstream PeopleFile("dev_people.txt");
while (PeopleFile >> age >> gender >> yearlyIncome);
vector<Person> pplInRange;
for (i = 0; i < ppl.size(); ++i) {
age = ppl.at(i).GetAge();
gender = ppl.at(i).GetGender();
yearlyIncome = ppl.at(i).GetYearlyIncome();
if ((age >= Agelow) && (age <= Ageup) && (DesGen == gender || DesGen == "Any") && (yearlyIncome >= YIlow) && (yearlyIncome <= YIup)) {
pplInRange.push_back(ppl.at(i));
}
}
return pplInRange;
}
Now it works fine. Thanks Paul!
My initial thoughts are that you aren't collecting user input correctly. You send your variables that determine whether or not a Person object is a potential customer off into another function.
By default C++ passes parameters by value -- meaning that when a parameter is passed into a function, a copy of said parameter is made and used throughout that function. When the function comes to a close, the edited parameter is then disposed of and all changes / edits are lost. If you want to grab user input from another method, and have said input saved, make sure to pass your parameters by reference.
Passing by reference essentially tells the machine where that specific parameter is located in memory and allows the program to directly access that piece of memory as opposed to making a copy of the parameter when executing your function. This in turn makes any changes made to parameters permanent!
Hope this helps!

Typo searching for at least 1 character

The original prompt was:
Write a program that keeps track of a speakers bureau. The program should use a
structure to store the following data about a speaker:
Name
Telephone Number
Speaking Topic
Fee Required
The program should use an array of at least 10 structures. It should let the user enter
data into the array, change the contents of any element, and display all the data stored
in the array. The program should have a menu-driven user interface.
Input Validation: When the data for a new speaker is entered, be sure the user enters
data for all the fields. No negative amounts should be entered for a speaker s fee.
The added prompt was:
I need this to expand the search pattern with the potential one character of letter or digit typos. Only one character maybe a typo, in any position Try these test patterns should get the following results:
0-9 is 0x30-0x39
a-z is 0x41-0x5A
A-Z is 0x61-0x7A (or lower case it)
And I can't get the added prompt to work with my current program.
No other characters in the search pattern may be changed.
#include <iostream>
#include <cstring>
#include<string>
using namespace std;
bool print_one_typo(string input, string people[11], bool is_found[11])
{
bool found = false;
if (input[0] == '?')
{
char *strPtr = NULL;
for (int i = 0; i < 11; i++)
{
strPtr = strstr(people[i].c_str(), input.substr(1).c_str());
if (strPtr != NULL)
{
cout << "\t" << people[i] << endl;
found = true;
is_found[i] = true;
}
}
}
else
{
for (int i = 0; i < 11; i++)
{
bool match = true;
string str = people[i];
int value = str.find(input[0]);
for (int k = 0; k < input.length(); k++)
{
if (input[k] != '?' && input[k] != str[value++])
{
match = false;
break;
}
}
if (match && !is_found[i])
{
found = true;
cout << "\t" << people[i] << endl;
}
}
}
return found;
}
int main()
{
string people[11] = { "Becky Warren, 555-1223",
"Joe Looney, 555-0097",
"Geri Palmer, 555-8787",
"Lynn Presnell, 555-1225",
"Holly Gaddis, 555-8878",
"Sam Wiggins, 555-0998",
"Bob Kain, 555-8712",
"Tim Haynes, 555-7676",
"Warren Gaddis, 555-9037",
"Jean James, 555-9223",
"Ron Palmer, 555-7227" };
bool is_found[11] = { false };
string lookUp;
int i;
cout << "\t People and Phone numbers" << endl;
cout << "Enter name or phone number: ";
cin >> lookUp;
cout << "result: " << endl;
bool found = false;
bool output = false;
for (int i = 0; i < lookUp.length(); i++)
{
string local = lookUp;
found = print_one_typo(local.replace(i, 1, 1, '?'), people, is_found);
if (found) output = true;
}
if (!output)
cout << "No matching product was found" << endl;
return 0;
}
I think your code overthinks the problem. Also, you didn't specify if "typo" just means "wrong character", or a fuller range that includes dropped characters or inserted characters.
If you are only looking for matches with zero or one incorrect characters, but otherwise the same length, I think this code should do:
bool print_one_typo(string input, string people[11], bool is_found[11])
{
for (int i = 0; i < 11; i++)
{
if ( is_found[i] ) // Skip if it had already been found?
continue;
if ( input.length() != people[i].length() ) // Are they same length?
continue; // No: Skip it.
int typos = 0;
size_t len = input.length();
for (size_t j = 0; j != len && typos < 2; j++)
if ( input[j] != people[i][j] )
typos++;
if (typos < 2) // Fewer than 2 typos: We have a winner! Return it.
{
is_found[i] = true;
return true;
}
}
return false;
}
This code skips strings that differ in length, or which you're filtering out via the is_found[] array. Not sure why you're doing that, but I preserved that bit of your original code.
If it finds two strings that are the same length, it just compares them character by character, counting up typos. If it sees 2 or more typos, it skips to the next one. Otherwise, it takes the first string that's the same length but fewer than 2 typos.

garbage character at end of string?

Hi there I'm reading a string and breaking each word and sorting it into name email and phone number. with the string joe bloggs joeblog#live.com 12345. But once i break everything down, the individual separated variables which hold the name,email and phone number have garbage characters at the end of them. I cant figure out why.
test file
//test file
#include <iostream>
#include <string>
#include "iofunc.h"
using namespace std;
int main(){
string str1 = "joe bloggs joeblog#live.com 12345";
iofunc func;
cout<<"|-----------------------getname DEMONSTRATION------------------|\n" << endl;
func.getName(str1);
cout<<"the names are: " << func.glob_name << endl;
cout<<"\n|-----------------------getphone DEMONSTRATION------------------|\n" << endl;
func.getPhone(str1);
cout<<"the phone number is:" << func.glob_phone << endl;
cout<<"\n|-----------------------getemail DEMONSTRATION------------------|\n" << endl;
func.getEmail(str1);
cout<<"the email address is:" << func.glob_email << endl;
return 0;
}
here's my get name function, the class is too big to scroll through:)
void iofunc::getName(string arg){
lineProcess(arg);
//make sure to call this depending on what function u are using
int name_count = 0;
int wspace_count = 0;
int arg_len = arg.length();
//int char_len = 0;
char name_temp[80];
name_count = numberofNames();
//line process was called before so this will work,
//make sure you call line process before using this function
//for special, condition when there is no space in front of names
if (special_condition == true){
int i = 0;
while(i < arg_len){
name_temp[i] = arg[i];
i++;
}
glob_name = string(name_temp);
}
if (special_condition == false){
if (name_count == 1){
int i = 0;
while (arg[i] != ' '){
name_temp[i] = arg[i];
i++;
}
glob_name = string(name_temp);
}
//for 2 names
if (name_count == 2){
for (int i = 0; i < arg_len;i++){
if (arg[i] == ' '){
wspace_count++;
}
if (wspace_count !=2){
name_temp[i] = arg[i];
}
}
glob_name = string(name_temp);
}
//for 3 names
if (name_count == 3){
for (int i = 0; i < arg_len;i++){
if (arg[i] == ' '){
wspace_count++;
}
if (wspace_count !=3){
name_temp[i] = arg[i];
}
}
glob_name = string(name_temp);
}
}
}
basic jist of all that is, im using the function called lineProcess to figure out whether there is an email, phone and name in the argument string, And the numberofNames functions gives how many names there are so that I can act accordingly.
I had to use char name_temp to copy just the names from string so that I can extract just that and assign it to the string variable named glob_name. It copies everything i need but it gives me that garbage after each extracted string.
any idea?.
EDITED
void iofunc::getName(string arg){
lineProcess(arg);
//make sure to call this depending on what function u are using
int name_count = 0;
int wspace_count = 0;
int arg_len = arg.length();
//int char_len = 0;
char name_temp[80];
int index_track = 0;
name_count = numberofNames();
//line process was called before so this will work,
//make sure you call line process before using this function
//for special, condition when there is no space in front of names
if (special_condition == true){
int i = 0;
while(i < arg_len){
name_temp[i] = arg[i];
index_track = i;
i++;
}
name_temp[index_track+1] = '\0';
glob_name = string(name_temp);
}
if (special_condition == false){
if (name_count == 1){
int i = 0;
while (arg[i] != ' '){
name_temp[i] = arg[i];
index_track = i;
i++;
}
name_temp[index_track+1] = '\0';
glob_name = string(name_temp);
}
//for 2 names
if (name_count == 2){
for (int i = 0; i < arg_len;i++){
if (arg[i] == ' '){
wspace_count++;
}
if (wspace_count !=2){
name_temp[i] = arg[i];
index_track = i;
}
}
name_temp[index_track+1] = '\0';
glob_name = string(name_temp);
}
//for 3 names
if (name_count == 3){
for (int i = 0; i < arg_len;i++){
if (arg[i] == ' '){
wspace_count++;
}
if (wspace_count !=3){
name_temp[i] = arg[i];
index_track = i;
}
}
name_temp[index_track+1] = '\0';
glob_name = string(name_temp);
}
}
}
When you do things like this:
while(i < arg_len){
name_temp[i] = arg[i];
i++;
}
You are copying the characters of the string to name_tmp, but not the 0 at the end which terminates the string.
add to each new string '\0' end-of string symbol
Garbage characters at the end of a string could indicate that you're not null-terminating the string (ending it with a 0x00 byte). This causes the string to continue reading until the next null character, which is actually past where the string's memory ends. This could even cause a segmentation fault in some cases.
You can fix this by adding '\0' to the end of each new string you create. Note that you will have to allocate a string one byte larger now, to hold that new ending character.
The others have pointed you in the right direction, you aren't appropriately terminating your c strings. Declaring a char array of length 80 just points to a block of memory, it doesn't initialise the array in any way, this means that unless you /0 terminate the string you copy into it, you'll get all the crap lying around on the end up to the 80 characters.
I've not written C++ in probably 15 years so the code below may not even work but hopefully it'll give you some ideas for a more elegant and maintainable solution.
void iofunc::getName(string arg){
lineProcess(arg);
//make sure to call this depending on what function u are using
int name_count = 0;
int wspace_count = 0;
int arg_len = arg.length();
//int char_len = 0;
string name_temp;
// Let's assemble a c-str version if the inbound arg string
char* cstr;
cstr = new char [arg.size()+1];
strcpy (cstr, arg.c_str());
name_count = numberofNames();
//line process was called before so this will work,
//make sure you call line process before using this function
//for special, condition when there is no space in front of names
if (special_condition == true){
glob_name = arg;
}
if (special_condition == false){
// Assuming there's at least 1 name, which we have to otherwise the original
// code may never set glob_name, let's use the C String function strtok
// to tokenise our newly created c string at each " ".
// Grab the first name.
name_temp = string(strtok(cstr, " "));
for (int i = 1; i < name_count; i++) {
// Grab names 2 to name_count as required and append them to name_temp
// We need to reinsert the space as strtok doesn't grab it.
name_temp += " " + string(strtok(NULL, " "));
}
// Assign our final name to glob_name
glob_name = name_temp;
}
}