user1362058 user1362058 - 1 month ago 9
C++ Question

While parsing same arguments, sometimes segfault

I am writing a C++ program that will read in two matrices from two separate files. It will do things with these matrices eventually but I am having issues parsing the command line options right now. This is how I am being presented the data.

There are a couple different command line variants:

dtype N file1 file2 file3

dtype N M L file1 file2 file3

where dtype can be either int or double, if just N is presented all matrices are NxN, otherwise matrix1 is NxM and matrix2 if MxL, and files 1 and 2 contain the matrices to be manipulated while file3 is where the result will be stored.

I have included what I have written so far below. I am a novice with C++ so please don't be too harsh on your criticism.

The issue is right now if I run this code it seems completely random if it will segfault and I have no idea what could be causing it. I know it could be a pain in the rear to troubleshoot segfaults, I look at other questions on here, but I literally have no other option but to ask for your help as I am at a stand still.

To troubleshoot I compiled g++ with the -g option and ran my program through gdb. I could not replicate the segfault through gdb.

#include <iostream>
#include <string>
#include <string.h>
#include <vector>
#include <fstream>
#include <typeinfo>
#include <sys/stat.h>
#include <stdexcept>

using namespace std;

inline bool exists_test(const std::string& name) {
struct stat buffer;
return (stat (name.c_str(), &buffer) == 0);
}

int main(int argc, char const *argv[])
{

int dtype = 0; // 0 = int; 1 = double
int M = 0;
int N = 0;
int L = 0;
const char *file1;
const char *file2;
const char *file3;

for (int i=1; i<argc ; i++)
{
try
{
if(i==1){
if(!((strcmp(argv[1], "int") == 0) || (strcmp(argv[1], "double") == 0))){
throw invalid_argument("wrong dtype");
}else{
if((strcmp(argv[1], "double") == 0)){
dtype = 1;
}
}
}else if(i==2){
M=stoi(argv[i]);
}else if(i==3){
if(!exists_test(argv[i])){
N=stoi(argv[i]);
}else{
file1 = argv[i];
}
}else if(i==4){
if(!exists_test(argv[i])){
L=stoi(argv[i]);
}else{
file2 = argv[i];
}
}else if(i==5 || i==6 || i==7){
if(!exists_test(argv[i])){
throw invalid_argument("no such file");
}else{
if(i==6){
file2 = argv[i];
}else if(i==7){
file3 = argv[i];
}else if(strcmp(file1, argv[i]) == 0){

}else{
file1 = argv[i];
}
}
}
continue;
}
catch (...)
{
cout << "error code 1 or this one" << endl;
return 1;
}
}

if(N==0){
N=M;
}
if(L==0){
L=M;
}

ifstream thisfile;

double filler = 0;
vector<double> readThese;
vector< vector<double> > matrixA(4, vector<double>(3, 0));

thisfile.open(file1);

while (thisfile >> filler )
{
readThese.push_back(filler);
}

thisfile.close();

//for(int j = 0; j < N; j++){
// matrixA[0][j] = readThese[j];
//}

cout << matrixA[0][0] << " " << matrixA[0][1] << " " << matrixA[0][2] << " " << matrixA[0][3] << endl;
cout << matrixA[1][0] << " " << matrixA[1][1] << " " << matrixA[1][2] << " " << matrixA[1][3] << endl;
cout << matrixA[2][0] << " " << matrixA[2][1] << " " << matrixA[2][2] << " " << matrixA[2][3] << endl;
cout << matrixA[3][0] << " " << matrixA[3][1] << " " << matrixA[3][2] << " " << matrixA[3][3] << endl;
}


The following shows that the output of the program. It doesn't always segfault every other time, it just happened to this time.

$ ./a.out int 3 4 1 file1 file2
0 0 0 1.63042e-322
0 0 0 1.63042e-322
0 0 0 1.63042e-322
0 0 0 5.14322e-321
$ ./a.out int 3 4 1 file1 file2
Segmentation fault (core dumped)
$ ./a.out int 3 4 1 file1 file2
0 0 0 1.63042e-322
0 0 0 1.63042e-322
0 0 0 1.63042e-322
0 0 0 5.14322e-321
$ ./a.out int 3 4 1 file1 file2
Segmentation fault (core dumped)

Answer

You declare

matrixA(4, vector<double>(3, 0));

which represents a 4 x 3 matrix, but then access the 4-th column

cout << matrixA[0][0] << " " << matrixA[0][1] << " "\
     << matrixA[0][2] << " " << matrixA[0][3] << endl;
                                ^^^^^^^^^^^^^
                                   here

which is inexistent, so you get a segfault. To test out of bounds, you can use vector::at() instead of vector::operator[], it is slower but throws an exception if you access out of bounds. Once you make sure the code is fine, you can reverse to operator[].

BTW, in general it's a bad idea to represent a matrix as a vector<vector>. It's way better to use a single vector and map from 1D to 2D coordinates and vice-versa, due to the fact that a single vector guarantees that the elements are contiguously stored in memory hence you have better cache locality.