strongly connected components with stl c++ bug? - c++

I have a file that contains a directed graph. Graph vertices are labeled from 1 to N with N close to 800.000 (thousands). My cointainers are:
vector<long> isExplored;
vector<long> f;
vector<vector<long>> matrix;
vector<vector<long>> matrixInverse;
My file function to read the file and set the vectors is(vector[0] is always zero, that is the containers have size n+1):
void InputClass::readFile() {
ifstream inputFile;
inputFile.open(fileName);
string line;
string word;
int vertexNumber = 0;
while(getline(inputFile, line)) {
istringstream inputStream(line);
inputStream >> word;
if(vertexNumber != stoi(word)) {
vertexNumber = stoi(word);
matrix.resize(vertexNumber + 1);
}
while(inputStream >> word) {
if(matrix[vertexNumber].size() == 0) {
matrix[vertexNumber].push_back(0);
}
matrix[vertexNumber].push_back(stoi(word));
}
}
long size = matrix.size();
isExplored.resize(size);
f.resize(size);
for(unsigned long i = 0; i < matrix.size(); i++) {
isExplored.push_back(false);
f.push_back(0);
}
cout << "done";
}
My dfs algorithm is:
void dfs(long vertex, InputClass kostas) {
isExplored[vertex] = true;
cout << "vertex: " << vertex; //1
for(unsigned long i = 1; i < kostas.matrix[vertex].size(); i++) {
cout << " i: " << i << endl;
if(!isExplored[kostas.matrix[vertex].at(i)]) {
cout << "done1" << endl;
dfs(kostas.matrix[vertex].at(i), kostas);
cout << "done2" << endl;
}
}
t++;
f[vertex] = t;
}
And finally the dfs loop:
void dfsLoop(InputClass kostas) {
t = 0;
for(unsigned long i = kostas.matrix.size() - 1; i >= 1; i--) {
if(!isExplored[i]) {
dfs(i, kostas);
cout << "done" << " t " << endl;
}
//more code here
}
My program crashes at i = kostas.matrix.size() - 1 after some(i think 5) dfs recursive calls. The crash happens on the dfs call and //1 is never printed. I have checked the vector but they are intialized fine. Since //1 is never printed my guess is that the crash happens on function's variables long vertex or InputClass kostas. Kostas should be fine and my guess is that long vertex causes the error. Any suggestions? I must also mention that the algorithm works wihout a problem on small/medium inputs.

It appears to me that you are copying the InputClass every time you make a call to dfs. Try passing it by reference by changing the method to void dfs(long vertex, InputClass &kostas) and the method call to dfs(i, kostas);

Related

Why String is returning Junk values

Here I am using Data Structure Queues to change cards places using strings. User picks the top card than put it at last of the deck. The problem is that I need to return updated string to main. What it is returning is junk Values. I also tried to copy the string array and than returning that arraybut didn't work. Can anyone help?
#include<iostream>
#include<string>
using namespace std;
string CommunityChest(string Cards[]){
struct Que{
string cards[6];
int front =0;
int back=-1;
}ComQ;
string temp;
for(int i=0; i<5;i++)
{//Enqueue(Cards)
ComQ.back++;
if(ComQ.back<=5)
{
ComQ.cards[ComQ.back]=Cards[i];
}
else{
cout<<"Overflow";
}
}
//Display
for(int i=ComQ.front; i<=ComQ.back; i++)
{
cout<<ComQ.cards[i]<<endl;
}
//Del()
if(ComQ.front>=0)
{
temp=ComQ.cards[ComQ.front];
ComQ.front++;
}
cout<<endl<<"Pick the top Card"<<endl;
cout<<temp<<endl;
//EnQ the picked card
ComQ.back++;
if(ComQ.back<=5)
{
ComQ.cards[ComQ.back]=temp;
}
else{
cout<<"Overflow";
}
cout<<endl<<"After Inserting top card:"<<endl;
//Display
string newQ1[5];
for (int i=ComQ.front; i<=ComQ.back; i++) //Making an alternate array to copy Comq.cards array data
{
newQ1[i]=ComQ.cards[i];
}
for(int i=0; i<5; i++)
{
return newQ1[i]; //trying to return string array
//cout<< newQ1<<endl;
}
}
int main(){
string cards[5]{ "1 Advance ........",
"2. It is your ...........",
"3. You have won .............",//Cards as strings
"4. From sale of..............",
"5. Pay Hospital............"};
string newQ1=CommunityChest(cards);
for(int i=0; i<5; i++)
cout << newQ1[i] << endl;
return 0;
}
There are some issues with this code as mentioned in the comments, you are trying to do a return in a loop, this may look okay but it's wrong since a return can get you out of the function. But it seems like you want to return an array of strings.
A fix for this function would be like this:
#include <iostream>
std::string* CommunityChest(std::string Cards[]) {
struct Que {
std::string cards[6];
int front = 0;
int back = -1;
} ComQ;
std::string temp;
for (int i = 0; i < 5; i++) { // Enqueue(Cards)
ComQ.back++;
if (ComQ.back <= 5) {
ComQ.cards[ComQ.back] = Cards[i];
}
else {
std::cout << "Overflow";
}
}
// Display
for (int i = ComQ.front; i <= ComQ.back; i++) {
std::cout << ComQ.cards[i] << std::endl;
}
// Del()
if (ComQ.front >= 0) {
temp = ComQ.cards[ComQ.front];
ComQ.front++;
}
std::cout << std::endl
<< "Pick the top Card" << std::endl;
std::cout << temp << std::endl;
// EnQ the picked card
ComQ.back++;
if (ComQ.back <= 5) {
ComQ.cards[ComQ.back] = temp;
}
else {
std::cout << "Overflow";
}
std::cout << std::endl
<< "After Inserting top card:" << std::endl;
// Display
// Creating a dynamic array to store the values
std::string* newQ1 = new std::string[5];
for (int i = ComQ.front, j = 0; i <= ComQ.back && j < 5; i++, j++) {// Making an alternate array to copy Comq.cards array data
newQ1[j] = ComQ.cards[i];
}
return newQ1; // Returning the dynamic array
}
int main()
{
std::string cards[5]{
"1 Advance ........",
"2. It is your ...........",
"3. You have won .............", // Cards as strings
"4. From sale of..............",
"5. Pay Hospital............"
};
std::string* newQ1 = CommunityChest(cards);
for(int i = 0; i < 5; i++) {
std::cout << newQ1[i] << std::endl;
}
delete[] newQ1; // Deleting the array
return 0;
}
The output will be:
1 Advance ........
2. It is your ...........
3. You have won .............
4. From sale of..............
5. Pay Hospital............
Pick the top Card
1 Advance ........
After Inserting top card:
2. It is your ...........
3. You have won .............
4. From sale of..............
5. Pay Hospital............
1 Advance ........
In this fix, I'm returning a dynamically allocated array of strings because a static array will be destroyed once the scope ends, it would be better sometimes to use other ways to allocate memory such as std::unique_ptr<> or std::shared_ptr<>, but I'd suggest you learn how to do it yourself first then use those when needed.
EDIT:
You can also return an std::array<>, I suggest you to read about it as C-Style arrays cannot be returned in you way that you tried and can't be returned without using dynamic allocation, so an std::array<> can be a good replacement over std::string* in this case

Reading into an Array Multiple Times

I'm having a little trouble with my code. It's pretty much supposed to open two files, and compare the first twenty line of the file "StudentAnswers.txt" [inputted as a char into a char array] against a char value in (each line of another file) "CorrectAnswers.txt" in another array at the same position (index). It's like a linear search, but the same position in the arrays. Then a report should be displayed, detailing which question the student missed, the given answer, the correct answer, and if the student passed (got >= 70%) or not, like the following:
Report for Student X:
2 (A/D), 3 (C/D), 5(D/A)
This student passed the exam!
Then it should clear the SAArray, and feed the next twenty lines from StudentAnswers.txt, and start the process all over again. I guess the program has to determine the number of students from (lines of 'StudentAnswers.txt' file / 20).
I'm having trouble displaying the report, and having the array clear itself after the program. I'm guessing this can be done with a while loop and an accumulator for the number of students (to be determined by above equation).
Also, Visual Studio seems to go to "Missed __ questions for a total of ___ %", and then keep looping -858993460.
Any help would be appreciated.
#include <iostream>
#include <fstream>
#include <string>
#include <array>
#include <algorithm>
using namespace std;
void GradeReturn(char[], char[], int, int, int);
string PassFail(float);
int main()
{
ifstream SA("StudentAnswers.txt");
ifstream CA("CorrectAnswers.txt");char CAArray[20];
char SAArray[20];
// char SA2Array[20];
bool isCorrect;
int correct;
int incorrect;
int counter;
correct = 0;incorrect = 0;
counter = 0;
cout << endl;
if (!SA.fail())
{
cout << "'StudentAnswers.txt' file opened successfully." << endl;
cout << "'CorrectAnswers.txt' file opened successfully." << endl << endl;
int a = 0;
int b = 0;
while (a < 20)
{
CA >> CAArray[a];
a++;
} // while loop to feed char into the array
while (b < 20)
{
SA >> SAArray[b];
b++;
}
} // while loop to feed char into array
CA.close(); // closing "CorrectAnswers.txt"
SA.close(); // closing "StudentAnswers.txt"
GradeReturn(&CAArray[counter], &SAArray[counter], correct, incorrect, counter);
return 0;
}
void GradeReturn(char CAArray[], char SAArray[], int correct, int incorrect, int counter)
{
float percent;
float hundred;
int student;
int catcher[20];
int writeCatcher; int starter;
int catcher_size;
student = 0;
writeCatcher = 0;
catcher_size = ((sizeof catcher) / 4);
while (counter < 20)
{
if ((CAArray[counter]) == (SAArray[counter]))
{
correct++;
cout << "Good job!" << endl;
} // correct handling
else
{
incorrect++;
cout << "You got question " << counter << " wrong." << endl;
counter >> catcher[writeCatcher];
writeCatcher++;
} // incorrect handling
counter++;
} // while loop to determine if a student got a question right or wrong
static_cast <float> (incorrect); // float conversion
cout << endl; // for cleanliness
percent = ((static_cast <float> (correct)) / 20); // percentage
hundred = percent * 100;
PassFail(percent);
if (PassFail(percent) == "pass")
{
student++;
cout << "Report for Student " << student << ":" << endl;
cout << "-----------------------------" << endl;
cout << "Missed " << incorrect << " questions out of 20 for ";
cout << hundred << " % correct." << endl << endl;
starter = 0;
while (starter < (sizeof catcher)
{
if(1=1)
{
catcher_size
}
else
{
cout << "";
starter++;
}
}
}
else if (PassFail(percent) == "fail")
{
student++;
cout << "Missed " << incorrect << " questions out of 20 for ";
cout << hundred << " % correct." << endl << endl;
while (starter < catcher_size)
{
if ((catcher[starter]) == -858993460)
{
starter++;
}
else
{
cout << "";
starter++;
}
}
}
return;
}
string PassFail(float percent)
{
if (percent >= 0.70) // if <pass>
{
return "pass";
}
else // if <fail>
{
return "fail";
}
cout << endl;
}
To get a loop you should keep streams open instead of closing them after reading 20 lines.
As pseudo code that would be:
a = 0;
while(streams_not_empty)
{
CA >> CAArray[a];
SA >> SAArray[a];
++a;
if (a == 20)
{
GradeReturn(&CAArray[counter], &SAArray[counter], correct, incorrect, counter);
a = 0; // Reset a
}
}
CA.close(); // closing "CorrectAnswers.txt"
SA.close(); // closing "StudentAnswers.txt"
You would also need to pass correct, incorrect, counter by reference so that the GradeReturn can change their value and their by do the accumulation.
Like:
void GradeReturn(char CAArray[], char SAArray[], int& correct, int& incorrect, int& counter)
Further you shouldn't rely on being able to read exactly Nx20 lines from the files every time. A file could have, e.g. 108 (5x20 + 8) lines, so you code should be able to handle the with only 8 lines. In other words, don't hard code 20 in your function like while (counter < 20). Instead pass the number of lines to be handled and do while (counter < number_to_handle).
Something like this as pseudo code:
a = 0;
while(streams_not_empty)
{
CA >> CAArray[a];
SA >> SAArray[a];
++a;
if (a == 20)
{
GradeReturn(&CAArray[counter], &SAArray[counter], correct, incorrect, counter, a);
// ^
a = 0; // Reset a
}
}
if (a != 0)
{
// Process the rest
GradeReturn(&CAArray[counter], &SAArray[counter], correct, incorrect, counter, a);
}
CA.close(); // closing "CorrectAnswers.txt"
SA.close(); // closing "StudentAnswers.txt"
One problem you have is you're trying to compare C-style strings with the == operator. This will compare them essentially as if they were pointers to char, i.e. compare whether they point at the same location in memory, not compare the contents of the string. I urge you to look up array-decay and c-string variables to understand more.
Specifically, if (PassFail(percent) == "pass") isn't going to do what you want it to. strcomp doc, strncmp doc using std::string variables instead of c-style strings would all work, but it would be better simply to compare percent to a value, i.e. if(percent >= 0.70 directly instead of calling PassFail and comparing a string.
There are many other issues here also, you at one point call PassFail but do nothing with the return value. The only side affect of PassFail is cout << endl, if that's what you intend, it's a poor decision and hard to read way to put a newline on the console.
Try asking your compiler for more warnings, that's often helpful in finding these types of issues. -Wall -Wextra work for gcc, you may have to read your compiler manual...

cout error while using functions

I've encountered a problem while trying to create a code which converts decimal numbers to binary, using functions. At first I created the code using only main function and it worked fine, but decided to modify it to use function. I believe code is written right, however when I try to cout my answer I get a big number like 115120160758866453687091316369641637416.
This is the code
#include <iostream>
#include <math.h>
using namespace std;
int* unsigned_dec(int dec_M) { //function for converting absolute part of numbers
int bin[8] = { 0,0,0,0,0,0,0,0 };
int ind = 7;
int arr_ind = 0;
for (int base = (int)abs(dec_M); base > 0; base = base / 2) {
if (base % 2 == 0) {
bin[arr_ind] = 0;
ind--;
}
else {
bin[arr_ind] = 1;
ind--;
}
arr_ind++;
}
return bin;
}
int main() {// main function
int dec_N;
cin >> dec_N;
int* bin_main = unsigned_dec(dec_N); //we are not sure if we are assigning the returned value of function to array in correct
for (int i = 0; i <= 7; i++) {
cout << bin_main[i];
}
cout << endl;
return 0;
}
then I tried to change the cout code to
cout << bin_main[0] << bin_main[1] << bin_main[2] << bin_main[3] << bin_main[4] << bin_main[5] << bin_main[6] << bin_main[7] << endl;
And this worked fine.
Then I wrote the same 2nd variant of cout in other way
cout << bin_main[0];
cout << bin_main[1];
cout << bin_main[2];
cout << bin_main[3];
cout << bin_main[4];
cout << bin_main[5];
cout << bin_main[6];
cout << bin_main[7];
cout << endl;
and my code started to cout the same strange number. I think that all 3 ways of couts are almost the same (especially 2 and 3), but don't understand what makes it not to work.
int bin[8] = { 0,0,0,0,0,0,0,0 };
is allocated on stack. You should either allocate bin on heap
auto bin = std::unique_ptr<int, std::default_deleter<int[]>>(new int[8]);
or even better, use std::vector
you are returning pointer to local array of intbin[] in unsigned_dec. This array on stack of function unsigned_dec will get invalidated once another function from main gets called i.e cout operator .
As others have already mentioned: A function should never return a pointer to a local variable. Local variable is not valid when the function returns.
A better way is to use a vector and just make the function return the vector.
Something like:
#include <iostream>
#include <math.h>
using namespace std;
//function for converting absolute part of numbers
vector<int> unsigned_dec(int dec_M) {
vector<int> bin; // Create a vector
bin.resize(8, 0); // Fill it with 8 elements initialized to zero
int arr_ind = 0;
// Note: added check for arr_ind being valid
for (int base = (int)abs(dec_M); base > 0 && arr_ind < 8; base = base / 2) {
if (base % 2 == 0) {
bin[arr_ind] = 0;
}
else {
bin[arr_ind] = 1;
}
arr_ind++;
}
return bin; // Return the vector
}
int main() {
int dec_N;
cin >> dec_N;
vector<int> bin_main = unsigned_dec(dec_N);
for (int i = 0; i < bin_main.size(); i++) {
cout << bin_main[i];
}
cout << endl;
return 0;
}

Core Segmentation Fault With Vector

The following pertains to homework. Restraunt pet project type thing, task is to update it to use vectors. The issue I'm having is this:
This winds up causing a core segmentation fault, yet is able to retrieve all the information appropriately when I use valgrind.
void Table::partyCheckout(void)
{
if(status == SERVED)
{
cout << " ---------------- " << endl;
cout <<"Table: " << tableId << "\nParty Size: " << numPeople << "\nWaiter: " << waiter->getName() << "\nSummary: " <<endl;
order->requestSummary();
cout << "Total: " << endl;
order->requestTotal();
cout << " ---------------- " << endl;
status = IDLE;
}
else
{
cout << "Error: " << tableId << " ";
if(numPeople == 0)
{
cout << "No one is at this table." << endl;
}
else
{
cout << "This party hasn't been served." << endl;
}
}
}
Setup: I'm storing the waiters and the orders in vectors.At runtime: when it does the waiter->getName() it complains that it's an invalid read, and that the memory location has been free'd by vector via a deallocater. My logic on the matter: It looks ahead and sees that the vector itself is not accessed again and so deallocates it. Since I do no more writing after this point, the memory location remains intact. When it tries to read the location it sees it has been free'd, hence invalid read but it still gets the appropriate data. So my question then, I suppose is two fold:Does this logic sound right? What should I do to fix it?
#ifndef HW3_H
#define HW3_H
#include <vector>
#include "Table.h"
#include "Waiter.h"
class hw3
{
private:
vector<Table> tables;
vector<Waiter> waiters;
vector<Order> orders;
public:
void begin();
};
#endif
.cpp file, most of the allocation:
ifstream configFile("config.txt"); //This guy is for initializing things
string line;
Menu theMenu;
getline(configFile, line);
stringstream intMaker;
int t1;
int t2;
string temp;
string temp2;
string temp3;
while (true)
{
getline(configFile, line);
Tokenizer str(line, " \n");
if(line =="")
{
break;
}
else
{
temp = str.next();
temp2 = str.next();
intMaker << temp;
intMaker >> t1;
intMaker.str("");
intMaker.clear();
intMaker << temp2;
intMaker >> t2;
intMaker.str("");
intMaker.clear();
tables.push_back(*(new Table(t1,t2)));
}
}
getline(configFile, line);
while (true)
{
getline(configFile, line);
Tokenizer name(line, " ");
string tabl = "";
//Siphon off the name and the tables.
temp = name.next();
tabl = name.next();
Tokenizer strink(tabl, ",\n");
int numTables = (int) tables.size();
Table * tabs[numTables];
t1 = 0;
int keepinTabs = 0;
while(true)
{
string temp2 = strink.next();
if (temp2 == "")
{
break;
}
else
{
intMaker << temp2;
intMaker >> t1;
intMaker.str("");
intMaker.clear();
for(int i = 0; i < numTables; i++)
{
if(tables.at(i).getTableId() == t1)
{
tabs[keepinTabs] = &tables.at(i);
}
}
keepinTabs++;
}
}
waiters.push_back(*(new Waiter(temp, tabl, *tabs))); //Waiter(name, list of tables, and an array of table numbers.
for(int j = 0; j < keepinTabs; j++)
{
for(int i = 0; i < tables.size(); i++)
{
if(tabs[j]->getTableId() == tables[i].getTableId())
{
tables.at(i).assignWaiter(&(waiters.back()));
}
}
}
if(line == "")
{
break;
}
}
Multiple issues I can see:
tables.push_back(*(new Table(t1,t2)));
This code dynamically allocates an object of type Table, then pushes a copy of this object into tables, and then forgets the address of the dynamically allocated object - you're leaking memory.
waiters.push_back(*(new Waiter(temp, tabl, *tabs)));
As above, with Waiter this time.
tabs[keepinTabs] = &tables.at(i);
This takes the address of an object inside the vector. While legal, it's extremely fragile. std::vector can move its contents around in memory when it resizes (e.g. when you push into it).
This (or similar code elsewhere) might be the cause of your segfault. Seeing as you're allocating the objects dynamically, maybe you should declare your vectors to hold just pointers:
vector<Table*> tables;
vector<Waiter*> waiters;
vector<Order*> orders;
You would then do e.g. tables.push_back(new Table(t1, t2));. Of course, you have to make sure to delete the dynamically allocated objects when you remove them from the vectors. An alternative would be to use smart pointers, e.g.:
vector<std::shared_ptr<Table> > tables;
vector<std::shared_ptr<Waiter> > waiters;
vector<std::shared_ptr<Order> > orders;

Accessing a pointer to a vector c++

Im having trouble accessing the following vector. Im new to vectors so this is probably a small syntactical thing i've done wrong. here is the code....
void spellCheck(vector<string> * fileRead)
{
string fileName = "/usr/dict/words";
vector<string> dict; // Stores file
// Open the words text file
cout << "Opening: "<< fileName << " for read" << endl;
ifstream fin;
fin.open(fileName.c_str());
if(!fin.good())
{
cerr << "Error: File could not be opened" << endl;
exit(1);
}
// Reads all words into a vector
while(!fin.eof())
{
string temp;
fin >> temp;
dict.push_back(temp);
}
cout << "Making comparisons…" << endl;
// Go through each word in vector
for(int i=0; i < fileRead->size(); i++)
{
bool found = false;
// Go through and match it with a dictionary word
for(int j= 0; j < dict.size(); j++)
{
if(WordCmp(fileRead[i]->c_str(), dict[j].c_str()) != 0)
{
found = true;
}
}
if(found == false)
{
cout << fileRead[i] << "Not found" << endl;
}
}
}
int WordCmp(char* Word1, char* Word2)
{
if(!strcmp(Word1,Word2))
return 0;
if(Word1[0] != Word2[0])
return 100;
float AveWordLen = ((strlen(Word1) + strlen(Word2)) / 2.0);
return int(NumUniqueChars(Word1,Word2)/ AveWordLen * 100);
}
The error is in the lines
if(WordCmp(fileRead[i]->c_str(), dict[j].c_str()) != 0)
and
cout << fileRead[i] << "Not found" << endl;
the problem seems to be, because its in the form of a pointer the current syntax im using to access it is made invalid.
Using [] on a pointer to a vector will not call std::vector::operator[]. To call std::vector::operator[] as you want, you must have a vector, not a vector pointer.
The syntax to access the n-th element of a vector with a pointer to the vector would be: (*fileRead)[n].c_str().
However, you should just pass a reference to the vector:
void spellCheck(vector<string>& fileRead)
Then it's just:
fileRead[n].c_str()
You can use the unary * to get a vector& from a vector*:
cout << (*fileRead)[i] << "Not found" << endl;
Two options to access:
(*fileRead)[i]
fileRead->operator[](i)
One option to improve the method
pass by reference
You can either pass fileRead by reference like this:
void spellCheck(vector<string> & fileRead)
Or add a dereferece when you use it like this:
if(WordCmp( (*fileRead)[i]->c_str(), dict[j].c_str()) != 0)