Missing array element issue - c++

This is part of a homework assignment I recently finished. I am required to use an array of structs to store a library of books by title and author. The code is working and running perfectly fine when sorting and displaying author or title alphabetically according to user input.
The only issue I run into is when it shows all books sorted alphabetically. There are 14 books total in the text file used with the assignment, but only 13 books show up when the show all (S) option is entered.
An example of the error would be:
()
Audio for Games (Brandon)
Instead of:
Audio for Games (Brandon)
Beginning LINUX Programming (Stones and Matthew)
My Code:
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
using namespace std;
// structure
struct Book {
string title;
string author;
};
const int ARRAY_SIZE = 1000;
Book books[ARRAY_SIZE];
string pathName;
ifstream lib;
// global variables
int loadData();
void showAll(int count);
void sortByTitle(int count, string title);
int main()
{
// initialised variables
int count = 0;
char selector = 'q', yesNoAnswer = 'n';
string name;
string title;
// asks user for file pathname
cout << "Welcome to Tommy's Library Database." << endl;
cout << "Please enter the name of the file: ";
getline(cin, pathName);
loadData();
count = loadData();
cout << count << " Records loaded successfully." << endl;
// Switch case menu
do {
cout << endl << "Please enter a keyword that corresponds to the list of options: " << endl;
cout << " Search by: (A)uthor, (T)itle, (S)how All, (Q)uit Program: ";
cin >> selector;
selector = toupper(selector);
switch (selector)
{
case 'S':
sortByTitle(count, title);
if (count <= 0) {
cout << " No counts found! " << endl;
}
else {
showAll(count);
}
break;
}
}
while (selector != 'q' && selector != 'Q');
return 0;
}
int loadData()
{
int count = 0;
int i = 0;
lib.open(pathName);
ifstream lib(pathName);
if (!lib)
{
cout << " Unable to open file path! " << endl;
return -1;
}
while (!lib.eof())
{
getline(lib, books[count].title);
getline(lib, books[count].author);
count++;
}
return count;
}
// displays all book titles beside the author names
void showAll(int count)
{
for (int i = 0; i < count; i++)
{
cout << books[i].title << " " << "(" << books[i].author << ")" << endl;
}
}
// Sorts by book title.
void sortByTitle(int count, string title) {
Book temp;
for (int i = 0; i < count; i++) {
for (int j = 0; j < count - i; j++) {
if (books[j].title > books[j + 1].title) {
temp = books[j];
books[j] = books[j + 1];
books[j + 1] = temp;
}
}
}
}
The text file im using with the assignment (books.txt)
Objects First with Java
Barnes and Kolling
Game Development Essentials
Novak
The Game Maker's Apprentice
Overmars
C++ Programming: From Problem Analysis...
Malik
C++ Programming Lab Manual
Scholl
Beginning LINUX Programming
Stones and Matthew
C++ Programming: Program Design Including...
D. S. Malik
C++ How to Program
Deitel and Deitel
Programming and Problem Solving with C++
Dale, Weems, Headington
Game Character Development with Maya
Ward
Developing Games in Java
Brackeen
C# Programming
Harvey, Robinson, Templeman, Watson
Java Programming
Farrell
Audio for Games
Brandon

You were starting your loop from 0 inside your showAll() method when your books array starts from 1, just start the loop from 1 and go to count + 1
for (int i = 1; i < count + 1; i++)

Your sort function doesn't work correctly. It's off by one and moves an empty element to the first index. It would cause undefined behavior if your array were full. Your sort function sorts all elements from 0 to count but it should sort from 0 to count - 1. You should fix your sort function (std::sort usually is faster than bubble sort):
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
using namespace std;
// structure
struct Book {
string title;
string author;
};
const int ARRAY_SIZE = 1000;
Book books[ARRAY_SIZE];
string pathName;
ifstream lib;
// global variables
int loadData();
void showAll(int count);
void sortByTitle(int count, string title);
int main()
{
// initialised variables
int count = 0;
char selector = 'q', yesNoAnswer = 'n';
string name;
string title;
// asks user for file pathname
cout << "Welcome to Tommy's Library Database." << endl;
cout << "Please enter the name of the file: ";
getline(cin, pathName);
loadData();
count = loadData();
cout << count << " Records loaded successfully." << endl;
// Switch case menu
do {
cout << endl << "Please enter a keyword that corresponds to the list of options: " << endl;
cout << " Search by: (A)uthor, (T)itle, (S)how All, (Q)uit Program: ";
cin >> selector;
selector = toupper(selector);
switch (selector)
{
case 'S':
sortByTitle(count, title);
if (count <= 0) {
cout << " No counts found! " << endl;
}
else {
showAll(count);
}
break;
}
}
while (selector != 'q' && selector != 'Q');
return 0;
}
int loadData()
{
int count = 0;
int i = 0;
lib.open(pathName);
ifstream lib(pathName);
if (!lib)
{
cout << " Unable to open file path! " << endl;
return -1;
}
while (!lib.eof())
{
getline(lib, books[count].title);
getline(lib, books[count].author);
count++;
}
return count;
}
// displays all book titles beside the author names
void showAll(int count)
{
for (int i = 0; i < count; i++)
{
cout << books[i].title << " " << "(" << books[i].author << ")" << endl;
}
}
// Sorts by book title.
void sortByTitle(int count, string title) {
std::sort(books, books + count, [](const auto &lhs, const auto &rhs) {
return lhs.title < rhs.title;
});
}
In addition:
You shouldn't read a stream with while (!lib.eof()): Why is iostream::eof inside a loop condition (i.e. while (!stream.eof())) considered wrong?
You can remove the first loadData()
You can remove the second parameter of void sortByTitle(int count)
You are shadowing global variables with local variables, e.g. global ifstream lib and local ifstream lib in int loadData()
You can remove unused variables
You should remove using namespace std;: Why is “using namespace std;” considered bad practice?
You should avoid global variables
You should replace endl by '\n' if you don't need to flush in that moment. endl does more than a simple linebreak and usually it's not necessary.
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
using std::cin;
using std::cout;
using std::ifstream;
using std::string;
// structure
struct Book {
string title;
string author;
};
const int ARRAY_SIZE = 1000;
// global variables
int loadData(string pathName, Book *books);
void showAll(Book *books, int count);
void sortByTitle(Book *books, int count);
int main()
{
// initialised variables
int count = 0;
char selector = 'q';
// asks user for file pathname
cout << "Welcome to Tommy's Library Database.\n";
cout << "Please enter the name of the file: ";
string pathName;
getline(cin, pathName);
Book books[ARRAY_SIZE];
count = loadData(pathName, books);
cout << count << " Records loaded successfully.\n";
// Switch case menu
do {
cout << "\nPlease enter a keyword that corresponds to the list of options: \n";
cout << " Search by: (A)uthor, (T)itle, (S)how All, (Q)uit Program: ";
cin >> selector;
selector = toupper(selector);
switch (selector)
{
case 'S':
sortByTitle(books, count);
if (count <= 0) {
cout << " No counts found! \n";
}
else {
showAll(books, count);
}
break;
}
}
while (selector != 'q' && selector != 'Q');
return 0;
}
int loadData(string pathName, Book *books)
{
int count = 0;
ifstream lib(pathName);
if (!lib)
{
cout << " Unable to open file path! \n";
return -1;
}
while (getline(lib, books[count].title))
{
getline(lib, books[count].author);
count++;
}
return count;
}
// displays all book titles beside the author names
void showAll(Book *books, int count)
{
for (int i = 0; i < count; i++)
{
cout << books[i].title << " " << "(" << books[i].author << ")\n";
}
}
// Sorts by book title.
void sortByTitle(Book *books, int count) {
std::sort(books, books + count, [](const auto &lhs, const auto &rhs) {
return lhs.title < rhs.title;
});
}

Related

Dealing with file io in c++

I have a program that takes input for names and outputs the last names in a string. The task I have now is to include FileIO in it. Specifically, "get user input for the filename, and then read the names from the file and form the last name string."
When I run the program, the console will show the name string from the text file. But only initially. As you keep entering names, that string disappears. Also, my user input for file name seems to be doing nothing, because I can enter anything and it still show the string of last names from the text file.
Here is what I have so far. Included all of it, just to make sure.
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <fstream>
using namespace std;
// function declerations
int Menu();
void getName(vector<string> &names, int &count);
void displayName(vector<string> &names, int count);
string getLastNames(vector<string> &names, int count);
int main()
{
vector<string> names;
int count = 0;
int choice = Menu();
ifstream File;
string line;
cout << "Enter file name: ";
getline(cin,line);
File.open("File.txt");
while(File.good()){
getline(File,line);
cout << line << endl;
}
File.close();
while (choice != 0)
{
// switch statement to call functions based on users input
switch (choice)
{
case 1: {
getName(names, count);
} break;
case 2: { displayName(names, count); } break;
case 3: {
cout << getLastNames(names, count) << endl;
} break;
case 0: {
return 0;
} break;
}
choice = Menu();
}
return 0;
}
// function definition for vector of strings
void getName(vector<string> &names, int &count)
{
string name;
// get input for name
cout << "Enter name: ";
getline(cin, name);
// find position of space in string
int pos = name.find(' ');
// reverse order of name
if(pos != -1) {
string first = name.substr(0, pos);
string last = name.substr(pos+1);
name = last + "," + first;
}
// add name to end of vector
names.push_back(name);
count++;
}
// give user option of what to do
int Menu() {
int choice;
cout << "1. Add a name" << endl;
cout << "2. Display names " << endl;
cout << "3. Show all Last Names" << endl;
cout << "0. Quit" << endl;
cout << "Enter a option: ";
cin >> choice;
// if outside of above choices, print 'choice not on list'
while (choice < 0 || choice > 3)
{
cout << "Choice not on list: ";
cin >> choice;
}
cin.ignore();
return choice;
}
// defining function that gets last names
string getLastNames(vector<string> &names, int count) {
stringstream ss;
for (int i = 0; i<count; i++)
{
int pos = names[i].find(',');
if (pos != -1) {
ss << "\"" << names[i].substr(0, pos) << "\", ";
} else {
ss << "\"" << names[i] << "\", ";
}
}
return ss.str();
}
// display the names
void displayName(vector<string> &names, int count)
{
if (count == 0)
{
cout << "No names to display" << endl;
return;
}
for (int i = 0; i<count; i++)
{
cout << names[i] << endl;
}
}

My Ifstream reference is not working although it did in similar previous function

I have a file I want to continue calling on in different functions in my program. It worked fine as a reference in the shiftText function but when I repeated the reference in the next function, all that returns is 0,
Can I get a small hint at something I am missing perhaps to make it behave this way? Thanks!
(PS there's definitely a lot of 'fat' in this that I have included for testing purposes only)
I will eventually return the value of "e" into the shiftText function if you were curious why that's there :)
#include <iostream>
#include <cmath>
#include <fstream>
#include <cctype>
#include <string>
using namespace std;
void inputfile(ifstream &masterfile) // ask for file name
{
string filename;
cout << "Please enter the name and extension of your file " << endl;
cin >> filename;
masterfile.open(filename);
if (!masterfile)
{
cout << "warning: cannot open file" << endl;
exit(1);
}
}
int findShift(ifstream &file, int counter[]) // find most used char
{
char ch;
int code;
while (file.get(ch))
{
code = static_cast<int>(ch);
cout << code << " ";
counter[code]++;
}
int max, min;
int indexMax, indexMin;
max = counter[65];
indexMax = 65;
min = counter[65];
indexMin = 65;
for (int i = 66; i <= 122; i++)
{
if (counter[i] > max)
{
max = counter[i];
indexMax = i;
}
if (counter[i] < min)
{
min = counter[i];
indexMin = i;
}
}
cout << endl
<< "Most frequent was " << indexMax;
return indexMax;
}
void shiftText(ifstream &file) // this is where my program skips over my ifstream reference
{
char ch;
int code;
while (file.get(ch))
{
code = static_cast<int>(ch);
cout << code << " ";
}
}
char stopFlashing() // for sanity
{
char reply;
cout << endl
<< "Press q (or any other key) followed by 'Enter' to quit: ";
cin >> reply;
return 0;
}
int main()
{
int counter[256] = {0};
ifstream file;
inputfile(file);
int e = findShift(file, counter);
shiftText(file);
cout << endl << " " << file << " " << endl; // for testing, a zero is returned
stopFlashing();
}
In function findShift you loop over the file. In function shiftText you are trying to do the same. However, the file is already at its end. Before calling shiftText you should rewind the file by using seekg:
file.seekg(0, std::ios_base::beg)

Almost all forms of String comparisons are not working in C++ 11

So I am doing a school project that requires me to execute my program with arguments and display the contents of a file based on a particular action.
This is done by simply requesting the action after the file name is specified.
It is:
./executable_name 'filename' 'action'
actions include list or find. List will list all the book contents of the specific file in that order and find will find a book by it's ISBN number specified.
Now my error lies with the find function, more specifically how i compare the Strings. I cannot compare the strings within the "find" function for the life of me. Ive tried "strcmp()" with the ".c_str()", I've tried "==", I've tried "string.copmare(string2)", and nothing. I have developed some interesting clues though.
If I try to print the string from my array of arguments concatenated with a few letters it properly does some expected printing, BUT if I perform the same action from the struct instance of any particular book array it seems to be overwritten like a return carriage type.
EX:
argv[4] = 0-201-60464-7 near here
books[0].isbn = near here-60464-7
Driver File
##include"book.h"
#include<iostream>
#include<string>
#include<fstream>
#include<cstring>
using namespace std;
int main(int argc, char** argv)
{
//The structure of the book will also incorporate an array to
//acommadate more books
Book books[35];
string filename = argv[1];
int filesRead = read (filename, books);
if(string(argv[2])== "list")
{
for(int index =0;index < filesRead; index++ )
{
cout << books[index].title << endl;
cout << books[index].authorCount<< endl;
for(int j =0; j < books[index].authorCount; j++)
{
cout << books[index].authors[j] << endl;
}
cout << books[index].publisher <<endl;
cout << books[index].yearPublish <<endl;
cout << books[index].hardcover << endl;
cout << books[index].price << endl;
cout << books[index].isbn << endl;
cout << books[index].copies << endl;
}
}
if(argc > 3)
{
if(string(argv[2]) == "find")
{
int book_index = find(argv[3], books, filesRead);
if(book_index < 0)
{
cout << "Not found" << endl;
}
cout << books[book_index].title << endl;
cout << books[book_index].authorCount<< endl;
for(int j =0; j < books[book_index].authorCount; j++)
{
cout << books[book_index].authors[j];
}
cout << books[book_index].publisher <<endl;
cout << books[book_index].yearPublish <<endl;
cout << books[book_index].hardcover << endl;
cout << books[book_index].price << endl;
cout << books[book_index].isbn << endl;
cout << books[book_index].copies << endl;
}
}
}
Function file
#include"book.h"
#include<iostream>
#include<string>
#include<fstream>
#include<cstring>
using namespace std;
int read (string filename, Book books[])
{
ifstream inputFile(filename);
//validation for the file itself
if(!inputFile)
{
cout << "File does not exist!" << endl;
}
//use a mix of get line and ifstream
//created a temporary string to consume lines
//from primitive data types
int counter =0;
string consume_line;
while(counter < 35 && getline(inputFile, books[counter].title))
{
inputFile >> books[counter].authorCount;
getline(inputFile, consume_line);
for(int j =0; j < books[counter].authorCount; j++)
{
getline(inputFile, books[counter].authors[j]);
}
getline(inputFile, books[counter].publisher);
inputFile >> books[counter].yearPublish;
inputFile >> books[counter].hardcover;
inputFile >> books[counter].price;
getline(inputFile, consume_line);
getline(inputFile, books[counter].isbn);
inputFile >> books[counter].copies;
getline(inputFile, consume_line);
if(inputFile.eof())
{
break;
}
counter++;
}
return counter;
}
int find(string id, Book books[], int length)
{
int found=0;
for(int index = 0; index < length; index++)
{
string test =books[index].isbn;
if(id.compare(test)==0)
{
found = index;
break;
}
if(id > test)
{
cout << "greater than" << endl;
found = -1;
break;
}
if(id < test)
{
cout << "less than" << endl;
found =-1;
break;
}
}
return found;
}
Header File
// #file book.h
#ifndef BOOK_H
#define BOOK_H
#include <string>
using namespace std;
const int MAX_AUTHORS = 20;
struct Book {
string title;
string authors[MAX_AUTHORS];
short authorCount;
string publisher;
short yearPublish;
bool hardcover;
float price;
string isbn;
long copies;
};
/**
* #param filename name of the input data file
* #param books[] an array of textbook records read from the file
*
* #return the number of textbook records read
*/
int read (string filename, Book books[]);
/**
* #param id the ISBN number to search for
* #param books[] the list of textbook records
* #param length the number of textbook records in the array
*
* #return the array index of the matching record, otherwise it returns -1
*/
int find (string id, Book books[], int length);
#endif /* BOOK_H */
condensed Code
e
#include<iostream>
#include<string>
#include<fstream>
#include<cstring>
using namespace std;
const int MAX_AUTHORS = 20;
struct Book {
string title;
string authors[MAX_AUTHORS];
short authorCount;
string publisher;
short yearPublish;
bool hardcover;
float price;
string isbn;
long copies;
};
int read (string filename, Book books[])
{
ifstream inputFile(filename);
//validation for the file itself
if(!inputFile)
{
cout << "File does not exist!" << endl;
}
//use a mix of get line and ifstream
//created a temporary string to consume lines
//from primitive data types
int counter =0;
string consume_line;
while(counter < 35 && getline(inputFile, books[counter].title))
{
inputFile >> books[counter].authorCount;
getline(inputFile, consume_line);
for(int j =0; j < books[counter].authorCount; j++)
{
getline(inputFile, books[counter].authors[j]);
}
getline(inputFile, books[counter].publisher);
inputFile >> books[counter].yearPublish;
inputFile >> books[counter].hardcover;
inputFile >> books[counter].price;
getline(inputFile, consume_line);
getline(inputFile, books[counter].isbn);
inputFile >> books[counter].copies;
getline(inputFile, consume_line);
if(inputFile.eof())
{
break;
}
counter++;
}
return counter;
}
int find(string id, Book books[], int length)
{
int found=0;
for(int index = 0; index < length; index++)
{
string test =books[index].isbn;
if(id.compare(test)==0)
{
found = index;
break;
}
if(id > test)
{
cout << "greater than" << endl;
found = -1;
break;
}
if(id < test)
{
cout << "less than" << endl;
found =-1;
break;
}
}
return found;
}
int main(int argc, char** argv)
{
//The structure of the book will also incorporate an array to
//acommadate more books
Book books[35];
string filename = "test3.txt";
string isbn = "0-201-60464-7";
int filesRead = read (filename, books);
int book_index = find(isbn, books, filesRead);
if(book_index < 0)
{
cout << "Not found" << endl;
}
cout << books[book_index].title << endl;
cout << books[book_index].authorCount<< endl;
for(int j =0; j < books[book_index].authorCount; j++)
{
cout << books[book_index].authors[j];
}
cout << books[book_index].publisher <<endl;
cout << books[book_index].yearPublish <<endl;
cout << books[book_index].hardcover << endl;
cout << books[book_index].price << endl;
cout << books[book_index].isbn << endl;
cout << books[book_index].copies << endl;
}
test file in txt or dat whichever extension preferred
#file.txt
C++ Network Programming – Volume 1
2
Douglas C. Schmidt
Stephen D. Huston
Addison-Wesley
2002
0
35.99
0-201-60464-7
236
refactored to one compilation unit and zero test files.
Fixed logic errors
added some (hopefully explanatory) comments
added handling of windows-style line endings for increased portability
Note: Avoid the use of using namespace at global scope. A reasonable exception to this rule is using namespace std::literals;
#include<iostream>
#include<string>
#include<fstream>
#include<cstring>
#include <sstream>
using namespace std;
const int MAX_AUTHORS = 20;
struct Book {
string title;
string authors[MAX_AUTHORS];
short authorCount;
string publisher;
short yearPublish;
bool hardcover;
float price;
string isbn;
long copies;
};
void strip(std::string& str)
{
if (str.size() && str.back() == '\r')
{
str.pop_back();
}
}
std::istream& get_line_and_strip(std::istream& is, std::string& result)
{
std::getline(is, result);
strip(result);
return is;
}
// be specific about the bounds of the output variable.
int read (std::istream& inputFile, Book books[35])
{
//validation for the file itself
if(!inputFile)
{
std::cout << "File does not exist!" << std::endl;
// avoid UB by returning a value as per the function signature
return 0;
}
//use a mix of get line and ifstream
//created a temporary string to consume lines
//from primitive data types
int counter =0;
std::string consume_line;
while(counter < 35)
{
get_line_and_strip(inputFile, books[counter].title);
inputFile >> books[counter].authorCount;
std::getline(inputFile, consume_line);
for(int j =0; j < books[counter].authorCount; j++)
{
get_line_and_strip(inputFile, books[counter].authors[j]);
}
get_line_and_strip(inputFile, books[counter].publisher);
inputFile >> books[counter].yearPublish;
std::getline(inputFile, consume_line);
inputFile >> books[counter].hardcover;
std::getline(inputFile, consume_line);
inputFile >> books[counter].price;
std::getline(inputFile, consume_line);
get_line_and_strip(inputFile, books[counter].isbn);
inputFile >> books[counter].copies;
std::getline(inputFile, consume_line);
if(!inputFile) // tests for EOF or error during input
{
break;
}
counter++;
}
return counter;
}
int find(string id, Book books[35], int length)
{
int found=0;
for(int index = 0; index < length; index++)
{
string test =books[index].isbn;
if(id.compare(test)==0)
{
found = index;
break;
}
if(id > test)
{
cout << "greater than" << endl;
found = -1;
break;
}
if(id < test)
{
cout << "less than" << endl;
found =-1;
break;
}
}
return found;
}
auto test_data = ""
"C++ Network Programming – Volume 1\r\n"
"2\r\n"
"Douglas C. Schmidt\r\n"
"Stephen D. Huston\r\n"
"Addison-Wesley\r\n"
"2002\r\n"
"0\r\n"
"35.99\r\n"
"0-201-60464-7\r\n"
"236\r\n"
""s;
int main(int argc, char** argv)
{
//The structure of the book will also incorporate an array to
//acommadate more books
Book books[35];
string filename = "test3.txt";
string isbn = "0-201-60464-7";
auto test_file = std::istringstream(test_data);
int filesRead = read (test_file, books);
int book_index = find(isbn, books, filesRead);
if(book_index < 0)
{
cout << "Not found" << endl;
// would be invalid to continue if book not found
return 0;
}
cout << books[book_index].title << endl;
cout << books[book_index].authorCount<< endl;
for(int j =0; j < books[book_index].authorCount; j++)
{
cout << books[book_index].authors[j] <<endl;
}
cout << books[book_index].publisher <<endl;
cout << books[book_index].yearPublish <<endl;
cout << books[book_index].hardcover << endl;
cout << books[book_index].price << endl;
cout << books[book_index].isbn << endl;
cout << books[book_index].copies << endl;
}
Expected output:
C++ Network Programming – Volume 1
2
Douglas C. Schmidt
Stephen D. Huston
Addison-Wesley
2002
0
35.99
0-201-60464-7
236
https://coliru.stacked-crooked.com/a/9b08598ffcd0edc2

Extra string outputs if user input is more than one word

This is my first time asking a question on here, so be gentle lol. I wrote up some code for an assignment designed to take information from a (library.txt datatbase) file, store it in arrays, then access/search those arrays by title/author then output that information for the user based on what the user enters.
The issue I am having is, whenever the user enters in a search term longer than one word, the output of "Enter Q to (Q)uit, Search (A)uthor, Search (T)itle, (S)how All: " is repeated several times before closing.
I am just looking to make this worthy of my professor lol. Please help me.
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
using namespace std;
struct Book
{
string title;
string author;
};
int loadData(string pathname);
char switchoutput();
void showAll(int count);
int showBooksByAuthor(int count, string name);
int showBooksByTitle(int count, string title);
int FindAuthor(int count, string userinput);
int FindTitle(int count, string userinput);
void ConvertStringToLowerCase(const string orig, string& lwr); //I found this program useful to convert any given string to lowercase, regardless of user input
const int ARRAY_SIZE = 1000;
Book books[ARRAY_SIZE];
int main()
{
string pathname;
string name;
string booktitle;
int count = 0;
int counta = 0;
int countt = 0;
char input = 0;
cout << "Welcome to Jacob's Library Database." << endl;
cout << "Please enter the name of the backup file: " ;
cin >> pathname;
count = loadData(pathname);
cout << count << " records found in the database." << endl;
while (toupper(input != 'Q'))
{
input = switchoutput(); // function call for switchoutput function
switch (input)
{
case 'A':
cout << "Author's Name: ";
cin >> name;
counta = showBooksByAuthor(count, name);
cout << counta << " records found." << endl;
break;
case 'T':
cout << "Book Title: ";
cin >> booktitle;
countt = showBooksByTitle(count, booktitle);
cout << countt << " records found." << endl;
break;
case 'S':
showAll(count);
break;
case 'Q':
break;
}
}
//Pause and exit
cout << endl << "Press 'ENTER' to quit";
getchar();
getchar();
return 0;
}
int loadData(string pathname) //loading data into the array of structs
{
ifstream inFile;
inFile.open(pathname);
if (!inFile) {
cout << "Error, could not read into file. Please re-compile." << endl;
system("PAUSE");
exit(1); //if not in file, exit;
}
int i = 0;
while (!inFile.eof()) {
getline(inFile, books[i].title);
getline(inFile, books[i].author);
i++;
}
return i;
}
char switchoutput() //seperate output function to get my characteroutput constantly resetting and returning the uppercase version for my switch
{
char input;
cout << "Enter Q to (Q)uit, Search (A)uthor, Search (T)itle, (S)how All: ";
cin >> input;
return toupper(input);
}
int showBooksByAuthor(int count, string name)
{
int authorcount = 0;
authorcount = FindAuthor(count, name);
return authorcount;
}
int showBooksByTitle(int count, string title)
{
int titlecount = 0;
titlecount = FindTitle(count, title);
return titlecount;
}
void showAll(int count)
{
for (int i = 0; i < count; i++)
{
cout << books[i].title << " (" << books[i].author << ")" << endl;
}
}
int FindAuthor(int count, string userinput)
{
int authorcount = 0;
string stringlower, arraylower;
int num;
// called upon function to lowercase any of the user inputs
ConvertStringToLowerCase(userinput, stringlower);
for (int i = 0; i < count; ++i) //this function's count determines at which locations to output the author and names (an argument from books by author)
{
// called upon function to lowercase any of the stored authors'
ConvertStringToLowerCase(books[i].author, arraylower);
num = arraylower.find(stringlower); // searches string for userinput (in the lowered array) and stores its value
if (num > -1) // you can never get a -1 input value from an array, thus this loop continues until execution
{
cout << books[i].title << " (" << books[i].author << ")" << endl; //cout book title and book author
authorcount++; //count
}
}
return authorcount;
}
int FindTitle(int count, string userinput) //same as previous but for titles
{
int titlecount = 0;
string stringlower, arraylower;
int num;
ConvertStringToLowerCase(userinput, stringlower);
for (int i = 0; i < count; ++i)
{
ConvertStringToLowerCase(books[i].title, arraylower);
num = arraylower.find(stringlower);
if (num > -1)
{
cout << books[i].title << " (" << books[i].author << ")" << endl;
titlecount++; //count
}
}
return titlecount;
}
void ConvertStringToLowerCase(const string orig, string& lwr) // I found this from another classmate during tutoring, I thought to be useful.
{
lwr = orig;
for (int j = 0; j < orig.length(); ++j) //when called upon in my find functions, it takes the string and convers the string into an array of lowercase letters
{
lwr[j] = tolower(orig.at(j));
}
}

C++ Searching a String Array for every instance of a user given search term.

Ok. So I have an assignment that loads a file of books and their authors sequential lines. I've got the titles loading into book title array and book authors into book author array.
I need the following to happen.
Show all books and authors. <<< completed.
Show ALL books and authors from user input AUTHOR search string. << semi works
Show ALL books and authors from user input BOOK search string. << semi works
The last two are having problems by the way of
Author function.
User input : Malik
output: 0 authors found! (14 times)
Same for the title query.
I've scoured the net, read my book a million times. OK maybe not that much. Tried a hundred different versions of code and still hurting.
Any help would be great!
Here is my code.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
//these declarations should be at file scope
const int ARRAY_SIZE = 1000;
string bookTitle [ARRAY_SIZE];
string bookAuthor [ARRAY_SIZE];
int nob = 0;
ifstream dataBase;
// Function prototypes
int loadData(string pathName);//complete
void showAll(int nob);
int showBooksByAuthor (int nob, string name);
int showBooksByTitle (int nob, string title);
void showChoices();
int main()
{
string pathName;
int x = 1;
char menu;
cout << "Welcome to Phil's Library Database. " << endl;
cout << "Enter the location of the Database: (ex: c:/filename.txt ";
cin >> pathName;
//read pathName and input data to arrays
dataBase.open(pathName);
loadData(pathName);
//output number of files loaded
cout << nob <<" records loaded successfully." <<endl;
string name;
string title;
while(x == 1)
{
//prompt User for what they want to do
cout << "Enter Q to (Q)uit, Search (A)uthor, Search (T)itle, (S)how All: ";
cin >> menu;
switch(menu)
{
case 'Q':
case 'q':
//exit out of program
x = 3;
break;
case 'A':
case 'a':
cout << "Author's Name: ";
getline (cin, name, '\n');
//list books by author
showBooksByAuthor (nob,name);
break;
case 'T':
case 't':
cout << "Book Title: ";
getline (cin, title, '\n');
showBooksByTitle (nob, title);
break;
case 'S':
case 's':
//cout the entire documents array-ed contents
showAll(nob);
break;
}
}
system("pause");
getchar();
return 0;
}
int loadData(string pathName)
{
if(dataBase.is_open())
{
while(!dataBase.eof())
{
getline(dataBase, bookTitle[nob], '\n');
getline(dataBase, bookAuthor[nob], '\n');
nob += 1;
}
dataBase.clear();
dataBase.seekg(0);
return nob;
}
else
cout << "Bad file path!"<< endl;
return -1;
}
//showall Function
void showAll(int nob)
{
for (int i = 0; i < nob; i++)
{
//show all content of each array
cout << bookTitle[i]<<endl;
cout << bookAuthor[i]<<endl;
}
}
//showall books based on Author
int showBooksByAuthor (int nob, string name)
{
int x = 0;
for(int i = 0; i < nob; i++)
{
if (bookAuthor[i].find(name))
{
//output array location data
cout << bookTitle[i];
cout << "(" << bookAuthor[i] << ")" << endl;
//add onto counter for output of successfully searched items
x++;
}
cout << x << " Records found. " << endl;
}
return x;
}
//showall books based on Title
int showBooksByTitle (int nob, string title)
{
int x = 0;
for(int i = 0; i < nob; i++)
{
if (bookAuthor[i].find(title))
{
//output array location data
cout << bookTitle[i];
cout << "(" << bookAuthor[i] << ")" << endl;
//add onto counter for output of successfully searched items
x++;
}
cout << x << " Records found. " << endl;
}
return x;
}
Thank you in advance!
As per this page, http://www.cplusplus.com/reference/string/string/find/, and this http://www.cplusplus.com/reference/string/string/npos/, the find() method on the String returns -1 when there is no match.
if ( some_num ) is true whenever some_num is non-zero, including -1, where some_num is any expression.
Read the find documentation carefully to understand how it can be used to check for a match.
1) The find function is not necessary. All you need to do is use ==.
2) For the title, you should be testing the bookTitle array, not bookAuthor.
int showBooksByAuthor (int nob, string name)
{
// ...
// Search for author
if ( bookAuthor[i] == name)
{
// name found
}
// ...
}
// Search for title
int showBooksByTitle (int nob, string title)
{
//...
if (bookTitle[i] == title)
{
// title found
}
//...
}