ECS 110: Data Structures and Programming Discussion Section Notes -- Week 2 Ted Krovetz (tdkrovetz@ucdavis.edu) More C++ -------- 1. TWO WAYS TO GET COMMAND LINE ARGUMENTS In the current assignment, you must get some information from the command line. The way both C and C++ pass this information to the main program is the same. The parameters argc and argv contain the number of terms in the command and an array of char*, respectively. Argv[0] is guaranteed to be the name of your program and argv[argc] is guaranteed to be NULL. Argv[1]..argv[argc-1] are each term the user typed into the command interpreter after the program's name. Thus, the command line prog1 7.5 -d would fill argc and argv as follows: argc = 3 argv[0] = "prog1" argv[1] = "7.5" argv[2] = "-d" argv[3] = NULL Notice that argv[1] is a string of characters and that we need to convert it to a floating point type to be useful in our program. Here are two examples of getting the command line and converting the command strings into useful types. Our first example relies on the C libraries. It is really an example of mixing C library functions with C++ code. This type of mixing is often necessary because there often is no equivalent function in C++. #include #include #ifndef FALSE enum {FALSE, TRUE}; #endif int verbose; double mai; // mean_arrival_interval int main(int argc, char* argv[]) { if ((argc != 2) && (argc != 3)) { cerr << "Usage: " << argv[0] << " mean_arrival_interval [-d]" << endl; return(1); } mai = atof(argv[1]); verbose = (argc == 3); cout << "Verbose = " << (verbose ? "TRUE" : "FALSE") << endl; cout << "MAI = " << mai << endl; return 0; } Our second example doesn't change very much, but the change that we make eliminates the need for the C libraries. Instead, we include a new C++ system header called which allows you to define a custom I/O stream initialized by a string. Because C++'s I/O streams have powerful type conversions built-in, we can easily use the stream to convert our string into a floating-point number. [Note: this level of C++ knowledge is not part of the class. It is only given here to demonstrate C++'s power and flexibility.] #include #include // String Streams #ifndef FALSE enum {FALSE, TRUE}; #endif int verbose; double mai; // mean_arrival_interval int main(int argc, char* argv[]) { if ((argc != 2) && (argc != 3)) { cerr << "Usage: " << argv[0] << " mean_arrival_interval [-d]" << endl; return(1); } istrstream ist(argv[1]); ist >> mai; verbose = (argc == 3); cout << "Verbose = " << (verbose ? "TRUE" : "FALSE") << endl; cout << "MAI = " << mai << endl; return 0; } 2. PROGRAMMING STYLE Part of programming is typing the program into a text editor. The conventions you use when indenting; placing spaces, brackets and parentheses; and capitalizing identifiers is often called your programming style. The most important thing about programming style is consistency. However, another important aspect to consider is readability. If you program in such a way that identifiers are easy to find and categorize, then future maintenance of your program, by you or somebody else, will be much easier. Copying others style is often a good place to start. But, even copying others leaves you with many decisions. If you follow Stroustrup's example, you will capitalize almost nothing but the first character of class names. On the other hand, the Horowitz book seems to capitalize the first character of every globally defined identifier (types, classes, functions, etc.) Adopting conventions for naming your variables, constants and classes can be helpful, too. I prefix all my global variables with a 'g', my constants with a 'k' and my classes with a 'C'. For example, const int kMaxLength = 255; // constant int gCurLength; // global variable class CPriorityQueue { }; You should do whatever is most comfortable for yourself, but do think about it and strive to be clear and consistent. 3. ANOTHER STACK We did not have enough time last week to go over our stack example, so lets improve it somewhat and go over it this week. In keeping with the notion of abstraction, let's get rid of the type of element we are storing on our stack and replace it with a more generic "Element" type. Also, housing our stack elements in an array is a bit too restrictive. This time we shall use a linked list. #include typedef int elem_type; class Stack { public: Stack(); ~Stack(); void Push(elem_type); void Pop(); elem_type Top(); elem_type Empty(); friend ostream& operator<< (ostream& os, Stack& s); private: struct node_type { elem_type elem; node_type* prev; }; node_type* top; }; Stack::Stack() { top = NULL; } Stack::~Stack() { while ( ! Empty()) Pop(); } void Stack::Push(elem_type new_value) { node_type* temp = new node_type; temp->prev = top; temp->elem = new_value; top = temp; } void Stack::Pop() { if ( ! Empty()) { node_type* temp = top->prev; delete top; top = temp; } } elem_type Stack::Top() { return (top->elem); } elem_type Stack::Empty() { return (top == NULL); } ostream& operator<< (ostream& os, Stack& s) { if (s.Empty()) os << "The stack is empty"; else { Stack::node_type* temp = s.top; while (temp != NULL) { os << temp->elem << " "; temp = temp->prev; } } os << endl; return os; } int main() { Stack s; int num; cout << "How many would you like to push? "; cin >> num; for (int i = 1; i <= num; i++) { s.Push(i); cout << s; } while ( ! s.Empty()) { cout << "The top of the stack is " << s.Top() << endl; s.Pop(); } cout << s; return 0; } 4. IMPORTANT NOTES ABOUT OUR STACK EXAMPLE 4.1 ADT Means Separation of Interface and Implementation If you compare this example with last week's, you'll notice that the public part of our Stack implementation has not changed. This is an important result of designing our stack as an abstract data type. If you had used my previous stack example in a program somewhere, you would be able to substitute the new one without any notice whatsoever. 4.2 Constructors/Destructors Last week, I do not think I emphasized enough how important the use of constructors and destructors are in C++. They allow you design your ADT so that upon creation and deletion, your objects are in a known state. This is very useful for reducing errors, and also makes the use of your types more seamless. 5. QUESTIONS AND ANSWERS If any time remains, I'll answer questions regarding C++ and the current assignment.