Skip to main content

The following C++ programming details will helpful in completing the initial homeworks for the course.

Command Line Arguments

Most of the programs we write will expect additional information from the user when the program is launched. We will do this by providing this data on the command line:

  ./my_program.exe blue 3.14159 my_input_data_file.txt my_output_data_file.txt

In order for your program to receive arguments from the command line, you will make use of the optional arguments to the main function. Here is the prototype:

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

The parameter argc contains the number of strings on the command line, including the executable name. For the example above, argc = 5. The array argv stores those C-style strings. You can access the executable name with argv[0] and the arguments with argv[1], argv[2], etc.

Important Note: To compare command line argument strings using the == operator, you must cast this data to a STL C++-style string:

  if (std::string(argv[1]) == std::string("blue")) {
     std::cout << "my favorite color is blue too!" << std::endl;
  }

Command Line Arguments in Visual Studio

You can also specify command line arguments when running the program inside of the Visual Studio development environment. Go to "Project" → "Properties" → "Configuration Properties" → "Debugging" and in "Command arguments" enter:

  blue 3.14159 my_input_data_file.txt my_output_data_file.txt

Note, that the default directory for files is the working directory.

Converting a C/C++ String to an Integer or Floating Point Value

This is done using the atoi (char-to-integer) and atof (char-to-float) functions. First, be sure to #include <cstdlib>. Then, to convert a C++-style STL std::string variable to an int:

  std::string my_stl_string = "17";
  int x = atoi(my_stl_string.c_str());

Alternatively, if you are compiling with C++11 (or greater) you can use a similar C++ version of this function:

  std::string my_stl_string = "17";
  int x = std::stoi(my_stl_string);

And to convert C-style char array (C-style string) to a float:

  char* my_char_string = argv[2];
  float y = atof(my_char_string);

Or similarly, std::stof.

Reading From & Writing To Files

The STL streams std::cin & std::cout are used to read data from and write data to the "console". Often, we would rather read data from a file and/or write the output to a file. We can do this using the STL file stream library:

  #include <fstream>

Here's an example fragment of code that attempts to open an input file stream for a file name specified on the command line above:

  std::ifstream in_str(argv[3]);

It is good coding practice to verify that the input stream was successfully opened:

  if (!in_str.good()) {
    std::cerr << "Can't open " << argv[3] << " to read.\n";
    exit(1);
  }

Likewise here's how to open a stream for output:

  std::ofstream out_str(argv[4]);
  if (!out_str.good()) {
    std::cerr << "Can't open " << argv[4] << " to write.\n";
    exit(1);
  }

Once the streams are created, you can use in_str & out_str just like you use std::cin & std::cout.

In general, for this course, we encourage you to use the stream operator>> for all input parsing, rather than using getline, eof, getc, etc. We will not deduct points for using the other methods of parsing, but we have designed the assignment input format specifications for easy parsing with >>.

Note that the following code has a bug. If the input file ends with one or more extra newlines, the inner loop will "do something" with the last successfully read element twice. It is important to check the return value of each >> expression to be sure the read was successful.

  while (!in_str.eof()) {
    in_str >> my_variable;
    // do something with my_variable
  }

A simpler and more robust way to write the same code is:

  while (in_str >> my_variable) {
    // do something with my_variable
  }

File Parsing Example with different data types

For example, if your input file contains family last name, number of children, and ages of the children:

  Smith   3   4.5   6.0   8.1
  Jones   1  13.6
  Lee     2   1.5   4.2

Here is code to read all of this data:

  std::string last_name;
  int num_children;
  std::vector<float> ages;
  float tmp;
  while (in_str >> last_name) {
    in_str >> num_children;
    // error checking to make sure num_children is not negative
    assert (num_children >= 0);				  
    // clear out ages data from the last family
    ages.clear();  
    for (int i = 0; i < num_children; i++) {
       in_str >> tmp;
       ages.push_back(tmp);
    }				  
    // Do something interesting with the last_name and ages variables!
  }

Note that we do not use getline or attempt to find a newline character, so we are not relying on the newlines or spaces or tabs being in specific places in the file. We only assume that data is consistent -- the number of children is non-negative and the number of floats matches the specified number of children. We could do more error checking on each >> operation to make sure each read did not fail, but most of the time in this course its ok to assume the input won't be terribly broken. If there is an error in the input, this code will get confused and break or crash. Robustly handling all broken input is beyond the scope of this course.

Comparing Two Text Files

To check the correctness of your program, you can compare your output text file to the provided sample output text file using the UNIX utility diff (available on Linux & WSL & MacOSX):

  diff my_output.txt sample_output.txt

Any lines in the two files that are not identical (including whitespace), will be printed to the console. WinDiff is another option for Windows users. Please see a TA or the instructor in office hours if you have a question about these programs.

Redirecting Input & Output

What if you have an interactive program that uses std::cin & std::cout to read from and write to the "console", but you'd like to take the input from a file and you'd rather not rewrite the program to use the input & output streams described above? This following trick is handy for repeated testing and debugging an interactive program (you'd rather not have to manually type in the same input test data many times). Asking the executable to read from a file instead of the console and/or write to a file instead of the console is called I/O redirection.

  • First, create the input.txt file that contains input which you would otherwise type at the console during program's execution.

  • Then on the Linux/WSL/MacOSX command prompt simply type:

       program.exe < input.txt > output.txt
    

  • When the program has finished, look in the newly created file output.txt.

You can do the same thing in Visual Studio. (See section on "Command Line Arguments in Visual Studio" above).