0

I've been working on a C++ program to make morphology changes to a text file that the user chooses, but while making this program I've ran into an issue where a different function that essentially does its purpose the same way as the other functions, wont print. Even though it should be printing.

Here is what I have so far:

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <algorithm>
//look up line by line parsing
using namespace std;
void replacee(vector<vector<char>> &vec, char oldd, char neww)
{
    for (vector<char> &v : vec) // reference to innver vector
    {
        replace(v.begin(), v.end(), oldd, neww); // standard library 
algorithm
    }
}
void dialationn(vector<vector<char>> &vec, char suspect, char n)
{
    for (int i = 0; i < vec.size(); i ++) {
            for (int j = 0; j < vec[i].size(); j++) {
                if (vec[i][j] == suspect) {
                    if (i > 0) {
                     vec[i-1][j] = n;
                    }
                    if (j > 0) {
                     vec[i][j-1] = n;
                    }
                    if (i + 1<vec.size()) {
                        vec[i+1][j] = n;
                    }
                    if (j + 1<vec[i].size()) {
                        vec[i][j+1] = n;
                    }
                }
            }
        }
        replacee(vec, n, suspect);
}    
int main(int argc, char* argv[]) {

    fstream fin; char ch;
    string name (argv[1]); //File Name.
    vector<vector<char>> data;
    // 2D Vector.
    vector<char> temp;
    // Temporary vector to be pushed 
    // into vec, since its a vector of vectors.
    fin.open(name.c_str(),ios::in);
    // Assume name as an arbitary file.
    string argument2 (argv[2]);
    string argument3 (argv[3]);
    string argument4 (argv[4]);
    while(fin)
    {
        ch = fin.get();
        if(ch!='\n') {
            temp.push_back(ch);
        }
        else 
        { 
            data.push_back(temp); 
            temp.clear(); 
        }
    }
    if (argument2 == "replace") {
        replacee(data, argument3[0], argument4[0]);
        for (int i = 0; i < data.size(); i ++) {
            for (int j = 0; j < data[i].size(); j++) {
                cout << data[i][j];
            }
            cout << endl;
        }
    } else if (argument2 == "dilate") {
        dialationn(data, argument3[0], 'i');
        for (int m = 0; m < data.size(); m ++) {
            for (int n = 0; n < data[m].size(); n++) {
                cout << data[m][n];
            }
            cout << endl;
        }
    }

    fin.close();
} 

Note: the reason I'm so confused is because the printing method I used in the int main works for replace, but doesn't work for dilation. I don't see any major differences that occur between the two functions for them to not be printing. I even made a small test program and it worked in that one:

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <algorithm>

using namespace std;
void replacee(vector<vector<char>> &vec, char oldd, char neww)
{
    for (vector<char> &v : vec) 
    {
        replace(v.begin(), v.end(), oldd, neww); 
    }
}

void dialationn(vector<vector<char>> & vec, char suspect, char n)
{
    for (int i = 0; i < vec.size(); i ++) {
            for (int j = 0; j < vec[i].size(); j++) {
                if (vec[i][j] == suspect) {
                    if (i > 0) {
                     vec[i-1][j] = n;
                    }
                    if (j > 0) {
                     vec[i][j-1] = n;
                    }
                    if (i + 1<vec.size()) {
                        vec[i+1][j] = n;
                    }
                    if (j + 1<vec[i].size()) {
                        vec[i][j+1] = n;
                    }
                }
            }
        }
        replacee(vec, n, suspect);
}
int main(int argc, char* argv[]) 
{
    vector<vector<char>> data(5, std::vector<char>(9,'.'));
    data[2][4] = 'x';
    dialationn(data, 'x', 'i');
    for (int i = 0; i < data.size(); i ++) {
            for (int j = 0; j < data[i].size(); j++) {
                cout << data[i][j];
            }
            cout << endl;
        }
} 

Since this is being done with inputs from the command line, they go as follows for the replace function:

./a.exe input1.txt replace (OLD LETTER NEEDING TO BE REPLACED) (NEW LETTER REPLACING)

For the dilation function:

./a.exe input1.txt dilate (SYMBOL IN FILE TO DILATE)

input1.txt is as follows:

.........
.........
.........
.........
....X....
.........
.........
.........
.........
Cris Luengo
  • 43,236
  • 6
  • 46
  • 92
  • For which function does it not print: `replace()` or `dialation()`? Also, you should check the `std::ifstream` if it fails or not... – Ruks Nov 10 '18 at 03:52
  • Unrelated: `while(fin)` is a better [variant of this](https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong), but still allows `ch = fin.get();` to fail undetected. – user4581301 Nov 10 '18 at 03:57
  • Print the matrix right before you call the function, to verify you are dealing with the correct data. Also you should be using the debugger -- all of the issues you mentioned can be easily solved by using the debugger. – PaulMcKenzie Nov 10 '18 at 03:59
  • @Ruks for dialationn() also, the input is from the command line using argv. –  Nov 10 '18 at 03:59
  • 2
    You should mention the command line arguments you are using. – PaulMcKenzie Nov 10 '18 at 04:00
  • 1
    The main difference between your two code samples is that the one which doesn't work uses command line argument, and the which which works doesn't use command line arguments. Check whatever arguments you are supplying to the program. – Peter Nov 10 '18 at 04:02
  • @xannax159 Have you checked the code using a debugger? – Ruks Nov 10 '18 at 04:02
  • @PaulMcKenzie im using sublime with a linux vm, it doesn't have a debugger. –  Nov 10 '18 at 04:04
  • @PaulMcKenzie commandline arguments added along with testing file –  Nov 10 '18 at 04:08
  • More than likely GDB will be installed on your system. [If not, there's onlineGDB](https://www.onlinegdb.com/) – user4581301 Nov 10 '18 at 04:09
  • 1
    Note: *input1.txt dialate (SYMBOLE IN FILE TO DIALATE)* looks a lot like 3 arguments, meaning `string argument4 (argv[4]);` goes out of bounds and all bets are off. – user4581301 Nov 10 '18 at 04:16
  • 1
    I added a dummy argument `input1.txt dialate X y` and the program behaves as I expect. – user4581301 Nov 10 '18 at 04:21
  • @user4581301 i use argument4 for the replace function. without it, how would i be able to differentiate from different needed user inputs. The requirement for the assignment is that it needs to be one command line to do the trick. I understand where you are coming from though, but argv[1] is the file name. argv[2] is the morph, and 3-4 are the parameters required for the functions called. –  Nov 10 '18 at 04:21
  • @user4581301 just saw your new test, so is it not possible to use argv like the way i intent? –  Nov 10 '18 at 04:22
  • 1
    @xannax159 Declare argument4 where you need it then... that is, inside the `if (argument2 == "replace")`... and it will be automatically discarded after use... Because assigning an empty argument to a string will break the program immediately... – Ruks Nov 10 '18 at 04:22
  • @Ruks that fixed it! Thank you all (i wish i could @ you all but it doesnt let me) –  Nov 10 '18 at 04:26

1 Answers1

0

Given input of input1.txt dialate X the program invokes undefined behaviour when asking for a fifth parameter with

string argument4 (argv[4]);

Solution:

argument4 is only used in the body of if (argument2 == "replace") so you should move the definition and initialization of argument4 into the body of the if.

I also strongly recommend testing argc ahead of time to ensure you have sufficient arguments. argc is the number of user-provided arguments plus 1 for the command used to run the program1. Don't count on the user to not make mistakes. Meat-sacks are known to be quite error-prone.

Your program needs to make sure argc is at least 3 before getting argument1 and argument2 and argument2 will tell you if you need an argc of 4 or 5 to continue.

1 Usually. argv[0] may be left blank since some systems, usually embedded systems, don't have a program name

user4581301
  • 29,019
  • 5
  • 26
  • 45