-
March 3rd, 2009, 01:49 PM
#1
Seg fault error
Hey I am writing a c++ program that takes in input from the command line of two files containing matrices. It then takes that and does matrix multiplication. The results are outputted to a file. When I compile using g++ I get a segmentation fault error. I have tried adding cout to find the source but to no avail. Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <iostream>
using namespace std;
float mat_sum(vector <vector<float> > mata,vector <vector<float> > matb, int row, int column, int rowc);
int main (int argc, char *argv[])
{
vector <vector<float> > mata, matb, matc; //initalize matricies
int rows, cols; //value for rows and columns input matrix
int rowc, colc; //values for row and column output matrix
float temp, sum;
FILE *matrixa, *matrixb, *matrixc;
matrixa=fopen(argv[0],"r");
fscanf (matrixa,"%d %d", &rows, &cols);
rowc=cols;
cout<<rowc;
for (int i=0; i<rows; i++){
mata.push_back (vector<float>() );
for (int j=0; j<cols; j++){
fscanf (matrixa,"%f",temp);
mata[i].push_back(temp);
}
}
fclose (matrixa);
matrixb=fopen(argv[1],"r");
fscanf (matrixb,"%d %d", &rows, &cols);
colc=rows;
for (int i=0; i<rows; i++){
matb.push_back (vector<float>() );
for (int j=0; j<cols; j++){
fscanf (matrixb,"%f",temp);
matb[i].push_back(temp);
}
}
fclose (matrixb);
matrixc=fopen(argv[2],"w");
fprintf (matrixc,"%d\n%d\n",rowc,colc);
for (int i=0; i<rowc; i++){
matc.push_back (vector<float>());
for (int j=0; j<colc; j++){
matc[i].push_back(mat_sum(mata,matb,i,j,rowc));
fprintf(matrixc," %f",matc[i][j]);
}
fprintf(matrixc,"\n");
}
fclose(matrixc);
return 0;
}
float mat_sum(vector <vector<float> > mata,vector <vector<float> > matb,int row,int column, int rowc){
float sum=0;
for (int i=0; i<rowc; i++){
sum=sum+mata[row][i]*matb[i][column];
}
return sum;
}
-
March 3rd, 2009, 01:52 PM
#2
Re: Seg fault error
Use code tags when posting.
Run it in the debugger.
-
March 4th, 2009, 04:20 AM
#3
Re: Seg fault error
Probably caused by buffer overflow.
Alias you 2D array with typedef and initialize with fixed column and row and you can resize row with resize().
Thanks for your help.
-
March 4th, 2009, 07:21 AM
#4
Re: Seg fault error
At a first glance the following code runs into eyes:
Code:
fscanf (matrixb,"%f",temp);
The arguments to scanf() functions that follow the format string specification are addresses of the vars where the input should be stored. In the code above float temp is interpreted as a memory address, which of course (probably) is from unmapped region - and attempt to write might cause segfault.
As you probably guess, you should write instead:
Code:
fscanf (matrixb, "%f", &temp);
-
March 4th, 2009, 07:26 AM
#5
Re: Seg fault error
Firstly you should write some error checking code, how do you know you have been given three arguments? You should check this e.g.
Code:
if(argc!=4) //program name + three arguments = 4 program arguments
{
std::cerr << "Usage: [program] [inMatrix1] [inMatrix2] [outMatrix]" << std::endl;
}
else
{
//...
}
Incidently, did you realise that argv[0] is not the first argument but the program name? Therefore your accessing of argv[0], argv[1] and argv[2] should be argv[1], argv[2] and argv[3] respectively. This is obviously a contributer to the problems you are having.
Secondly, make sure you initialise your variables and preferably only declare one per line.
Thirdly, when writing C++, please get into the habit of using the C++ file stream instead of C's FILE. You could then use istream to convert the next bit of data to a int, float or what ever else it needs to be directly and safely without attempting to use C functions such as fscanf - I expect your other problems are to do with misuse or abuse of these C functions.
Fourthly, you could extract your read code into a function since you are effectively doing the same thing twice.
Fifthly, consider exception safety...
I have to go to lunch now, but if nobody else has replied by then, I'll help you with the code a bit more.
Last edited by PredicateNormative; March 4th, 2009 at 09:41 AM.
-
March 4th, 2009, 09:38 AM
#6
Re: Seg fault error
I'm now able to reply to this... so here are my thoughts. Firstly, as Peter_APIIT pointed out, a typedef wouldn't go amiss:
Code:
typedef std::vector<std::vector<float> > Vector2D;
Now, as I previously mentioned, once you have checked that the number of arguments is equal to three, you want to read in the matrix data from the two files into two Vector2D's. Since the code to do this is the same for each matrix file, the code could be extracted into a function to save having to write it twice:
Code:
Vector2D readMatrix(const std::string& filename)
{
Vector2D matrix;
std::ifstream infile(filename.c_str());
float temp(0);
int rows = NextIStreamValTo<int>(infile);
int cols = NextIStreamValTo<int>(infile);
for (int i=0; i<rows; i++){
matrix.push_back (vector<float>() );
for (int j=0; j<cols; j++){
temp = NextIStreamValTo<float>(infile);
matrix[i].push_back(temp);
}
}
infile.close();
return matrix;
}
The function NextIStreamValTo<T> converts the next bit of data from an istream to the type designated by T. The code looks like this:
Code:
template<typename T>
T NextIStreamValTo(std::istream& s)
{
if(!s.good())
{
throw std::runtime_error("NextIStreamValTo failed : istream is not in a good state!");
}
T result;
if(!(s>>result))
{
throw std::runtime_error("NextIStreamValTo failed : failed to convert data to desired type!");
}
return result;
}
Now that is covered, there is arguably a problem with the code I have just given you for readMatrix. Condsider what would happen if the line
Code:
std::ifstream infile(filename.c_str());
failed to open the file given in the string filename. The std::ifstream constructor does not throw an exception if the open fails, so instead the code would carry on. The next thing that would happen is NextIStreamValTo<T> would throw an exception stating that the "istream is not in a good state!" because it could not read the istream. Although this exception message is true, it would be better to state why the istream is in a bad state, and for that an exception should be thrown at the point of failure:
Code:
Vector2D readMatrix(const std::string& filename)
{
Vector2D matrix;
std::ifstream infile(filename.c_str());
float temp(0);
if(infile.is_open())
{
int rows = NextIStreamValTo<int>(infile);
int cols = NextIStreamValTo<int>(infile);
for (int i=0; i<rows; i++){
matrix.push_back (vector<float>() );
for (int j=0; j<cols; j++){
temp = NextIStreamValTo<float>(infile);
matrix[i].push_back(temp);
}
}
infile.close();
}
else
{
throw std::runtime_error("Cannot open file " + filename + " for reading!");
}
return matrix;
}
Now a lot of the logic is correctly handled, the main function outside of error checking and exception handling becomes:
Code:
Vector2D mata = readMatrix(argv[1]);
Vector2D matb = readMatrix(argv[2]);
Vector2D matc;
int colc = mata.size();
int rowc= matb[0].size();
std::ofstream matrixc(argv[3]);
matrixc << rowc << std::endl << colc << std::endl;
for (int i=0; i<rowc; i++){
matc.push_back (vector<float>());
for (int j=0; j<colc; j++){
matc[i].push_back(mat_sum(mata,matb,i,j,rowc));
matrixc << matc[i][j] << " ";
}
matrixc << std::endl;
}
matrixc.close();
Putting it all together then with error checking and exception handling, gives:
Code:
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <stdexcept> //for std::runtime_error
using namespace std;
typedef std::vector<std::vector<float> > Vector2D;
template<typename T>
T NextIStreamValTo(std::istream& s)
{
if(!s.good())
{
throw std::runtime_error("NextIStreamValTo failed : istream is not good!");
}
T result;
if(!(s>>result))
{
throw std::runtime_error("NextIStreamValTo failed : failed to convert data to desired type!");
}
return result;
}
Vector2D readMatrix(const std::string& filename)
{
Vector2D matrix;
std::ifstream infile(filename.c_str());
float temp(0);
int rows = NextIStreamValTo<int>(infile);
int cols = NextIStreamValTo<int>(infile);
for (int i=0; i<rows; i++){
matrix.push_back (vector<float>() );
for (int j=0; j<cols; j++){
temp = NextIStreamValTo<float>(infile);
matrix[i].push_back(temp);
}
}
infile.close();
return matrix;
}
float mat_sum(vector <vector<float> > mata,vector <vector<float> > matb, int row, int column, int rowc);
int main (int argc, char *argv[])
{
if(argc!=4)
{
std::cerr << "Usage: [program] [inMatrix1] [inMatrix2] [outMatrix]" << std::endl;
}
else
{
try
{
Vector2D mata = readMatrix(argv[1]);
Vector2D matb = readMatrix(argv[2]);
Vector2D matc;
int rowc = mata.size();
int colc = matb[0].size();
std::ofstream matrixc(argv[3]);
matrixc << rowc << std::endl << colc << std::endl;
for (int i=0; i<rowc; i++){
matc.push_back (vector<float>());
for (int j=0; j<colc; j++){
matc[i].push_back(mat_sum(mata,matb,i,j,rowc));
matrixc << matc[i][j] << " ";
}
matrixc << std::endl;
}
matrixc.close();
}
catch(std::exception& e)
{
std::cerr << e.what() << std::endl;
}
catch(...)
{
std::cerr << "Unknown exception caught" << std::endl;
}
}
system("PAUSE");
return 0;
}
float mat_sum(vector <vector<float> > mata,vector <vector<float> > matb,int row,int column, int rowc)
{
float sum=0;
for (int i=0; i<rowc; i++){
sum=sum+mata[row][i]*matb[i][column];
}
return sum;
}
Last edited by PredicateNormative; March 5th, 2009 at 03:33 AM.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|