C++ - Class method changes member variable, but not in main - c++

I have a Student class which stores a student's name and registration number. One of the private members of the Student class is a map which stores a student's module code (string), along with the mark for the module (float).
The class has an 'addMark' function which takes a module code and the mark for that module. If the module already exists in the map, the mark is overwritten. Otherwise, it is inserted into the map.
void Student::addMark(const string &module, float mark)
{
map<string, float>::iterator iter = marks.find(module);
if (iter != marks.end()){marks[module] = mark;}
else{marks.insert({module, mark});}
}
I have checked, and this seems to work inside that function.
In the main function, I have a vector markLine which stores each token of a line in a text file containing the marks. The first token (markLine.at(0)) is the registration number, the second token is the module code, and the third token is the mark. So the vector might look like the following for a line:
markLine = {10105, "CE101", 78.5};
Anyway, after reading a line and storing each token, the module mark needs to be stored for the correct student, so I use a for loop to go through all the students and see if their registration number matches. If it does, the mark is added:
for (Student st: studVect)
{
if (st.getRegNo() == markLine.at(0))
{
st.addMark(markLine.at(1), markLine.at(2));
}
}
But when I check afterwards to see if the marks have changed for a student, they have not.
I've googled around a lot and found some questions quite similar to mine, and I have a feeling that this is something to do with references, and a copy of marks being created. However, I'm not really sure where exactly I need to be using a reference. If anyone could point me in the right direction, I would be grateful.

You're working with a copy of the Student record.
Change
for (Student st: studVect)
to
for (Student &st: studVect)

Related

How to choose randomly from a list, inside a dictionary

I have been trying to make a "Workout Generator" that uses my input to give me a gym workout that focuses on specific muscles or body parts depending on my choice ("input").
I am stuck because I am now trying to get a random workout from a list (Which is a dictionary value) while being in a randomly chosen key inside a dictionary.
This is my first solo project and nothing i have tried has been working so far and I really want to be able to complete this :)
Here is the code so far, I have put the line of code that accepts input as a note so that when i run to test i dont have to keep inputing the same thing, and also made a note the second line of code in my if statement because if I fix this problem with the first one then I can repeat the same for the second one.
Here is a sample of the code
import random
choose_workout = input("Enter body area here: ")
upper_body_cb = {
"chest" : ["Bench press" , "Pushups"],
"back" : ["Lateral Pulldown" , "Pull Up"]
}
random_upper_cb = print(random.choice(list(upper_body_cb.values())))
if choose_workout == "upper c":
print(random_upper_cb)

TypeError: unbound method loadDisplacement() must be called with person instance as first argument (got float64 instance instead)

This is the code I have written so far:
I am very new to python so am trying to use the most basic ways of accomplishing goals as possible as I currently don't know how to make it more efficient etc.
def simulateBeamRun(personlist, beam, times):
times = np.linspace(0,35,500)
templist = []
maxdeflectionlist = []
for t in times:
for i in personlist: #for each person instance
Tuple = personModel.person.loadDisplacement(t)
if 0 < Tuple(1) < beamModel.beam.L:
templist.append(Tuple)
else:
pass
return templist
File "beamSimulation.py", line 40, in simulateBeamRun
Tuple = personModel.person.loadDisplacement(t)
The error I am getting is:
TypeError: unbound method loadDisplacement() must be called with person instance as first argument (got float64 instance instead)
personlist is a list of lists each containing arrivalTime, weight, gait, speed for a given "person". This is so that it gives values to the constructor. Load displacement is the only other function in the person class:
class person(object):
"""This class models the displacement of a person's load as they run at
'speed' in one dimension. It assumes that the load is always concentrated
in a single point and that the displacement of that point is less than or
equal to the displacement of the person's centre of mass. Also the
displacement of the load will always be a multiple of 'gait'.
"""
def __init__(self, arrivalTime, weight, gait, speed):
"""This constructor function defines the person's weight, gait and
running speed as well as the time that they arrive at the position of
zero displacement.
"""
how do I fix this?
Given the limited code presented, some of this is just guessing, but it might point you in the right direction, at least:
There's no need to pass in the times argument if you're just going to immediately overwrite it with times = ....
You're not using maxdeflectionlist for anything, so it's not really needed (although maybe you're planning to later...).
Inside your for i in ... loop, i is your iteration variable, and should take each value successively from personlist. Guessing from variable names, these might be the person instances that you need to get displacements from, so the line that you're getting the error on should maybe be Tuple = i.loadDisplacement(t). If that's not the case, given your later comments, perhaps you need to instantiate a person object from the data in i - something like p = personModel.person(some, arguments, extracted, from, i), and then follow that with Tuple = p.loadDisplacement(t). Calling loadDisplacement() as you have is more appropriate for a class method or static method, not for an instance method, which is the essential meaning behind the error message you get. It's telling you that personModel.person is not a person instance - it's probably a class object.
The else: pass bit is sort of pointless.

c++ searching and sorting in student list

What I want to do is to make a searching engine for searching student`s grade in student list with student number and student name. If multiple students match the requested name, the system will ask the user to enter the student id.
I have done the read txt file, however, I stopped at changing txt to array for storing and searching. I don't know how to store those data into array.
I got 20 students and here's two examples of student's grading in each subject:
SS6709 Peter VT001 C VT002 E VT003 D VT004 D VT009 A+ VY018 A++ VT024 B
SS9830 Amy VT001 D VT002 C VT003 C VT004 D VT009 D VT018 D VT023 B
think and define a class Item that will represent a single item that will hold the data about a single student (code, name, ...)
create an empty std::vector of those structures that will hold your "items"
open the file for reading
read the file line-by-line (use std::getline to get WHOLE lines, not just filestream.getline or file >> var operator)
(for each line that you read)
read the line as std::string, just as std::getline wants
create a Item for holding next group of data
analyze the line and cut/copy the student's code into myItem.code
analyze the line and cut/copy the student's name into myItem.name
analyze the line and cut/copy the XXXXXXXXXXXXXX into myItem.whateverelse
append the myItem that you have just read to the vector that you prepared earlier
close the file after reading all lines
Now you have a 'vector' that holds all the data, nicely stored as "items" that each have a code, name, and other data. You can now loop/search over that vector to find if any name or code matches.
it looks like you need to create your own data structure to store the values. You can define your own struct
struct Student{
string name
string iD
....
};
and use a array of type in this case Student
Student data_base[100];
this is a very basic approach but it should get you going...

String formatting issue when using a function

I have what I believe to be an embarrassingly simple problem, but three hours of googling and checking stackoverflow have not helped.
Let's say I have a very simple piece of code:
def secret_formula(started):
jelly_beans = started*500
jars = jelly_beans/1000
crates = jars/100
return jelly_beans,jars,crates
start_point = 10000
print("We'd have {} beans, {} jars, and {} crates.".format(secret_formula(start_point)))
What happens is I get the "IndexError: tuple index out of range". So I just print the secret_formula function to see what it looks like, and it looks like this:
(5000000, 5000.0, 50.0)
Basically, it is treating the output as one 'thing' (I am still very new, sorry if my language is not correct). My question is, why does it treat it like this and how do I make it pass the three outputs (jelly_beans, jars, and crates) so that it formats the string properly?
Thanks!
The format function of the string take a variable number of argument. The secret_formula function is returning a tuple. You want to convert that to a list of arguments. This is done using the following syntax:
print("We'd have {} beans, {} jars, and {} crates.".format(*secret_formula(start_point)))
The important par is the * character. It tell that you want to convert the following iterable into a list of argument to pass to the function.

String extraction

Currently I am working very basic game using the C++ environment. The game used to be a school project but now that I am done with that programming class, I wanted to expand my skills and put some more flourish on this old assignment.
I have already made a lot of changes that I am pleased with. I have centralized all the data into folder hierarchies and I have gotten the code to read those locations.
However my problem stems from a very fundamental flaw that has been stumping me.
In order to access the image data that I am using I have used the code:
string imageLocation = "..\\DATA\\Images\\";
string bowImage = imageLocation + "bow.png";
The problem is that when the player picks up an item on the gameboard my code is supposed to use the code:
hud.addLine("You picked up a " + (*itt)->name() + "!");
to print to the command line, "You picked up a Bow!". But instead it shows "You picked up a ..\DATA\Images\!".
Before I centralized my data I used to use:
name_(item_name.substr(0, item_name.find('.')))
in my Item class constructor to chop the item name to just something like bow or candle. After I changed how my data was structured I realized that I would have to change how I chop the name down to the same simple 'bow' or 'candle'.
I have changed the above code to reflect my changes in data structure to be:
name_(item_name.substr(item_name.find("..\\DATA\\Images\\"), item_name.find(".png")))
but unfortunately as I alluded to earlier this change of code is not working as well as I planned it to be.
So now that I have given that real long winded introduction to what my problem is, here is my question.
How do you extract the middle of a string between two sections that you do not want? Also that middle part that is your target is of an unknown length.
Thank you so very much for any help you guys can give. If you need anymore information please ask; I will be more than happy to upload part or even my entire code for more help. Again thank you very much.
In all honeasty, you're probably approaching this from the wrong end.
Your item class should have a string "bow", in a private member. The function Item::GetFilePath would then (at runtime) do "..\DATA\Images\" + this->name + ".png".
The fundamental property of the "bow" item object isn't the filename bow.png, but the fact that it's a "bow". The filename is just a derived proerty.
Assuming I understand you correctly, the short version of your question is: how do I split a string containing a file path so I have removed the path and the extension, leaving just the "title"?
You need the find_last_of method. This gets rid of the path:
std::size_type lastSlash = filePath.find_last_of('\\');
if (lastSlash == std::string::npos)
fileName = filePath;
else
fileName = filePath.substr(lastSlash + 1);
Note that you might want to define a constant as \\ in case you need to change it for other platforms. Not all OS file systems use \\ to separate path segments.
Also note that you also need to use find_last_of for the extension dot as well, because filenames in general can contain dots, throughout their paths. Only the very last one indicates the start of the extension:
std::size_type lastDot = fileName.find_last_of('.');
if (lastDot == std::string::npos)
{
title = fileName;
}
else
{
title = fileName.substr(0, lastDot);
extension = fileName.substr(lastDot + 1);
}
See http://msdn.microsoft.com/en-us/library/3y5atza0(VS.80).aspx
using boost filesystem:
#include "boost/filesystem.hpp"
namespace fs = boost::filesystem;
void some_function(void)
{
string imageLocation = "..\\DATA\\Images\\";
string bowImage = imageLocation + "bow.png";
fs::path image_path( bowImage );
hud.addLine("You picked up a " + image_path.filename() + "!"); //prints: You picked up a bow!
So combining Paul's and my thoughts, try something like this (broken down for readability):
string extn = item_name.substr(item_name.find_last_of(".png"));
string path = item_name.substr(0, item_name.find("..\\DATA\\Images\\"));
name_ = item_name.substr( path.size(), item_name.size() - extn.size() );
You could simplify it a bit if you know that item name always starts with "..DATA" etc (you could store it in a constant and not need to search for it in the string)
Edit: Changed extension finding part to use find_last_of, as suggested by EarWicker, (this avoids the case where your path includes '.png' somewhere before the extension)
item_name.find("..\DATA\Images\") will return the index at which the substring "..\DATA\Images\" starts but it seems like you'd want the index where it ends, so you should add the length of "..\DATA\Images\" to the index returned by find.
Also, as hamishmcn pointed out, the second argument to substr should be the number of chars to return, which would be the index where ".png" starts minus the index where "..\DATA\Images\" ends, I think.
One thing that looks wrong is that the second parameter to substr should be the number of chars to copy, not the position.