i'm learning how to program in c++ and i'm facing into a problem:
I have a struct called Professeur, where Cours and Etudiant are other structs (not the problem here) :
struct Professeur {
std::string Nom;
int Ancien;
Cours* ListeDeCours;
Etudiant* ListeDEtudiant;
Professeur* Suivant;
};
In my program i read a file and then store the data in these structure. However when i want to display the info stored in the "Suivant" Professeur i have a problem, see :
The data file :
Prof1
1
Cours11
Cours12
Cours13
&
Etudiant11
Etudiant12
Etudiant13
$
Prof2
2
Cours21
Cours22
Cours23
&
Etudiant21
Etudiant22
Etudiant23
$
And the output :
2
1
1
6304032
As you can see, newprof->Ancien don't give me the same value and i don't know why as i don' modify it (i suppose). So i did a test program, where i create my struct by myself and it work perfectly:
I searched everything but i don't know why it's not working.. Could someone take a look ? Thanks a lot
Here is code where the problem should be located :
test.cpp
ifstream fichier;
vector<DossierProfesseur::Professeur> ContainerProf;
vector<DossierProfesseur::Cours> ContainerCours;
vector<DossierProfesseur::Etudiant> ContainerEtudiant;
DossierProfesseur::DossierProfesseur(string FP){
fichier.open(FP);
if (fichier.is_open() ){
Professeur premier = DossierProfesseur::CreationListeProfesseur();
tete = &premier;
Professeur *newprof = DossierProfesseur::getNextProf(tete);
cout<< newprof->Ancien<<"\n";
cout<< tete->Ancien<<"\n";
cout<< tete->Ancien<<"\n";
cout<< newprof->Ancien<<"\n";
}
else{
printf("Error while openning file");
}
}
DossierProfesseur::Professeur* DossierProfesseur::getNextProf(DossierProfesseur::Professeur* prof){
return prof->Suivant;
}
DossierProfesseur::Professeur DossierProfesseur::CreationListeProfesseur(){
Professeur prof;
Cours cours;
Etudiant etudiant;
if(!fichier.eof()){ //Fin du fichier
getline(fichier,prof.Nom);
string ancien;
getline(fichier,ancien);
prof.Ancien = stoi(ancien);
Professeur nextProf = DossierProfesseur::CreationListeProfesseur();
prof.Suivant = &nextProf;
}
else{
prof.Nom = string();
prof.Ancien = 0;
prof.ListeDeCours = NULL;
prof.ListeDEtudiant = NULL;
prof.Suivant = NULL;
}
ContainerProf.push_back(prof);
return ContainerProf.back();
}
int main()
{
string dest = "FP.txt";
DossierProfesseur dos (dest);
return 0;
}
test.h :
#ifndef DossierProfesseur_h
#define DossierProfesseur_h
#include <iostream>
#include <fstream>
#include <cstring>
#include <stdlib.h>
class DossierProfesseur
{
public:
DossierProfesseur(std::string FP);
struct Cours{
std::string Sigle;
Cours* Suivant;
};
struct Etudiant{
std::string Sigle;
Etudiant* suivant;
};
struct Professeur {
std::string Nom;
int Ancien;
Cours* ListeDeCours;
Etudiant* ListeDEtudiant;
Professeur* Suivant;
};
Professeur CreationListeProfesseur();
Professeur *getNextProf(Professeur *prof);
Professeur* tete;
private:
};
#endif
Edit :
Using vectors, i have the same output as previously:
2 - 0x7ffe26c10520
1
1
6320480 - 0x7ffe26c10520
They point to the same adress, but have different values
To use vectors i used this :
vector ContainerProf; as a global variable
And then in CreationListeEtudiant :
Insted of returning prof, i return this :
ContainerProf.push_back(prof);
return ContainerProf.back();
Did i do something wrong?
DossierProfesseur::Professeur DossierProfesseur::CreationListeProfesseur(){
Professeur prof;
Cours cours;
...
cours = DossierProfesseur::CreationListeCours();
prof.ListeDeCours = &cours;
etudiant = DossierProfesseur:
...
return prof;
}
You create cours as a local object inside this function, so cours will cease to exist when this function returns. Yet you stash the address of cours inside the prof object you return by value. So you are returning an object to the caller that contains a pointer to an object that no longer exists. Attempting to dereference that pointer is disastrous.
Please don't use pointers this way. It makes managing the lifetimes of objects extremely difficult.
Related
Hey ! i am trying to create a program of hospital management system using doubly linked list in c++.
in this i am using whole class for patient data.
i created a nodes for linked list .
i am using one node to represent one bed in hospital.
but after that when i am trying to print some data manually , nothing is printing in console and program is ending without showing any output
this is my code :
#define max_limit 25;// maximum 50 beds can be there in hospital
using namespace std;
class patient //creating class to store the data of patient
{
public:
int pt_id;
string pt_name; //patient name
string diagnosis; //diagnosis patient have
};
struct bed //each bed in hospital
{
class patient p;
struct bed *prev;
struct bed *next;
};
int main()
{
//creating 3 beds in starting only and giving values.
struct bed *head=(struct bed *)malloc(sizeof(patient));
struct bed *second=(struct bed *)malloc(sizeof(patient));
struct bed *tail=(struct bed *)malloc(sizeof(patient));
head->prev=NULL;
head->p.pt_id=6478;
head->p.pt_name="Jayraj";
head->p.diagnosis="Headaches";
head->next=second;
second->prev=head;
second->p.pt_id=8933;
second->p.pt_name="Mayank";
second->p.diagnosis="Highfever";
second->next=tail;
tail->prev=second;
tail->p.pt_id=1788;
tail->p.pt_name="Jay";
tail->p.diagnosis="Stomacheache";
tail->next=NULL;
cout<<"Size:"<<sizeof(patient);
return 0;
}```
You should check the errors - make sure your environment displays them. There are at least these issues:
When allocating a bed you shouldn't use sizeof(patient), but sizeof(bed).
define should not end with a semi-colon.
As a bed could be empty, you'd better define the p member as a pointer to a patient instance
You're not using C++ syntax:
Use new instead of malloc.
Define constructors and methods
Use nullptr instead of NULL
Use PascalCase for class names
Here is some code for inspiration, but you'll need to add more logic to it for your assignment (e.g. you'll have to verify the limit of beds):
#define max_limit 25 // maximum 25 beds allowed in hospital
using namespace std;
class Patient
{
public:
int pt_id;
string pt_name; //patient name
string diagnosis; //diagnosis patient have
// Constructor:
Patient(int id, string name, string diag) :
pt_id(id), pt_name(name), diagnosis(diag) {}
};
class Bed
{
public:
Patient* p = nullptr;
Bed* prev = nullptr;
Bed* next = nullptr;
// Constructors:
Bed() {};
Bed(Patient* p) : p(p) {};
// Method to ease linking beds
Bed* prepend(Bed* other) {
other->next = this;
this->prev = other;
return other;
};
};
int main()
{
// Use constructor to create patients
Patient *jaray = new Patient(6478, "Jayraj", "Headaches");
Patient *mayank = new Patient(8933, "Mayank", "Highfever");
Patient *jay = new Patient(1788, "Jay", "Stomacheache");
// Use constructor and method to create linked list
Bed *beds = (new Bed(jay))
->prepend(new Bed(mayank))
->prepend(new Bed(jaray));
// Let's output something: the beds with patient names
Bed *bed = beds;
while (bed != nullptr) {
if (bed->p == nullptr) {
cout << "bed without patient\n";
} else {
cout << "bed occupied by " << bed->p->pt_name << "\n";
}
bed = bed->next;
}
return 0;
}
I am trying to pass 5th element of an array(Products[]) of class product to another function. The goal is to update the information of the element Product[5]. Everything seems to work fine except information of Product[5] variable is not updating.
Update: Problem solved by removing while(!EOF), thanks to Remy Lebeau.
The relevant part of Class:
class product
{
private:
float Wholesale_Price = 0;
float Retail_Price = 0;
string Supplier = "N/A";
string Note = "N/A";
int Stock_Amount = 0;
public:
string Name="N/A";
void UpdateRetailPrice(float New_Retail_Price)
{
Retail_Price = New_Retail_Price;
}
void UpdateProductAmount(int New_Stock_Amount)
{
Stock_Amount = New_Stock_Amount;
}
void UpdateWholesale_price(float New_Wholesale_Price)
{
Wholesale_Price = New_Wholesale_Price;
}
};
The relevant part of function:
void ReadProductFromFile(product* Products)
{
string Name, Supplier, Note, Wholesale_Price, Retail_Price, Stock_Amount;//wholesale price, stock amount,price are in string so that
//it becomes easy to use getline(). Use stoi() later for turning string to int.
ifstream ReadProductFromFile;
ReadProductFromFile.open("product.txt");
if (!ReadProductFromFile)
{
perror("Product File failed to open");
return;
}
while(!EOF)
{
/*read product info txt file------>*/
getline(ReadProductFromFile, Name);
getline(ReadProductFromFile, Wholesale_Price);
getline(ReadProductFromFile, Retail_Price);
getline(ReadProductFromFile, Stock_Amount);
/*update product info---------->*/
Products->Name = Name;
Products->UpdateWholesale_price(stoi(Wholesale_Price));
Products->UpdateProductAmount(stoi(Stock_Amount));
Products->UpdateRetailPrice(stoi(Retail_Price));
}
}
Relevant part of Main function:
int main(int argc, char const *argv[])
{
product Products[10];
ReadProductFromFile(Products+5);//is this the right way to send Products[5]? tried &(product[5]) but error
return 0;
}
Input:
Bananas
210
270
310
So the question explains the problem...
Background:
I'm trying to solve this problem from HackerRank.
It's basically an html tag parser. Valid input guaranteed, attributes are strings only.
My Approach
I created a custom Tag class that can store a map<string,Tag> of other Tag's, as well as a map<string,string> of attributes. The parsing seems to be working correctly.
The Problem
During the querying part, I get a BAD_ACCESS error on the following query/html combo:
4 1
<a value = "GoodVal">
<b value = "BadVal" size = "10">
</b>
</a>
a.b~size
The error occurs when I try to access the b Tag from a. Specifically, it's in the t=t.tags[tag_name], Line 118 below.
Code
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <map>
#include <stack>
using namespace std;
class Tag {
public:
Tag(){};
Tag(string name):name(name){};
string name;
map<string,Tag> tags = map<string, Tag>();
map<string,string> attribs=map<string,string>();
};
int main() {
int lines, queries;
std::cin>>lines>>queries;
std:string str;
getline(cin, str);
stack<string> open;
auto tags = map<string, Tag>();
for (int i = 0; i < lines; i++) {
getline(cin, str);
if (str.length()>1){
// If it's not </tag>, then it's an opening tag
if (str[1] != '/') {
// Parse tag name
auto wordidx = str.find(" ");
if (wordidx == -1) {
wordidx = str.length()-1.f;
}
string name = str.substr(1,wordidx-1);
auto t = Tag(name);
string sub = str.substr(wordidx);
auto equalidx=sub.find("=");
// Parse Attributes
while (equalidx != std::string::npos) {
string key = sub.substr(1,equalidx-2);
sub = sub.substr(equalidx);
auto attrib_start = sub.find("\"");
sub = sub.substr(attrib_start+1);
auto attrib_end = sub.find("\"");
string val = sub.substr(0, attrib_end);
sub = sub.substr(attrib_end+1);
t.attribs[key] = val;
equalidx=sub.find("=");
}
// If we're in a tag, push to that, else push to the base tags
if (open.size() == 0) {
tags[name] = t;
} else {
tags[open.top()].tags[name]=t;
}
open.push(name);
} else {
// Pop the stack if we reached a closing tag
auto wordidx = str.find(">");
string name = str.substr(2,wordidx-2);
// Sanity check, but we're assuming valid input
if (name.compare(open.top())) {
cout<<"FUCK"<<name<<open.top()<<endl;
return 9;
}
open.pop();
}
} else {
std::cout<<"FUCK\n";
}
}
//
// Parse in queries
//
for (int i = 0; i < queries; i++) {
getline(cin, str);
Tag t = Tag();
bool defined = false;
auto next_dot = str.find(".");
while (next_dot!=string::npos) {
string name = str.substr(0,next_dot);
if (defined && t.tags.find(name) == t.tags.end()) {
//TAG NOT IN T
cout<<"Not Found!"<<endl;
continue;
}
t = !defined ? tags[name] : t.tags[name];
defined = true;
str = str.substr(next_dot+1);
next_dot = str.find(".");
}
auto splitter = str.find("~");
string tag_name = str.substr(0,splitter);
string attrib_name = str.substr(splitter+1);
if (!defined) {
t = tags[tag_name];
} else if (t.tags.find(tag_name) == t.tags.end()) {
//TAG NOT IN T
cout<<"Not Found!"<<endl;
continue;
} else {
t = t.tags[tag_name];
}
// T is now set, check the attribute
if (t.attribs.find(attrib_name) == t.attribs.end()) {
cout<<"Not Found!"<<endl;
} else {
cout<<t.attribs[attrib_name]<<endl;
}
}
return 0;
}
What I've tried
This is fixed by just defining Tag x = t.tags[tag_name]; in the line above as a new variable, and then doing t = x; but why is this even happening?
Also, the following query also then fails: a.b.c~height, but it fails on Line 99 when it tried to get a.tags["b"]. No idea why. I was gonna just go with the hacky fix above, but this seems like a big core issue that i'm doing wrong.
I would suggest running this on an IDE and verifying that the parsing is indeed correct.
t=t.tags[tag_name]
This expression is unsafe because you are copy-assigning an object that is owned by that object over the owning object.
Consider what happens on this line:
The map lookup is performed and returns a Tag&.
You try to copy-assign this to t, invoking the implicit copy-assigment operator.
This operator copy-assigns t.tags from the tags attribute of the copy source -- which lives in t.tags.
The result is that the object you're copying into t is destroyed in the middle of that copy. This causes undefined behavior, and an immediate crash is honestly the best possible outcome as it told you exactly where the problem was. (This kind of problem frequently manifests at some point later in the program, at which point you've lost the state necessary to figure out what caused the UB.)
One workaround would be to move the source object into a temporary and then move-assign that temporary over t:
t = Tag{std::move(t.tags[tag_name])};
This lifts the data we want to assign to t out of t before we try to put it in t. Then, when t's assignment operator goes to replace t.tags, the data you're trying to assign to t doesn't live there anymore.
However, this overall approach involves a lot of unnecessary copying. It would be better to declare t as Tag const *t; instead -- have it be a pointer to a tag. Then you can just move that pointer around to point at other tags in your data structure without making copies.
Side note: I just did this problem the other day! Here's a hint that might help you simplify things: do you actually need a structure of tags? Is there a simpler type of lookup structure that would work instead of nested tags?
I'm working on a tourist guide using c++, and I keep getting this thread when I run the code, in the Attraction class, setName function, and in the main function, and I dont understand what's the issue. Here's the .cpp and main files.
//.cpp file
#include <string>
#include "Attraction.h"
string Attraction::getName(){
return name;
}
int Attraction::getIDType(){
return id;
}
void Attraction::setName(string name){
this -> name = name;//In this line I receive the thread
}
void Attraction::setIDType(int typeID){
this -> typeID = typeID;
}
//main.cpp
int main() {
int x;
City Rome(111,"Rome");
City Dubai(222,"Dubai");
City Paris(333, "Paris");
menu(Rome,Dubai,Paris);
Sport* Ds = new Sport[x];
Culture* Dc = new Culture[x];
Shopping* Dh = new Shopping[x];
//{new Sport,new Sport,new Sport,new Culture,new Culture,new Culture,new Shopping,new Shopping,new Shopping};
Ds[0].setName("Camel and Horse Racing");
Ds[1].setName("Marine Sports");
Ds[2].setName("Football");
Dc[0].setName("Dubai Museum");
Dc[1].setName("Falconry");
Dc[2].setName("Sheikh Saeed Al-Maktoum's House");
Dh[0].setName("Dubai Mall");//And here
Dh[1].setName("Mall of Emirates");
Dh[2].setName("Deira City Centre");
Ds[0].setIDType(1);
Ds[1].setIDType(1);
Ds[2].setIDType(1);
Ds[3].setIDType(2);
Ds[4].setIDType(2);
Ds[5].setIDType(2);
Ds[6].setIDType(3);
Ds[7].setIDType(3);
Ds[8].setIDType(3);
Dubai.setAttraction(Ds, x);
return 0;
}
In your C++ code, you're creating a dynamic array of size x but you never assign a value to x, which means it has a default value of 0.
That means that the following lines create empty arrays:
Sport* Ds = new Sport[x];
Culture* Dc = new Culture[x];
Shopping* Dh = new Shopping[x];
So when you call Ds[0].setName(),you get a Segmentation Fault because you're calling a method on a bad address.
In order to fix this issue, Make sure you give a valid size for each array. Here is an example:
int main()
{
Sport* Ds = new Sport[9];
Ds[0].setIDType(1);
Ds[0].setName("Camel and Horse Racing");
Ds[1].setName("Marine Sports");
Ds[2].setIDType(1);
Ds[2].setName("Football");
Ds[3].setIDType(2);
Ds[4].setIDType(2);
Ds[5].setIDType(2);
Ds[6].setIDType(3);
Ds[7].setIDType(3);
Ds[8].setIDType(3);
Culture* Dc = new Culture[3];
Dc[0].setName("Dubai Museum");
Dc[1].setName("Falconry");
Dc[2].setName("Sheikh Saeed Al-Maktoum's House");
Shopping* Dh = new Shopping[3];
Dh[0].setName("Dubai Mall");//And here
Dh[1].setName("Mall of Emirates");
Dh[2].setName("Deira City Centre");
delete[] Ds;
delete[] Dc
delete[] Dh;
return 0;
}
I'm having a pretty confusing problem in building a binary tree. Apparently this should be an easy task but somehow I may mess up with the pointers in it.
Here's the simplified code (of course it's not the real code) :
#include <string.h>
#include <iostream>
using namespace std;
#define DIM1 2
typedef enum {LEFT,RIGHT} direction;
typedef char tName[MAX_NAME_LEN + 1];
struct Rectangle {
tName _name;
struct Rectangle *_binSon[DIM1];
};
struct Rectangle *recTree;
void insertRectToTree(char str[]){
struct Rectangle rect;
struct Rectangle *point;
struct Rectangle *parent;
strcpy(rect._name,str);
rect._binSon[RIGHT] = NULL;
rect._binSon[LEFT] = NULL;
point = ▭
if (recTree == NULL){
recTree = point;
} else {
struct Rectangle *current;
current = recTree;
while (current){
parent = current;
if (strcmp(point -> _name, current -> _name) > 0){
current = current -> _binSon[RIGHT];
} else {
current = current -> _binSon[LEFT];
}
}
if (strcmp(point -> _name, parent -> _name) < 0){
parent -> _binSon[LEFT] = point;
} else {
parent -> _binSon[RIGHT] = point;
}
}
}
int main(){
recTree = NULL;
char str[] = "LIKE";
insertRectToTree(str);
char str2[] = "GUIDE";
insertRectToTree(str2);
printf(recTree -> _name);
return 0;
}
As you can see, this binary tree tries to organize a record based on its name, so the smallest alphabetical order will go to the left side and so on.
The problem is, after the first insertion "LIKE", I want "GUIDE" inserted to the tree as well, with "LIKE" still as the root. However, the printf() shows that "GUIDE" takes over as its root. (In other word, "GUIDE" is the output). Any good explanation for this? Ask me if I need to add some more thing to this question. Thanks for all of your help.
Within the following lines
struct Rectangle rect;
...
point = ▭
...
recTree = point;
you assign a reference to a local variable to a global pointer. After leaving the function it may no longer contain valid data.
Howard is correct. But to correct the problem use new.
i.e. instead of
point = ▭
Put
point = new struct Rectangle;