logic issue or something more? - c++

My program simulates a video store. In my list there are multiple copies of some videos. If I try to rent a video and the first copy of that video in the list is already rented, my program fails to continue checking to see if the other copies are available (a film is available if custId is '0000'). Take a look at the text file from where the list gets its members for a better understanding of what i'm describing:
Could anyone take a look and let me know if they spot an issue? Any help is appreciated, thanks.
Code from main
try
{
int index = 0;
bool found = false;
while (!found)
{
if (strncmp(filmId,filmList.getAt(index).number,6) == 0 && strncmp("0000",filmList.getAt(index).rent_id,5) == 0)//If that film is rented by NO customer
{
found = true;//customer can rent it
strcpy(newItem.number,filmId);//copy filmId into newItem
filmList.retrieve(newItem);//copy the struct in our orderedList with the same filmId/copy into newItem
filmList.remove(newItem);//delete the struct with same filmId/copy as newItem from the orderedList
strcpy(newItem.rent_id,custId);//update info in
strcpy(newItem.rent_date,rentDate);// newItem to show
strcpy(newItem.return_date,dueDate);// that it has been rented
filmList.insert(newItem);//put NewItem into list, effectivily replacing the removed item.
cout << "Rent confirmed!" << endl;
}
else
{
if (strncmp(filmId,filmList.getAt(index).number,6) > 0 || strncmp("0000",filmList.getAt(index).rent_id,5) > 0)
{
++ index;
}
else
{
throw string ("Not in list");
}
}
}
}
catch (string s)
{
cout << "\n***Failure*** " << s << endl;
}
Let me know if more code is required from any other parts of the program.

Here's my best guess with the code provided.
Let's say we are looking up 101001Casablanca, therefore I'm assuming filmId = "101001Casablanca". Also, assume the 101001Casablanca is checked out to customer 0001. We are comparing the first 6 characters of filmId to filmList.getAt(index).number, which I'm going to assume is at the very least "101001". This passes, but since it is checked out the second condition fails.
In the else we check the same strings in the first condition and still get 0 returned from strncmp which is false. The second condition is also false since strncmp("0000", "0001", 5) is -1. Therefore we go to the final else which throws.
If you are only checking string equality with strncmp, remember that it can return -1, therefore check if equal or not equal to 0.

Related

Upgrade Delete Function in Inventory For Text Based Game

I am still a newbie at C++, but I am currently working on a text based game. For my game, I have an Inventory that works, but I want to add a couple functions to it so it is better. I have tried googling around, but I can't find enough help or resources for me to be able to do this myself.
The first thing I am trying to do is when I use my delete function. For the function, I am having the user enter the item they wish to remove from their inventory. I want to be able to check that the user enters an item that exists in their inventory and not make an item up. So after the user enters the item, I take that item and go through the list, check to see if it is there, and then if it is there, delete it, and if it is not there print out an error message.
This is my code so far:
void Inventory::DeleteItem()
{
string deleteitem = " ";
if (item_numbers == 0) {
cout << "\nError: No items in the Inventory.\n\n";
}
else {
cout << "\nPlease type the item you wish to use or take out of the inventory: ";
cin >> deleteitem;
}
bool found = false;
for (int i = 0; i<item_numbers && !found; i++) {
if (Info[i].item_name == deleteitem) {
while(found == true){
cout<<"Found an item matching what you wrote: "<<Info[i].item_name<<endl;
item_numbers--;
cout<<"Item: "<<Info[i].item_name<< " is now gone." <<endl;
break;
}
}
if (found == false){
cout<<"liar"<<endl;
break;
}
}
}
I bet the solution is so simple and I am missing it. I just honestly can't see it. I'm sorry! But I appreciate all the help!
Currently when I test the code, this is how it prints out:
Which item will you be adding to your inventory? Here
Which item will you be adding to your inventory? Now
Please type the item you wish to use or take out of the inventory: Here
liar
You can't delete it in the way you thought the program.
I have done something similar a while ago and my advice is:
1. Use another class "Item" with attribute "Name" and "NumberOfItems"(or more if you want);
2. In the Inventory class add an attribute "vector<Items> MyItems" (it this way you learn about vector as well)
3. when you find the object in your list, you call MyItems.erase(position), where position is the index of your found item.

How to check if element exists in a linked list in c++?

The problem:
Imagine there is a linked list class which has multiple methods to use. The main part of the code is like this:
int main ()
{
List l;
l.push_back (86);
l.push_front (43);
l.push_front (12);
int intToSearchFor = 12;
if (l.exists (intToSearchFor))
{
cout << "(" << intToSearchFor << ") found :)";
}
else
{
cout << "(" << intToSearchFor << ") not found :(";
}
}
As you can see in this piece of code, the List class has two methods to prepend and append new items to the list. And also it has an iterator method which lets us loop over the items and check the data in each node.
The issue?
I want to create a method which check existence of an element. For example l.exists(12) should return either true or false.
My Solution:
Start to loop over the items with iterator.
Check if the item data is equal to the one you are looking for.
If it is equal then return true. Otherwise if there are more items in the list, move into the next item in the list and go to step 2.
If there are no more items in the list return false.
bool List::exists (int x)
{
Iterator it = this->get_iterator ();
do {
if (it.current->data == x) {
return true;
}
it.current = it.current->next;
} while (it.has_more_elements ());
return false;
}
Full answer:
http://cpp.sh/6cfdh
You should check whether a pointer points to nullptr before accessing data pointed by the pointer (see has_more_elements()). Better naming may avoid some confusion.
while(it.current->data!=x && it.has_more_elements())
it.current=it.current->next;
return (it.current->data==x)?true:false;
If x is not present and it reaches end of list, it.current->data will cause run time error as it may be NULL.
while(it.has_more_elements() && it.current->data!=x)
it.current = it.current->next;
return it.current!=NULL;

Determining length for an array allocation

This is the snippet of code that I'm puzzled about. I'm checking for how long an incoming string is. I've appended * in order to have a sentinel value to stop the while loop. Yet, I'm consistently getting a length value that is inclusive of the * and I don't understand why, since the while loop with the nested if ought to stop prior to the *. Can someone point out what I'm doing wrong and why I'm having this issue?
void conversion(string romanIn)
{
length=0;
romanIn.append("*");
while(item!="*")
{
if(item != "*")
{
item = romanIn[length];
length++;
}
cout<<item;
}
you are naturally going to get a +1 the first time through the loop because you aren't initializing the variable "item". Also make it a do while instead of a while loop.
Try this:
do
{
// This line moves out of the if statement
item = romanIn[length];
if(item != "*")
{
length++;
}
cout<<item;
}while(item!="*")
What is the initial value of item?
Let's assume it's 0. You enter the loop
item == 0 != marker, so you enter the if as well, and you say
item = romanIn[0], length++
If romanIn[0] == "*" you will exit the loop, but your length now says 1 which includes the marker

possible misunderstanding of map iterators with for loops

very specific question I'm afraid (and I'm rather a novice, so apologies in advance):
I'm currently trying to finish my final project for a University object-oriented C++ course. I'm creating a student database to store exam results for students. My setup has loads of custom classes but all work perfectly (or at least do what I want them to do).
The project is set up as follows:
I have a "master" map of all "course"s, to which everything points to (so a course isn't duplicated if more than one student is taking it).
A "student" is a vector of pointers to "course"s and a corresponding double "result", and I have a master map of all students in the system.
a "degree" is a class of two vectors of pointers, one to courses offered by that degree, and one to students taking that degree. When a degree is created, it searches both master maps. If the first x letters in a course id matches the degree prefix, the course is added. If a student's subject matches the course name, the student is added.
My problem is this:
As I have some options to manually input courses and students after the initial setup from CSV files, I have writen a function to update my degrees if a course/result is added which should be included in a degree (see below). However, this code inevitably results in the first course and student being re-added (i.e. repeated) to the first degree the first time this function is called. this problem is not repeated if the function is called again. I have absolutely no idea why. A huge amount of time and cout statements later and I'm no closer to solving this. Am I missing something obvious about the first run? I may have set the loops up wrong (I'm not very familiar with maps). Don't hesitate to call me an idiot!
As I have said above, all the rest of the program is gravy, without this odd issue the program is fine. The problem does not appear to come from my print functions either.
Thank you in advance for your time.
//upgrade degrees function: used whenever new courses or students could be created by the user. It ticks through all stored degrees and scans cd and sd. If it finds an unstored course or student that should be stored, they are added.
void degree_database::update_degrees(course_database &cd, student_database &sd) {
cout << "updating degrees..." << endl;
bool found = false;
vector<degree>::iterator current;
for (current = start; current < end; ++current) {
//scan course list
map<string, course>::iterator x;
for (x = cd.get_start(); x != cd.get_end(); ++x) {
if (x->first.substr(0,3) == current->get_prefix().substr(0,3) || current->get_prefix() == "ALL") {
//check to see if course is already stored
vector<course*>::iterator a;
for (a = current->get_c_start(); a < current->get_c_end(); ++a) {
if (*a == &(x->second)) {
found = true;
break;
}
}
//if found == true, then while loop broke early (i.e. the course was already stored).
if (found == false) current->add_course(x->second);
found = false;
}
}
//scan student list
found = false;
map<string, student>::iterator y;
for (y = sd.get_start(); y != sd.get_end(); ++y) {
if (y->second.get_subject() == current->get_name() || current->get_name() == "All") {
//check to see if course is already stored
vector<student*>::iterator b;
for (b = current->get_s_start(); b < current->get_s_end(); ++b) {
if (*b == &(y->second)) {
found = true;
break;
}
}
//if found == true, then while loop broke early (i.e. the student was already stored).
if (found == false) current->add_student(y->second);
found = false;
}
}
}
cout << "done." << endl;
}
You store course by value in the course list and then you use pointer to this object in comparison. Apparently, you shoud store pointers in the map. I think (*a == &(x->second)) fails on the first run and pointer to the object from the course map is added to a degree object. On the second run, (*a == &(x->second)) succeeds and all looks ok. The same for student map.

Finding words that a player says & block it

I am wondering how to basically make the player's sentence stop after it has a swear word in it. Now, I have it already setup, BUT I need to know how to use the tolower method and how to stop it from saying the same word 3 times in a row while using this for loop:
std::size_t found;
std::string word[3] = { "swear", "swear1", "swear2" };
for(int i = 0; i < 3; i++)
{
found = msg.find(word[i]); // needs to have tolower
if(found != std::string::npos)
{
SendNotification("Message blocked. Does it contain swearing?");
return;
}
else
{
GetPlayer()->Say(msg, lang);
}
}
Help would be grateful!
The reason it is only blocking the first word, is because you are Say()ing the message inside the else block as soon as the first word is not matched. Keep a variable bool badWordFound = false before the start of the loop and set it true inside the if(...){ } block. Then, after checking all the words, if badWordFound == true display your warning, else Say()
set found to false
for each swear word
if found in the sentance
set found to true
if found is false
display sentance
else
display warning
HTH
Edit: Also, the comments about caching the filter list in memory are worth following up on if this is anything more than an exercise.