2

I am using visual studio 2012 writing normal c++ and I keep getting this error for a variable I have declared.

1>c:\users\joe\skydrive\documents\c++\consoleapplication2\matracies 1.cpp(182): error C2065: 'file' : undeclared identifier
1>c:\users\joe\skydrive\documents\c++\consoleapplication2\matracies 1.cpp(184): error C2065: 'file' : undeclared identifier

This is the function where I am getting the error.

void WriteMatrix(vector<vector<float>> Matrix, float row, float col, int choice)
{
if (choice == 1)
{
    ofstream file("MultiplyMatrix.txt", ios::app);
}
else if (choice == 2)
{
    ofstream file("AddMatrix.txt", ios::app);
}
else if (choice == 3)
{
    ofstream file("AddMatrix.txt", ios::app);
}
for(int i=0; i<row; i++)
{
    for(int j=0; j<col; j++)
    {
        float temp = Matrix[i][j];
        file<<temp<<" ";
    }
    file<<endl;
}
file<<endl;
file.close();
}
László Papp
  • 51,870
  • 39
  • 111
  • 135
Norno3
  • 87
  • 1
  • 11

4 Answers4

3

As Oli said, file only exists in the block within which it's defined.

You need to define file before the if statements. Then use file.open to open the chosen file.

And consider what happens if choice is neither 1, 2, or 3.

ooga
  • 15,423
  • 2
  • 20
  • 21
2

In C++ { } is used to denote scope. This means that file is only declared within your if statements. You can fix this by declaring file outside your if statements and opening them inside:

ofstream file; int choice;
if (choice == 1)
{
    file.open("MultiplyMatrix.txt", ios::app);
}
else if (choice == 2)
{
    file.open("AddMatrix.txt", ios::app);
}
else if (choice == 3)
{
    file.open("AddMatrix.txt", ios::app);
}
    return 0;
}
yizzlez
  • 8,757
  • 4
  • 29
  • 44
  • 1
    Personally I'd gather the filename in the conditionals, then construct the `ofstream` afterwards. I don't like having "dangly" objects lying around; though it's not unsafe in any way here, my subconscious sees it as a minor breach of RAII. That's a matter of taste, though. – Lightness Races in Orbit Apr 27 '14 at 17:40
2

You are trying to access the file variable outside the conditional branches where its life is over. When you declare them within the { ... } conditional blocks, it will go out of scope at the closing bracket.

The proper solution would be either to declare it in the beginning of your function outside the scope of the conditional branches, and then open the desired files in the branches, or open only after the conditional block.

I would also consider using the switch statement in this case, rather than continous if/elseif/... as that is what the switch statement is for!

Therefore, your code would be like this (with proper indent, too):

void WriteMatrix(vector<vector<float>> Matrix, float row, float col, int choice)
{

This is the first alternative to be demonstrated and probably the nicest C++ solution:

    static const vector<string> filenameLookUpTable{"MultiplyMatrix.txt",
                                        "AddMatrix.txt", "AddMatrix.txt"};
    ofstream file(filenameLookUpTable.at(choice-1), ios::app);

You could also do:

    ofstream file;
    switch(choice) {
    case 1:
        file.open("MultiplyMatrix.txt", ios::app);
        break;
    case 2:
        file.open("AddMatrix.txt", ios::app);
        break;
    case 3:
        file.open("AddMatrix.txt", ios::app);
        break;
    }

You could also write this:

    string filename;
    switch(choice) {
    case 1:
        filename = "MultiplyMatrix.txt";
        break;
    case 2:
        filename = "AddMatrix.txt";
        break;
    case 3:
        filename = "AddMatrix.txt";
        break;
    }

    ofstream file(filename, ios::app);

and then the end, basically:

    for(int i=0; i<row; i++)
    {
        for(int j=0; j<col; j++)
        {
            float temp = Matrix[i][j];
            file<<temp<<" ";
        }
        file<<endl;
    }

    file<<endl;
    file.close();
}
László Papp
  • 51,870
  • 39
  • 111
  • 135
  • re "declare it in the beginning of your function", this is good advice for (conventional, old) C, but in C++ there are good general reasons to *reduce the scope of a variable as much as practically possible*, which means declaring it as close to first use as practically possible. also, redundancy is ungood. so not, it's not "the proper solution", but it's *a* solution. – Cheers and hth. - Alf Apr 27 '14 at 17:32
  • 1
    Defer the file opening till after choosing the name. – Cheers and hth. - Alf Apr 27 '14 at 17:34
  • The `switch` in your code does two things: it chooses the file name, and triplicates the code for opening the file. Let it just choose the file name. Or better, replace the `switch` with an array of file names. – Cheers and hth. - Alf Apr 27 '14 at 17:36
  • 1
    Yeah it's entirely subjective but I do agree with it: my subconscious sees default construction of an `fstream` as a minor violation of RAII, even though it's (mostly) totally safe. I'd gather the filename in the conditionals, _then_ construct your `ofstream`. – Lightness Races in Orbit Apr 27 '14 at 17:41
  • @LaszloPapp I just preferred his answer to start with, but your answer is better now you've edited it. – Norno3 Apr 27 '14 at 18:13
  • @Cheersandhth.-Alf: time to clean up the comments. ;) I will remove this one, too. – László Papp Apr 27 '14 at 18:16
  • @LightnessRacesinOrbit: time to clean up the comments. ;) I will remove this one, too. – László Papp Apr 27 '14 at 18:17
1
void WriteMatrix(vector<vector<float>> Matrix, float row, float col, int choice)

This passes Matrix by value, which means copying, which can be time consuming for a large matrix. Instead pass it by reference, to const if it's not supposed to be changed. Also, the floatargument type for row and col is unreasonable; make that int.

void WriteMatrix(vector<vector<float>> const& Matrix, int row, int col, int choice)

Then this code,

if (choice == 1)
{
    ofstream file("MultiplyMatrix.txt", ios::app);
}
else if (choice == 2)
{
    ofstream file("AddMatrix.txt", ios::app);
}
else if (choice == 3)
{
    ofstream file("AddMatrix.txt", ios::app);
}

does two things:

  • it chooses the filename,

  • it triplicates code for opening and closing a file.

In each branch the file variable is a local automatic variable which ceases to exist (hence, the file closing) at the end of that curly braces block.

The triple redundancy is ungood, and not having access to the variable where it's intended to be used, later on, is ungood. So move that logic to after the file name selection. Then, the selection itself can be reduced to simple array indexing:

assert( 1 <= choice && choice <= 3 );
static char const* const names =
{ "MultiplyMatrix.txt", "AddMatrix.txt", "AddMatrix.txt" };

ofstream file( names[choice - 1], ios::app);
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • I'm totally +1'ing this and dropping my answer, as it is nearly identical (save for I actually if-check rather than debug-assert; now that I think about i should have done *both*). PS: you need a [] on the end of `names` – WhozCraig Apr 27 '14 at 17:49
  • @WhozCraig: well i have left to comment on the `float` arguments. didn't see that. it's like i have a filter so i only see reasonable things. – Cheers and hth. - Alf Apr 27 '14 at 17:51
  • I used `static const vector filenameLookUpTable{"MultiplyMatrix.txt", "AddMatrix.txt", "AddMatrix.txt"}; ofstream file(filenameLookUpTable.at(choice-1), ios::app);`, IMHO, that is the nicest C++ solution. Containers and initializer list \o/. :P – László Papp Apr 27 '14 at 17:55
  • 1
    @LaszloPapp: Since you're using C++11 syntax anyway, consider using `std::array`. That still provides you with `size` member, and avoids the dynamic allocation at the cost of not having the range checking `at`. But I think an `assert` is much more natural here than an exception. ;-) – Cheers and hth. - Alf Apr 27 '14 at 17:58
  • @Cheersandhth.-Alf: you will need to manually update the assert if the values change, with exception, you do not, so it is more flexible. Also, assert will not be there in release builds. – László Papp Apr 27 '14 at 17:59
  • @LaszloPapp: Re "you will need to manually update the assert if the values change", yes, but you will need to update the names list anyway. The assert could be in terms of number of names in the array, but I intentionally chose not to do that. – Cheers and hth. - Alf Apr 27 '14 at 18:04
  • If you need to update a, it is ok to introduce a dependency on updating b? That is more work than it could be, and not an excuse IMHO. – László Papp Apr 27 '14 at 18:12