Can't read integer from file to matrix - c++

I have to read from a file an array of numbers with an unknown size and save it as a matrix. The code must be as compact as possible, which is why I don't want to read file as string and then convert it to an int.
int main()
{
ifstream infile("array.txt");
int n, counter = 0, **p;
while (!infile.eof()) {
counter++;
}
counter = sqrt(counter);
cout << "counter is " << counter << endl;
p = new int*[counter];
for (int i = 0; i < counter; i++)
p[i] = new int[counter];
while (!infile.eof()) {
for (int i = 0; i < counter; i++) {
for (int j = 0; j < counter; j++)
p[i][j] = n;
}
}
for (int i = 0; i < counter; i++) {
for (int j = 0; j < counter; j++) {
cout << p[i][j] << " ";
}
cout << endl;
}
_getch();
return 0;
}
Here is my code, it was made for a square matrix. The problem is, I can't read the file at second time to save the numbers to the matrix.

You have a lot of problems in your code. A big one is that you have several infinite loops and aren't even reading from a file. An even bigger problem is that you're not using C++ constructs. I've written a small program that does what you're trying to do using more C++ concepts. In this case, you should use a std::vector - they will handle all the dynamic sizing for you.
test.cc
#include <iostream>
#include <vector>
#include <sstream>
#include <fstream>
#include <string>
// Nobody wants to write `std::vector<std::vector<int>>` more than once
using int_matrix = std::vector<std::vector<int>>;
void populate_matrix(int_matrix& mat, const std::string& line) {
int num;
std::stringstream ss(line);
std::vector<int> row;
// Push ints parsed from `line` while they still exist
while(ss >> num) {
row.push_back(num);
}
// Push the row into the matrix
mat.push_back(row);
}
// This is self-explanatory, I hope
void print_matrix(const int_matrix& mat) {
size_t n = mat.at(0).size();
for(size_t i = 0; i < n; ++i) {
for(size_t j = 0; j < n; ++j) {
std::cout << mat.at(i).at(j) << " ";
}
std::cout << std::endl;
}
}
int main(int argc, char** argv) {
int_matrix mat;
// Pass the file as a command-line arg. Then you don't need to worry about the path as much.
if(argc != 2) {
std::cout << "Number of arguments is wrong\n";
return EXIT_FAILURE;
}
// Open file with RAII
std::ifstream fin(argv[1]);
std::string line;
// Handle each line while we can still read them
while(std::getline(fin, line)) {
populate_matrix(mat, line);
}
print_matrix(mat);
return EXIT_SUCCESS;
}
This code assumes the text file looks something like this:
numbers.txt
1 2 3
4 5 6
7 8 9
i.e., n lines with n numbers per line separated by whitespace.
To compile and run this code, you can follow these steps:
13:37 $ g++ test.cc -std=c++14
13:37 $ ./a.out /path/to/numbers.txt

As far as I can see the program runs once through the file and later you run another while loop to read from the file. When you read from a file, then its like your "cursor" moves forward. So basicly, if you hit the end, you have to reset the cursor back to the start of the file.
You can set your cursor back with seekg(0).(http://www.cplusplus.com/reference/istream/istream/seekg/)

Related

How to make my program faster with Open MPI? My Open MPI program is currently slower than the original, what am I not understanding?

I have written a program for an assignment that cracks passwords using a dictionary attack and am trying to speed it up using Open MPI but my Open MPI version is slower and I am not sure why or what I am not understanding. The encrypted passwords are generated using a salt and a string passed into the unix function 'crypt.'
From what I have learned from looking at my class lecture notes, this is what I have come up with.
main.cc:
//****************************************************
// File: main.cc
// Author: Jordan Ward
// Purpose: Crack passwords in the form word+number
// or number+word where number can be at most
// three digits long using
// Open MPI to make it more efficient.
//*****************************************************
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <unistd.h>
#include <mpi.h>
using namespace std;
// Builds the list of encrypted passwords,
// list of dictionary words, and list of salts.
void file_IO(int argc, char *argv[], vector<string> &encPass, vector<string> &words,
vector<string> &salts);
// Builds the list of possible guesses.
void build_guesses(vector<string> &guesses, vector<string> &words);
// Tries each of the salts with each of
// the strings in the list of guesses to see
// if they match the ecrypted passwords.
void crack(string pass, vector<string> &salts, vector<string> &guesses);
// Broadcasts the vectors to all other processes.
void broadcast_receive(vector<string> &encPass, vector<string> &words,
vector<string> &salts, vector<string> &guesses);
// Converts a vector of strings to a vector of chars
vector<char> convert(vector<string> &strings);
int main(int argc, char *argv[]) {
vector<string> encPass;
vector<string> words;
vector<string> salts;
vector<string> guesses;
int numProcesses;
int procNum;
MPI_Init(NULL, NULL);
MPI_Comm_size(MPI_COMM_WORLD, &numProcesses); // Get the number of processes
MPI_Comm_rank(MPI_COMM_WORLD, &procNum); // Get the process number
if(procNum == 0) {
file_IO(argc, argv, encPass, words, salts);
build_guesses(guesses, words);
}
broadcast_receive(encPass, words, salts, guesses, numProcesses, procNum);
if(procNum != 0) {
for(size_t i = 0; i < encPass.size(); i++) {
if(i % procNum == 0) {
size_t del = encPass[i].rfind("$"); // Finds the last "$" in the string
string pass = encPass[i].substr(del); // Pass is a substring starting at the last "$"
crack(pass, salts, guesses);
}
}
}
MPI_Finalize();
return 0;
}
void file_IO(int argc, char *argv[], vector<string> &encPass, vector<string> &words,
vector<string> &salts) {
if(argc < 3) {
cout << "One or more files were not specified." << endl;
cout << "Correct format is 'mpiexec a.out file1 file2'" << endl;
exit(1);
}
ifstream secretPass(argv[1]);
string singlePass;
while(getline(secretPass, singlePass)) {
encPass.push_back(singlePass);
}
secretPass.close();
ifstream dictionary(argv[2]);
string word;
while(getline(dictionary, word)) {
words.push_back(word);
}
dictionary.close();
ifstream salt("salts");
string s;
while(getline(salt, s)) {
salts.push_back(s);
}
salt.close();
}
void build_guesses(vector<string> &guesses, vector<string> &words) {
//one word and one number
for(size_t i = 0; i < words.size(); i++) {
for(size_t j = 0; j < 10; j++) {
guesses.push_back(words[i] + to_string(j));
}
}
//one number and one word
for(size_t i = 0; i < 10; i++) {
for(size_t j = 0; j < words.size(); j++) {
guesses.push_back(to_string(i) + words[j]);
}
}
//one word and two numbers
for(size_t i = 0; i < words.size(); i++) {
for(size_t j = 0; j < 10; j++) {
for(size_t x = 0; x < 10; x++) {
guesses.push_back(words[i] + to_string(j) + to_string(x));
}
}
}
//two numbers and one word
for(size_t i = 0; i < 10; i++) {
for(size_t j = 0; j < 10; j++) {
for(size_t x = 0; x < words.size(); x++) {
guesses.push_back(to_string(i) + to_string(j) + words[x]);
}
}
}
//one word and three numbers
for(size_t i = 0; i < words.size(); i++) {
for(size_t j = 0; j < 10; j++) {
for(size_t x = 0; x < 10; x++) {
for(size_t y = 0; y < 10; y++) {
guesses.push_back(words[i] + to_string(j) + to_string(x) + to_string(y));
}
}
}
}
//three numbers and one word
for(size_t i = 0; i < 10; i++) {
for(size_t j = 0; j < 10; j++) {
for(size_t x = 0; x < 10; x++) {
for(size_t y = 0; y < words.size(); y++) {
guesses.push_back(to_string(i) + to_string(j) + to_string(x) + words[y]);
}
}
}
}
}
void crack(string pass, vector<string> &salts, vector<string> &guesses) {
for(size_t i = 0; i < salts.size(); i++) {
for(size_t j = 0; j < guesses.size(); j++) {
string ep = crypt(guesses[j].c_str(), salts[i].c_str());
if(ep.compare(salts[i] + pass) == 0) {
cout << "Password: " + guesses[j] << endl;
}
}
}
cout << "Password not found" << endl;
}
void broadcast_receive(vector<string> &encPass, vector<string> &words,
vector<string> &salts, vector<string> &guesses) {
int buffer[5];
buffer[0] = encPass.size();
buffer[1] = words.size();
buffer[2] = salts.size();
buffer[3] = guesses.size();
MPI_Bcast(buffer, 4, MPI_INT, 0, MPI_COMM_WORLD);
encPass.resize(buffer[0]);
words.resize(buffer[1]);
salts.resize(buffer[2]);
guesses.resize(buffer[3]);
vector<char> ep = convert(encPass);
vector<char> w = convert(words);
vector<char> s = convert(salts);
vector<char> g = convert(guesses);
MPI_Bcast(ep.data(), ep.size(), MPI_CHAR, 0, MPI_COMM_WORLD);
MPI_Bcast(w.data(), w.size(), MPI_CHAR, 0, MPI_COMM_WORLD);
MPI_Bcast(s.data(), s.size(), MPI_CHAR, 0, MPI_COMM_WORLD);
MPI_Bcast(g.data(), g.size(), MPI_CHAR, 0, MPI_COMM_WORLD);
}
vector<char> convert(vector<string> &strings) {
vector<char> cstrings;
cstrings.reserve(strings.size());
for(string s : strings) {
for(size_t i = 0; i < strlen(s.c_str()); i++) {
cstrings.push_back(s.c_str()[i]);
}
}
return cstrings;
}
My thought process is:
If process number is 0, read in the files and build the vectors with strings from the files and then build the list of guesses.
Else, receive all the lists and go through each encrypted password and see if any of the salts combined with any of the guesses matches the encrypted password.
What am I not doing correctly or not understanding that is making this slower than the original without the Open MPI code? Original code would just be the same file without the broadcast_receive and convert functions and obviously without the MPI calls in the main function.
I am compiling with mpic++ -std=c++11 -Wall main.cc -lcrypt and then running with mpiexec a.out enc_passwords words where enc_passwords is a small file with some encrypted passwords generated from the crypt function and words is a small list of words to build the guesses with.
Regarding your first question (why isn't MPI "faster"?), you need to ask two questions:
Q: Is the work actually being partitioned to multiple processors, in parallel?
Q: Does the overhead of message passing exceed the actual work you're trying to parallelize?
This should help with both questions:
OpenMPI FAQ: Performance Tools
Regarding your follow-on comment, "...but for some reason it is throwing a ton of errors.": please provide an MCVE. Or simply revert back to the "working" code.

Having issues eliminating duplicates and sorting from C++ array outfile

Trying to create a list of unique grades from a text file. Having issues with the output eliminating duplicates. Currently, I am trying to compare the value of each previous array entry to the next and if they are different, output the result to the outfile, but is just outputs an empty file.
I am also curious if there is an easy fix to change the sorting from 'low to high' into 'high to low'. Thank you in advance.
#include <iostream>
#include <string>
#include <limits>
#include <cmath>
#include <iomanip>
#include <fstream>
using namespace std;
int testScoreArray[100];
void selectSort(int testScoreArray[], int n);
void fileOutput(int testScoreArray[]);
int main()
{
int n = 100;
ifstream infile;
infile.open("testscoresarrayhomework.txt");
for (int i = 0; i < 100; i++) {
infile >> testScoreArray[i];
}
selectSort(testScoreArray, n);
fileOutput(testScoreArray);
infile.close();
return 0;
}
void selectSort(int testScoreArray[], int n)
{
//pos_min is short for position of min
int pos_min, temp;
for (int i = 0; i < n - 1; i++) {
pos_min = i; //set pos_min to the current index of array
for (int j = i + 1; j < n; j++) {
if (testScoreArray[j] < testScoreArray[pos_min])
pos_min = j;
//pos_min will keep track of the index that min is in, this is needed when a swap happens
}
//if pos_min no longer equals i than a smaller value must have been found, so a swap must occur
if (pos_min != i) {
temp = testScoreArray[i];
testScoreArray[i] = testScoreArray[pos_min];
testScoreArray[pos_min] = temp;
}
}
};
void fileOutput(int testScoreArray[])
{
ofstream outfile;
int gradeEvent = 0;
int previousGrade = 0;
outfile.open("testscoresoutput.txt");
outfile << "Test Score Breakdown: ";
outfile << endl
<< "Score / Occurance";
for (int i = 0; i < 100; i++) {
previousGrade = i;
if (previousGrade && previousGrade != i) {
outfile << '\n' << testScoreArray[i] << " / " << gradeEvent;
}
}
outfile.close();
};
You have declared a global variable testScoreArray and the function names use the same variable name for their parameters. It's best to avoid using global variables when possible. You can remove global declaration, then declare testScoreArray in main, and pass it to your functions. Example:
//int testScoreArray[100]; <=== comment out
void selectSort(int *testScoreArray, int n);
void fileOutput(int *testScoreArray, int n); //add array size
int main()
{
int testScoreArray[100]; //<== add testScoreArray in here
int n = sizeof(testScoreArray) / sizeof(testScoreArray[0]);
selectSort(testScoreArray, n);
fileOutput(testScoreArray, n);
...
}
In fileOutput you are basically checking to see if i != i, you need to examine the array, not indexing in the loop:
void fileOutput(int *testScoreArray, int n)
{
ofstream outfile("testscoresoutput.txt");
for(int i = 0; i < n; i++)
if(i && testScoreArray[i] != testScoreArray[i-1])
outfile << testScoreArray[i] << "\n";
};
To revers the sort, simply change the condition in this comparison
if (testScoreArray[j] < testScoreArray[pos_min])
pos_min = j;
To:
if(testScoreArray[j] > testScoreArray[pos_min])
pos_min = j;
Technically you would rename the variable to pos_max

writing to 2D vector, is crashing my program

I'm new to vectors programming, so my code is buggy:
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
int main()
{
std::ifstream in("input.txt");
std::vector<std::vector<int> > v, w;
if (in) {
std::string line;
while (std::getline(in, line)) {
v.push_back(std::vector<int>());
for(int x=0; x<line.size(); x++){
v.back().push_back((int)line[x] - (int)'0');
}
}
}
for (int i = 0; i < v.size(); i++) {
for (int j = 0; j < v[i].size(); j++)
std::cout << v[i][j] << ' ';
std::cout << '\n';
}
int size = v.size(); //because its a square matrix
w = v; //w is our temp vector for storing new values;
int alive =0;
int z=0;
for (int i=0;i<size;i++)
{
for (int j=0;j<size; j++)
{
alive = 0;
for(int c = -1;c<2; c++)
{
for(int d = -1; d<2 ; d++)
{
if(!(c==0 && d == 0))
{
z = v[i+c][j+d];
if(z)
++alive;
}
}
if(alive<2) w[i].push_back(0);
else if(alive == 3) w[i].push_back(1);
else w[i].push_back(0);
}
}
}
return 0;
}
I think I am assigning values into my second variable wrong. My program reads from an input file along the lines:
1010101
0101010
1010101
and is to write to the second vector w after analyzing its neighbors (game of life problem), I think I should use w.push_back() but I'm not sure on the syntax for a 2D vector. Is there a better way to push the variable?
There are two problems that I notice right away. The main one that is causing your crash is you are accessing outside of the bounds for the v array. This happens when i is 0 and c is -1, and can also happen when i is size-1 and c is +1 (the same thing happens with j and d).
The other issue is with how you save the alive value into w. Since you start with w = v, you have all the elements you need. Just replace them with, for example, w[i][j] = 0. (You'll also want to move that conditional block outside of the c loop.)

Reading 2-dimensional table to array

I have a simple program that tries to read 2-dimensional data into a heap allocated array of floating-points. The program is as follows.
#include <iostream>
#include <fstream>
void read_file(std::ifstream &inFile, float **arr, unsigned m, unsigned n)
{
for(unsigned i = 0; i < m; ++i) {
for(unsigned j = 0; j < n; ++j) {
inFile >> arr[i][j];
std::cout << arr[i][j];
}
std::cout << std::endl;
}
}
int main() {
const unsigned m = 20;
const unsigned n = 1660;
float **A = new float *[m]; // alloc pointers to rows 1,...,m
for(unsigned row = 0; row < m; row++) A[row] = new float [n]; // alloc columns for each row pointer
std::ifstream inFile("data.dat");
read_file(inFile, A, m, n);
// DEALLOC MEMORY
for(unsigned row = 0; row < m; row++) delete [] A[row]; // dealloc columns for each row pointer
delete [] A; // dealloc row pointers
return EXIT_SUCCESS;
}
The data is a table of 0-1 entries (see here: data) which is nicely row orientated and has 20 rows and 1660 columns. I added the printing into the read_file function to see what goes wrong and it prints only zeros, but the correct amount at least (20*1660 zeros).
The data seems to be tab delimitered; is that the problem or is my approach completely invalid?
It's exactly what may happen if the file doesn't exist.
You should check that the file exists after creating the inFile object, for instance like this:
std::ifstream inFile("data.dat");
if (!inFile)
{
std::cerr << "cannot open input" << std::endl;
return 1;
}
If file doesn't exist, cin doesn't put data in your array, and there are chances that you get 0 all the way (I had 0 + other strange stuff), so to sum it up undefined behaviour
Note that if the file exists, your program works as expected. It would be even better to check the file after having read a value to be sure that the file has as many values as expected:
for(unsigned j = 0; j < n; ++j) {
inFile >> arr[i][j];
if (!inFile)
{
std::cerr << "file truncated " << i << " " << j << std::endl;
return;
}
std::cout << arr[i][j];
}

How to Save and Read Binary Data?

I need your help again for the save and read data in binary. I have, a vector<<complex> > xy(256) which is read from the hardware in 10 times:
vector<<complex> > xy(256);
ofstream outfile2 (outfilename2.c_str() , ofstream::binary);
....
....
for(unsigned t = 0; t < 10; t++)
{
....
....
for(unsigned i = 0; i < 256; i++)
{
xy[i] = f[i] * conj(g[i]);
}
for(unsigned i = 0; i < 256; i++)
{
outfile2 << boost::format("%20.8e") % xy[i]<< endl; // write in text
}
} // the text data will be 2560 lines of complex data, for example:
// (6.69635350e+06,7.34146150e+06)
Now, I am trying to save into binary file, using this command:
for(unsigned i = 0; i < 256; i++)
{
outfile2.write((const char*)& xy[i], 1 * sizeof(complex<short>));
outfile2.flush();
}
Although, it still give me a data, but when i compare to the original text data, they were different. I do not understand why?
I would like to read complex 16 with floating point data.
I hope you guys can help.
Thank you very much.
I have written a demo, which works on my computer.
#include <cassert>
#include <complex>
#include <fstream>
#include <iostream>
#include <type_traits>
#include <vector>
int main() {
assert( std::is_trivially_copy_assignable<std::complex<short> >::value );
std::vector<std::complex<short> > vtr(256);
for (int i=0; i<256; ++i)
vtr[i] = std::complex<short>(i*2,i*2+1);
{
std::ofstream output("data.bin", std::ofstream::binary);
for (int i=0; i<256; ++i)
output.write((char *)&vtr[i],sizeof(vtr[i]));
}
vtr.clear();
std::cout << vtr.size() << std::endl;
vtr.resize(256);
{
std::ifstream input("data.bin", std::ifstream::binary);
for (int i=0; i<256; ++i)
input.read((char *)&vtr[i],sizeof(vtr[i]));
}
for (size_t i=0; i<vtr.size(); ++i)
std::cout << vtr[i] << " ";
std::cout << std::endl;
return 0;
}
You could run this demo on your computer. If this demo works, it's likely that you made some mistakes in your code. Please provide a complete, and verifiable example.