Could anyone please explain me this part of a code? - c++

I stumbled on this syntax while learning file handling.
while(fp.read((char*)&st,sizeof(student)) && found==0)
{
if(strcmpi(st.retadmno(),n)==0)
{
st.show_student();
cout<<"\nEnter The New Details of student"<<endl;
st.modify_student();
int pos=-1*sizeof(st);
fp.seekp(pos,ios::cur);
fp.write((char*)&st,sizeof(student));
cout<<"\n\n\t Record Updated";
found=1;
}
}
Many articles only gave the generic syntax of this comparison but i couldn't find the actual meaning of it. THe syntax is followed by an if statement and is as follows.
Thanks!

This line:
while(fp.read((char*)&st,sizeof(student)) && found==0)
reads a from the file, and if that is successful [1], checks that found is still zero, and enters the rest of the loop.
I personally would do:
while(!found && fp.read(reinterpret_cast<char*>&st, sizeof(student))
instead. That way, you don't read an extra student after writing.
[1] The sucess here is judged by the fact that fp.read returns the istream object that it operates on, and this can be converted to void * (pre-C++11) or bool (C++11 onwards) which reflects the status of fp.good(). In other words, the file is in a state where you can read more from it.

Related

How to make a string into a reference?

I have looked into this, but it's not what I wanted: Convert string to variable name or variable type
I have code that reads an ini file, stores data in a QHash table, and checks the values of the hash key, (see below) if a value is "1" it's added to World.
Code Examples:
World theWorld;
AgentMove AgentMovement(&theWorld);
if(rules.value("AgentMovement") == "1")
theWorld.addRule(&AgentMovement);
INI file:
AgentMovement=1
What I want to do is, dynamically read from the INI file and set a reference to a hard coded variable.
for(int j = 0; j < ck.size(); j++)
if(rules.value(ck[j]) == "1")
theWorld.addRule("&" + ck[j]);
^
= &AgentMovement
How would you make a string into a reference as noted above?
This is a common theme in programming: A value which can only be one of a set (could be an enum, one of a finite set of ints, or a set of possible string values, or even a number of buttons in a GUI) is used as a criteria to perform some kind of action. The simplistic approach is to use a switch (for atomic types) or an if/else chain for complex types. That is what you are currently doing, and there is nothing wrong with it as such:
if(rules.value(ck[j]) == "1") theWorld.addRule(&AgentMovement);
else if(rules.value(ck[j]) == "2") theWorld.addRule(&AgentEat);
else if(rules.value(ck[j]) == "3") theWorld.addRule(&AgentSleep);
// etc.
else error("internal error: weird rules value %s\n", rules.value(ck[j]));
The main advantages of this pattern are in my experience that it is crystal clear: anybody, including you in a year, understands immediately what's going on and can see immediately which criteria leads to which action. It is also trivial to debug which can be a surprising advantage: You can break at a specific action, and only at that action.
The main disadvantage is maintainability. If the same criteria (enum or whatever) is used to switch between different things in various places, all these places have to be maintained, for example when a new enum value is added. An action may come with a sound, an icon, a state change, a log message, and so on. If these do not happen at the same time (in the same switch), you'll end up switching multiple times over the action enum (or if/then/else over the string values). In that case it's better to bundle all information connected to an action in a data structure and put the structures in a map/hash table with the actions as keys. All the switches collapse to single calls. The compile-time initialization of such a map could look like this:
struct ActionDataT { Rule rule; Icon icon; Sound sound; };
map<string, AcionDataT> actionMap
= {
{"1", {AgentMovement, moveIcon, moveSound} }
{"2", {AgentEat, eatIcon, eatSound } } ,
//
};
The usage would be like
for(int j = 0; j < ck.size(); j++)
theWorld.addRule(actionMap[rules.value(ck[j])].rule);
And elsewhere, for example:
if(actionFinished(action)) removeIcon(actionMap[action].icon);
This is fairly elegant. It demonstrates two principles of software design: 1. "All problems in computer science can be solved by another level of indirection" (David Wheeler), and 2. There is often a choice between more data or more code. The simplistic approach is code-oriented, the map approach is data oriented.
The data-centrist approach is indispensable if switches occur in more than one situation, because coding them out each time would be a maintenance nightmare.
Note that with the data-centrist approach none of the places where an action is used has to be touched when a new action is added. This is essential. The mechanism resembles (in principle and implementation, actually) the call of a virtual member function. The calling code doesn't know and isn't really interested in what is actually done. Responsibility is transferred to the object. The calling code may perform actions later in the life cycle of a program which didn't exist when it was written. By contrast, compare it to a program with many explicit switches where every single use must be examined when an action is added.
The indirection involved in the data-centrist approach is its disadvantage though, and the only problem which cannot be solved by another level of indirection, as Wheeler remarked. The code becomes more abstract and hence less obvious and harder to debug.
You have to provide the mapping from the names to the object by yourself. I would wrap it into a class, something like this:
template <typename T>
struct ObjectMap {
void addObject(std::string name,T* obj){
m[name] = obj;
}
T& getRef(std::string name) const {
auto x = m.find(name);
if (x != m.end() ) { return *(x->second);}
else { return dummy; }
}
private:
std::map<std::string,T*> m;
T dummy;
}
The problem with this approach is that you have to decide what to do if an object is requested that is actually not in the map. A reference always has to reference something (in contrast to a pointer that can be 0). I decided to return the reference to a dummy object. However, you might want to consider to use pointers instead of references. Another option might be to throw an error in case the object is not in the map.

C++ - Continuing a while loop upon exception

When an exception is encountered in C++, does the program automatically terminate upon catching it. Is there a way that ,if the exception was caught within a loop, I could just skip the rest of the loop and go straight to the next iteration?
There are a number of different ways to solve this problem.
Create a member function that checks whether a move is valid before making it. The calling code will need to call this function before calling advance, and only call advance if the move is valid.
Make the advance member function return a value indicating whether the player's position was advanced. The calling code will need to test the return value to decide whether to print the board or print a "try again" type of message.
Make the advance member function throw an exception if the move is invalid. The calling code will need to catch the exception.
There are lots of other ways to solve this problems.
Well first of all, if that snipped of code is EXACTLY how you copy-pasted it, it has some syntax errors. This is how it should be written:
int main() {
...
Person *p = new Person("Neo");
...
string in;
while(cin >> in) {
if (in == "q") {
break;
}
else if (in == /*One of the eight directions North ... Northwest*/) {
p->advance(in);
} //this bracket here ends the if. after the parentheses, nothing else will execute
else {
cerr << "Input one of the eight directions" < endl;
}
}
}
So yeah, if I understood correctly your problem, adding that closing bracket there should solve it. I hope this is what you needed and that it was helpful

How to use a variable in the same struct it's defined in?

I am making a rogue-like ASCII game and made a struct called "Armor" and I want to use the name variable in the struct to have the path to whatever the name is.
struct Armor {
bool equipped;
std::string name;
int getBuff(int buff) {
std::fstream item;
std::string line;
std::string response;
std::string value;
item.open("../Data/Items/" + name + ".item", std::fstream::in);
if (item.fail())
errorQuit("ERROR: There was a problem loading armor type .ITEM file."); // Error and quit function
while (!item.eof()) {
getline(item, line);
response = split(line, '=', 0); // Splits string
if (response == "buff" + std::to_string(buff)) {
value = split(line, '=', 1);
break;
}
}
item.close();
return std::stoi(value);
}
};
Then I called it like this:
Armor sword;
sword.name = "Wooden Sword";
int buff = sword.getBuff(1);
But this throws an Unhandled exception error.
I changed it so that getBuff takes 2 parameters, int buff and std::string itemName. and replaced name in the path with itemName;
Then I tried calling it like this:
Armor sword;
sword.name = "Wooden Sword";
int buff = sword.getBuff(1, sword.name);
But this throws the same error.
I'm confused as to why I can't use the name variable as it has already be defined. Is there any other way I can use the name variable like that?
I see you've just edited your comment to say you've figured your problem out, but I just want to add something else that may be helpful:
Without seeing how errorQuit() is defined, there's a potential problem in your getBuff() function. If the expression if (item.fail()) evaluates to true, the function may continue on trying to process the data (unless errorQuit() somehow breaks out of the program or something, which probably isn't the best approach).
Basically, testing for fail() may or may not provide the behavior you require in all scenarios, depending on what bits are set in the stream state. Implementations vary, but... if the file fails to open, failbit and/or badbit will be set, but not eofbit. getline() will see the error state and so it will not try to read from the stream when you call it. But that also means the eofbit will never be set!
There's lots of different "techniques" to file reading. Some people prefer an RAII approach. Others like looping on getline(). Or you could even just use good() to check the error state if you don't care what happened and simply want to know if everything is fine or not.
In any case, you might be interested in the info on this page: std::ios_base::iostate.
Thanks for all your help but I figured it out on my own.
I just made a stupid error that I overlooked like an idiot.
It is searching for buff + int (e.x. buff1) in the file but there are multiple lines that contain that word so I guessed that messed it up. I just made an adjustment to the if statement and it is working as expected.
Sorry to bother you!
your getBuf() function fails on some io-operation and throws an exception.You dont handle exceptions and thus the application quits with the appropriate message. Try surrounding the call to getBuf with try/catch (add the includes to iostream and stdexcept)
try {
int buff = sword.getBuff(1);
}
catch (const std::exception &e) {
std::cout << e.what() << std::endl;
}

C++ How to differentiate std::cin to std::ifstream?

I am trying to make a simple comparison to find if istream is a std::cin or std::ifstream.
My pseudocode is something like that:
class myclass
{
public:
void write(istream& is)
{
if(is == cin) // this does not work
{
//do something
}
else
{
//do something else
}
}
};
How can I proceed?
Thank you!
Since std::cin is an instance of std::istream, you could compare the addresses of the two objects to see if they are equal:
if (&is == &std::cin)
(Demo)
However I would consider investigating if you can achieve your goal without doing this; switching logic based on the identity of the stream argument is not very clean and may inhibit future development or maintenance of this project.
I'm not sure why you need to check if you have cin or not, but I had the same problem and my reason was: if I have cin, it means I'm in interactive mode, so I should give some useful information to cout. While checking the address of cin with is will probably hopefully always work, I wouldn't really trust it...
Anyways, my solution was to slightly generalize and add an extra parameter with a reasonable default
void f(istream &i, ostream *o = nullptr) {
if (o) {
*o << "useful info...";
}
i >> important_variable;
}
This gives a slightly more general function, using the "pointer to parameter means optional parameter" idiom. If you need cin for some other reason, then you may also look into specifically which properties of cin you need, and how to determine if your input stream possesses them.

Extract JSON data from file in C++

Here there, sorry if this question is not well-suited for this forum. I'm pretty new to programming and thought I'd get a better command of strings and files by creating this little project. What I'm trying to do is extract data from a JSON document. Eventually I'd store the data in an array I suppose and work with it later.
Basically, I'm wondering if there is a better way of going about this. The code seems kind of wordy and definitely not elegant. Again, sorry if this question is not a good one, but I figured there'd be no better way to learn than through a community like this.
#include <iostream>
#include <fstream>
#include <cstring>
#include <string> //probably including more than necessary
using namespace std; //should be specifying items using scope resolution operator instead
int main(int argc, const char * argv[])
{
ifstream sfile("JSONdatatest.txt");
string line,temp;
while(!sfile.eof()){
getline(sfile, line);
temp.append(line); //creates string from file text, use of temp seems extraneous
}
sfile.close();
cout << "Reading from the file.\n";
size_t counter=0;
size_t found=0;
size_t datasize=0;
while(found!=string::npos && found<1000*70){ //problem here, program was creating infinite loop
//initial 'solution' was to constrain found var
//but fixed with if statement
found = temp.find("name: ",counter);
if(found!=string::npos){
found=found+7; //length of find variable "name: ", puts us to the point where data begins
size_t ended=temp.find_first_of( "\"", found);
size_t len=ended-found; //length of datum to extract
string temp2(temp, found, len); //odd use of a second temp function,
cout << temp2 << endl;
counter=ended+1;
datasize++; //also problem with data size and counter, so many counters, can they
//coordinate to have fewer?
}
}
cout << datasize;
return 0}
Where I indicate an infinite loop is made, I fixed by adding the if statement in the while loop. My guess is because I add 7 to 'found' there is a chance it skips over npos and the loop continues. Adding the if statement fixed it, but made the code look clunky. There has to be a more elegant solution.
Thanks in advance!
I would recommend that you use a third-party to do all this stuff, which is pretty tough with raw tools. I actually did this kind of stuff recently so I can give you some help.
I would recommend you take a look at boost::property_tree .
Here is the theory: A Json file is like a tree, you have a root, and many branches.
The idea is to transform this JSON file into a boost::property_tree::ptree, so then you use easily the object ptree and not the file.
First, let's say we have this JSON file:
{
"document": {
"person": {
"name": "JOHN",
"age": 21
},
"code": "AX-GFD123"
}
"body" : "none"
}
Then in your code, be sure to include:
#include "boost/property_tree/ptree.hpp"
#include "boost/property_tree/json_parser.hpp"
Then here is the most interesting part:
boost::property_tree::ptree root;
You create the ptree object named root.
boost::property_tree::read_json("/path_to_my_file/doc.json", root);
Then you tell what file to read, and where to store it (here in root). Be careful, you should use try / catch on this in case the file doesn't exist.
Then you will only use the root tree which is really easy to do. You have many functions (I invite you to see the boost documentation page).
You want to access the namefield. Right then do this:
std::string myname = root.get<std::string> ("document.person.name", "NOT FOUND");
The get function has the first parameter the path to get the attribute you want, the second is for default return if the path is incorrect or doesn't exist. the <std::string> is to show what type it must return.
Let's finish with another example. Let's say you want to check all your root nodes, that means every node which are on the top level.
BOOST_FOREACH(const boost::property_tree::ptree::value_type& child, root.get_child(""))
{ cout << child.first << endl; }
This is a bit more complicated. I explain. You tell boost to look every child of the root with root.get_child("") , "" is used for root. Then, for every child found, (like a basic iterator), you will use const boost::property_tree::ptree::value_type& child.
So inside the foreach, you will use the child to access whatever you want. child.firstwill give you the name of the child node currently in use. In my example it will print first document, and then body.
I invite you to have a look at Boost documentation. It looks maybe hard at first, but it is really easy to use after that.
http://www.boost.org/doc/libs/1_41_0/doc/html/property_tree.html