Command Line Calculator - Save Results in a Text File

Hello! For a project, I am supposed to create a program that allows you to make simple calculations from the command prompt. It is mostly finished, but I am having trouble trying to output the text to a file. Basically, this program should give the user the option of writing the text to a new file if they add "--o" at the end of the line they type in the command prompt. For example, "5 + 2 --o [filename]" would perform the calculation and then save the result in a file rather than just display it. If you run the program and add on "--help" at the end, it will give you more information on how it works, and it includes the usage of the --o command.

Edit: I think I could also be misunderstanding the way it works. From the project guidelines:
--o [file] Save the operation and output to a text file.

Sadly, there was no example given.

Here is the code that I have now - I apologize if it's a little messy now. I will work on making it look a bit nicer later on.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cmath>
using namespace std;

void calcFactorial(int num1);
void calcFibonacci(int num1);
void addNum(int num1, int num2);
void subtractNum(int num1, int num2);
void multiplyNum(int num1, int num2);
void divideNum(int num1, int num2);
void calcMod(int num1, int num2);
void calcExponent(int num1, int num2);

int main(int argc, char ** argv)
{
    if(strcmp(argv[1], "--help") == 0)
    {
        cout << "Usage: calc <X> <operator> [Y] [options] " << endl;
        cout << endl;
        cout << "Unary Operators: " << endl;
        cout << "  !         Computes the factorial of the given operand." << endl;
        cout << "  F         Displays the first X numbers of the Fibonacci sequence. " << endl;
        cout << endl;
        cout << "Binary Operators: " << endl;
        cout << "  +         Adds any two numbers." << endl;
        cout << "  -         Subtracts any two numbers." << endl;
        cout << "  *         Multiplies any two numbers." << endl;
        cout << "  /         Divides any two numbers." << endl;
        cout << "  %         Computes the modulus of any two integers." << endl;
        cout << "  P         Raises the first integer to the power of the second integer." << endl; 
        cout << endl;
        cout << "Options: " << endl;
        cout << "  --help    Display this information." << endl;
        cout << "  --o [file]      Save the operation and output to a text file." << endl;           
    }
    
    else
    {
        int num1 = atoi(argv[1]);
	int num2 = atoi(argv[3]);
	char opr = argv[2][0];

    	switch(opr)
    	{
    		case '!':
    			calcFactorial(num1);
    			break;
    		case 'F':
    			calcFibonacci(num1);
    			break;
    		case '+':
    			addNum(num1, num2);
    			break;
    		case '-':
    			subtractNum(num1, num2);
    			break;
    		case '*':
    			multiplyNum(num1, num2);
    			break;
    		case '/':
    			divideNum(num1, num2);
    			break;
    		case '%':
    			calcMod(num1, num2);
    			break;
    		case 'P':
    			calcExponent(num1, num2);
    			break;
    	}
    }
	return 0;
}

/********************************************************
* Name: calcFactorial
* Description: Calculates the factorial of a number that
* was entered. For example 5 ! -> 120
* Input: int num1
********************************************************/
void calcFactorial(int num1)
{
	int factorial = 1;

	for(int i = 1; i <= num1; i++ )
		factorial *= i;

	cout << factorial << endl;
}

/********************************************************
* Name: calcFibonacci
* Description: Displays the Fibonacci Sequence up to
* the nth number. For example, 5 F -> 1 1 2 3 5
* Input: int num1
********************************************************/
void calcFibonacci(int num1)
{
	int first = 1;
	int second = 1;
	int next = 0;

	cout << "The first " << num1 << " Fibonacci numbers are: ";
	for(int i = 0; i < num1; i++)
	{
		cout << " " << first;
		next = first + second;
		first = second;
		second = next;
	}

	cout << " " << endl;
}

/********************************************************
* Name: addNum
* Description: Finds the sum of two numbers
* Input: int num1, int num2
********************************************************/
void addNum(int num1, int num2)
{
	int sum = num1 + num2;
	cout  << sum << endl;
}

/********************************************************
* Name: subtractNum
* Description: Finds the difference of two numbers
* Input: int num1, int num2
********************************************************/
void subtractNum(int num1, int num2)
{
	int sum = num1 - num2;
	cout << sum << endl;
}

/********************************************************
* Name: multiplyNum
* Description: Finds the product of two numbers
* Input: int num1, int num2
********************************************************/
void multiplyNum(int num1, int num2)
{
	int sum = num1 * num2;
	cout << sum << endl;
}

/********************************************************
* Name: divideNum
* Description: Finds the quotient of two numbers
* Input: int num1, int num2
********************************************************/
void divideNum(int num1, int num2)
{
	float sum = float(num1) / num2;
	cout << sum << endl;
}

/********************************************************
* Name: calcMod
* Description: Uses the modulus operator on two numbers
* Input: int num1, int num2
********************************************************/
void calcMod(int num1, int num2)
{
	int sum = num1 % num2;
	cout << sum << endl;
}

/********************************************************
* Name: calcExponent
* Description: Raises num1 to the power of num2
* Input: int num1, int num2
********************************************************/
void calcExponent(int num1, int num2)
{
	double sum = pow(num1, num2);
	cout << sum << endl;
}
Last edited on
Hello Avex,

Looking over your program here are some small tips that may help:

The if statement the displays the help information can just as easily be written as:
1
2
3
4
5
6
cout
	<< "Usage: calc <X> <operator> [Y] [options] \n\n"
	<< "Unary Operators: \n"
	<< "  !         Computes the factorial of the given operand.\n"
	<< "  F         Displays the first X numbers of the Fibonacci sequence. \n\n"
        // rest of output. 

You do not need all those "std::endl"s the "\n"s will do. Also you do not need all the "std::cout" for each line. It can all be chained together. Leave the "std::endl" for the end of the last line. The "\n" tends to clear the output buffer in most cases, so you do not need all the overhead associated with the "std::endl".

Next I would put that code in a function because there may be one ot two other places that you could call it from.

In your switch/case for cases "F" and "P" it would help to write the case statements as:
1
2
3
4
5
6
7
8
9
10
switch (opr)
{
	case 'f':
	case 'F':
		break;

	default:
		std::cout << "Usage: calc <X> <operator> [Y] [--o] [file name] " << endl;
		return 1;
}

This way it will not matter if someone would use a lowercase letter or an upper case letter the case statements will catch either and just fall through until it finds a "break" statement.

The "default" is helpful if someone mistypes an operator. Here you could use the "std::cout" statement as I did or call the "help" function to display the instructions. The "return 1;" means that you left the program with a problem. Since (0) zero means that there was no problem any number greater than (0) zero means there is a problem and later you can use that number to help track down where the problem came from.

Now for the bigger problem:
1
2
3
4
5
6
7
else
{
	int num1 = atoi(argv[1]);
	int num2 = atoi(argv[3]);
	char opr = argv[2][0];

        switch (opr)

Line 3 works as long as it is a number that can be converted.
line 5 works to get your operator.
Line 4 does not work. One possibility is the "arg[3]" could be outside the bounds of the array and you would be accessing unknown memory which may or may not be convertible to a number. This will produce a run time error and stop the program. I doubt that you are up to "try/catch" yet, but this is one time where I use it to keep the program from crashing and deal with the problem in the program.

A suggestion would be to keep line 5 before the switch and in the for cases "!" and "F" you know that you will have only "arg[1]" to convert to a number and for the other cases you will have "argv[1]" and "argv3[3]" to convert to numbers.

You collect "argc" when the program starts, but never make use of it and it can be very helpful. At the minimum "argc" could be 3, (program name num opoerator) to a maximum of 6 (program name num operator [num] [switch(--o)] [file name]) or something in between. "argc" can be used to determine how much information there is to collect and use.

In order to write to a file you will need to include the header file "<fstream>" and create a function like "writeToFile()" in order to make use of the switch (--o). Then you will need to decide what variables to send to the function and what to write to the file. Also you will need to decide if the file should be overwritten each time it is opened or appended to.

If your opening lines are your interpretation of the specs, (guidelines, directions0, that is a start, but it is better to post what you were actually given as someone else may see something that you do not.

Here is the code that I have now - I apologize if it's a little messy now. I will work on making it look a bit nicer later on.
The time to clean up the code is when you write it and not so much after it is done. Clean code is much easier to read and it helps others who have to read it because they do not have to spend as much time trying to figure it out.

Remember that the compiler does not care about white space, blank lines or comments when it compiles the code. The person reading the code does. It looks like you are doing a good job with your comments before the functions.

In a little while I will load up the program and see if there is anything else I can find.

One last note:
1
2
//using namespace std;  // <--- Best not to use.
// A recent post that is worth reading. http://www.cplusplus.com/forum/beginner/258335/ 


Hope that helps,

Andy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int calcFactorial(int num1);
int calcFibonacci(int num1);
int addNum(int num1, int num2);
int subtractNum(int num1, int num2);
int multiplyNum(int num1, int num2);
int divideNum(int num1, int num2);
int calcMod(int num1, int num2);
int calcExponent(int num1, int num2);

int result;
switch(operation){
case '+':
	result = addNum(num1, num2);
	break;
//...
}

if (output_to_file)
	output << result << '\n';
else
	cout << result << '\n';

Thank you both for the help! I'm currently working on the program, and I'll let you know if I get it working properly.
Hello Avex,

Short of rewriting your code and using most of what you have I have come up with this for an idea:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
void calcFactorial(int num1);
void calcFibonacci(int num1);
void addNum(int num1, int num2);
void subtractNum(int num1, int num2);
void multiplyNum(int num1, int num2);
void divideNum(double num1, double num2);
void calcMod(int num1, int num2);
void calcExponent(int num1, int num2);
void helpText();
void writeToFile(char* fileName);

int main(int argc, char ** argv)
{
	const size_t MAXSIZE{ 20 };

	bool createOutput{ false };
	char fileName[MAXSIZE]{};

	if (strcmp(argv[1], "--help") == 0)
	{
		helpText();
	}

	else if (argc == 5 && strcmp(argv[3], "--o") == 0)
	{
		strcpy(fileName, argv[4]);
		createOutput = true;
	}
	
	else if (argc == 6 && strcmp(argv[4], "--o") == 0)
	{
		strcpy(fileName, argv[5]);
		createOutput = true;
	}

	if (argc > 2 && argc < 7)
	{
		char opr = argv[2][0];

		switch (opr)
		{
			case '!':
			{
				int num1 = atoi(argv[1]);
				calcFactorial(num1);
			}
			break;
			case 'f':
			case 'F':
			{
				int num1 = atoi(argv[1]);
				calcFibonacci(num1);
			}
			break;
			case '+':
			{
				int num1 = atoi(argv[1]);
				int num2 = atoi(argv[3]);
				addNum(num1, num2);
			}
			break;

	                // Other case statements.

			default:
				std::cout << "Usage: calc <X> <operator> [Y] [--o] [file name] " << endl;
				// Or helpText();
				return 1;
		}  // End switch
	}  //  End if

	//if (createOutput)
	if (strlen(fileName) > 0)
		 writeToFile(fileName);


For the "add" function I changed it to:
1
2
3
4
5
6
void addNum(int num1, int num2)
{
	int sum = num1 + num2;
	cout << "\n The sum of " << num1 << " + " << num2 << " = " << sum << endl;
	//std::cout << "\n The sum of " << num1 << " + " << num2 << " = " << num1 + num2 << std::endl; // <--- An alternative.
}

I feel the additions to the "cout" statement are better then just displaying a single number. If you like this the rest of the functions can be changed in the same manner.

I changed the "divideNum" function to:
1
2
3
4
5
void divideNum(double num1, double num2)
{
	double sum = num1 / num2;
	cout << sum << endl;
}

By defining "num1" and "num2" as "double"s in the parameters you do not need the type cast in the calculation.

One thing this function does not do is to check that "num2" is not (0) zero otherwise you will get a run time error "divide by (0) zero" and your program would crash. You could check if "num2" is (0) zero and if so allow the user to enter a new number before the calculation.

The only part left is to write the function "writeToFile()" and decide what you need to write to this file.

Hope that helps,

Andy
Thanks again! I really appreciate the help.
Topic archived. No new replies allowed.