C++ for Mathematicians An Introduction for Students and Professionals phần 7 potx

52 538 0
C++ for Mathematicians An Introduction for Students and Professionals phần 7 potx

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

Chapter 14 Strings, Input/Output, and Visualization For the most part, mathematical work does not involve manipulation of character data. Nonetheless, it is useful to have a general understanding of how C++ handles character data, how to convert text to numbers, how to use command line arguments, and how to read and write data in files. We also show how to modify the formatting of output (e.g., how to increase the number of digits printed after the decimal point). We illustrate many of these ideas by creating a class to parse files one line at a time, and break those lines into individual words. C++ has two ways to handle character data: arrays of char values and in objects of type string. The char arrays are a legacy of C++’s roots in the C programming language. It is necessary to understand their basics, but their use should be avoided where possible. The newer string variables are easier to use. We begin with a brief introduction to char arrays. Textual and numerical output are important, but there are times when graphical output is especially insightful. We close this chapter with a discussion of how to draw pictures in C++. 14.1 Character arrays Character (or text) data consist either of individual characters (letters, numerals, punctuation) or of lists of characters. The C++ data type char holds a single char- acter from the Latin character set (26 lower- and uppercase letters, numerals, white space, punctuation). These are known as the ASCII characters and are the only char- acters with which this book deals. Computers can also deal with a richer set of glyphs (from accented Latin letters to Chinese characters) using a system called uni- code; this system is beyond our scope. An ordered list of characters is generally called a character string. For example, the words Hello Gauss are such a list comprising 11 characters. As mentioned, C++ has two principal ways to work with character strings: as null-terminated char arrays and as objects of the class string. The character array representation is a primitive scheme inherited from the language C. It is useful for writing messages to the screen and other simple chores. The moment one wishes to do any manipulation of characters (e.g., concatenate two strings), the C++ string class makes program- 289 290 C++ for Mathematicians ming much easier. We begin by discussing the basics of character arrays and then introduce the string class in the next section. In a statement such as cout<<"The answer is "<<x<<endl;, the characters enclosed in quotation marks form a character array. That is, the sequence of letters is a C++ object of type char * : an array whose elements are type char. In this book we have used character arrays exclusively for writing messages to the computer’s screen, but it is possible to hold such arrays in variables. For example: const char * word = "Hello"; This creates an array of characters named word. The individual characters can be accessed using the usual array notation. For example, word[0] is the first character of the array, that is, H. It is surprising to learn that the length 1 of the array word (as declared above) is six (even though Hello is a five-letter word). Character arrays in C++ are null terminated; this means that after the last character of the string, the numerical value 0 is appended to mark the end of the string. Figure 14.1 illustrates how the contents of the variable word are stored inside the computer’s memory. The array is held at some 72 101 108108 111 0 word H olle 20320 20321 20322 20323 20324 20325 Figure 14.1: Illustrating a null-terminated character array. location in memory (arbitrarily set at 20320 in the figure); the variable word holds that memory location. The elements of the array, word[0] through word[5], are stored as ASCII values. The letter H has ASCII value 72, hence that’s what is stored in word[0]. The subsequent values are 101, 108, 108, and 111 corresponding to the letters e, l, l, and o. Finally, word[5] contains the numerical value 0 (which does not correspond to any printable character) and this marks the end of the character array. There are procedures for processing character array data; here are a few examples. • strlen gives the length of the character string (not including the terminating 0). 1 The length of the character string is 5, but the length of the array that supports that string is 6. The C/C++ procedure strlen applied to the character array "Hello" returns the value 5. Strings, Input/Output, and Visualization 291 • strcpy and strncpy are used for copying one character array to another. • strcat and strncat are used to concatenate two character arrays; that is, if s1 is "Good" and s2 is "Morning", their concatenation is "GoodMorning". • strcmp and strncmp give a total ordering on the set of character arrays; this is useful for sorting a list of character strings or determining if two strings are equal. On some compilers, you may need the directive #include <cstring> in order to use these procedures. Using character arrays and their associated procedures is awkward and error prone. In nearly all cases, it is much simpler to use the C++ string class instead. So, rather than delve into the details of these procedures, we turn to the friendlier and more powerful string class. 14.2 The string class For any character processing tasks beyond the most basic, use C++’s string class. To use string objects, you might need the directive #include <string> (the header is optional with some compilers). The string class contains a large number of features; in this section we discuss those with the greatest utility in mathematical work. 14.2.1 Initialization Variables of type string can be declared in several ways; here are the most basic versions: • string s; declares s to be an empty character string. • string s("Hello"); declares s to be a character string containing the let- ters Hello. In lieu of "Hello" we can use any null-terminated character array, such as this: const char * word = "Gauss"; string s(word); Please note: It is not permissible to use a single char value as an argument to a string constructor. Thus, string s(’j’); is illegal. Instead, use string s("j");. Alternatively, the following is permissible. string s; s = ’j’; // this is OK 292 C++ for Mathematicians • string s(s2); initializes s with a copy of the string s2. • string s(s2,idx); initializes s with a copy of the portion of string s2 that starts at position idx. • string s(s2,idx,len); initializes s with a copy of the portion of string s2 that starts at position idx and runs for len characters. For example, string s("Mathematics"); string t(s,2,3); cout << t << endl; writes the word the on the computer’s screen. Note that the 0th character of s is M. • string s(reps, ch); where ch is a character and reps is a nonnegative integer. This initializes s with reps copies of the character ch. For example, string snore(10,’z’); cout << z << endl; writes zzzzzzzzzz on the screen. In addition to setting a string’s value when it is declared, we may modify its value using an assignment statement such as any of these: s = "Gauss"; s = ’g’; s = other; // other is another string object 14.2.2 Fundamental operations The most basic operation one can perform on string objects is concatenation; the result of concatenating strings s1 and s2 is a new string comprising the characters of s1 immediately followed by the characters in s2. Concatenation of strings in C++ is denoted by the addition operator, +. For example, consider this code: string s1("Hello "); string s2("Gauss"); cout << s1+s2 << endl; This prints Hello Gauss on the computer’s screen. The + operation can be used to combine strings with single characters or with character arrays. Here are some examples. string s("Hello"); cout << s + " Gauss" << endl; // writes "Hello Gauss" string s1 = "good"; string s2 = "luck"; cout << s1 + ’ ’ + s2 << endl; // writes "good luck" One string can be appended to the end of another using the += operation: Strings, Input/Output, and Visualization 293 string s("Carl Friedrich"); s += ’ ’; // append a space s += "Gauss"; // append the last name cout << s << endl; writes Carl Friedrich Gauss on the screen. Characters may be inserted into the middle of a string using the insert method. The statement s.insert(pos,t); inserts the string t into s just before character s[pos]. The statement s.insert(0,t); inserts the characters at the beginning of s. Here is an example. string s("CarlGauss"); s.insert(4," Friedrich "); cout << s << endl; writes Carl Friedrich Gauss on the screen. In the statement s.insert(pos,t); the variable t may be either a string or a character array. It may not be type char. s.insert(3,"x"); // allowed s.insert(3,’x’); // forbidden The erase method is used for deleting characters from a string. The statement s.erase(pos); deletes all characters from position pos to the end of the string. For example, string s = "abcdefghijklmnopqrstuvwxyz"; s.erase(5); cout << s << endl; writes abcde to the screen. (Remember, for the original string, s[5] is f.) The statement s.erase(pos,nchars); deletes nchars of s starting at s[pos]. For example, string s = "abcdefghijklmnopqrstuvwxyz"; s.erase(5,3); cout << s << endl; writes abcdeijklmnopqrstuvwxyz to the screen. A portion of a string can be modified using the replace method. The statement s.replace(pos,nchars,new_chars); deletes nchars starting at position pos, and then inserts new_chars in place of the missing portion. The new_chars may be either a string or a char * character array, and may be of any length. Here is an example: string s = "abcdefghijklmnopqrstuvwxyz"; s.replace(5,16," "); cout << s << endl; This writes abcde vwxyz to the screen. 294 C++ for Mathematicians The substr method is used to extract a substring of a string; it does not mod- ify the string. The expression s.substr(pos) returns the substring of s starting with character s[pos] through to the end of s. More generally, the expression s.substr(pos,nchars) returns the substring of s starting with s[pos] up to, but not including, s[pos+nchars] . Here is an example. string s = "abcdefghijklmnopqrstuvwxyz"; cout << s.substr(5,3) << endl; This writes fgh to the screen. The length of a string can be ascertained using either s.size() or s.length(). One can test if the string is an empty string with s.empty() which returns true if the length of s is zero. Square brackets can be used to access a given character in a string (either for reading or for modification). In consonance with C++ principles, s[0] is the first character of s. This code string s = "good luck"; s[2] = ’l’; cout << s << endl; writes gold luck on the screen. The value between the square brackets must be nonnegative and less than the length of the string. Alternatively, the at method may be used: s.at(k) gives character number k of the string s (i.e., s[k]). Two string objects may be compared using the standard C++ comparison oper- ations: == , !=, <, <=, >, and >=. The ordering is mostly lexicographic. However, all uppercase letters precede lowercase letters. The following program illustrates the ordering of string values; note that sort implicitly relies on the < operator. Program 14.1: A program to illustrate the sorting of string values. 1 #include <iostream> 2 using namespace std; 3 4 const int NWORDS = 7; 5 6 int main() { 7 string words[NWORDS]; 8 words[0] = " zebra"; 9 words[1] = "ant eater"; 10 words[2] = "Aaron"; 11 words[3] = "aardvark"; 12 words[4] = "Baltimore"; 13 words[5] = "anteater"; 14 words[6] = "BREAKFAST"; 15 16 sort(words, words+NWORDS); 17 18 for (int k=0; k<NWORDS; k++) { 19 cout << words[k] << endl; 20 } Strings, Input/Output, and Visualization 295 21 22 return 0; 23 } Here is the output of this program. ✞ ☎ zebra Aaron BREAKFAST Baltimore aardvark ant eater anteater ✝ ✆ In a dictionary, aardvark precedes Aaron, but C++ sorts these the other way around because uppercase A comes before all lowercase letters. The space character pre- cedes all letters, hence zebra is first in the sorted output. 14.2.3 Searching The string class provides methods for searching for substrings. The most basic of these is find. The method is invoked with an expression such as s.find(pat) where s is a string and pat is a string or a char * . It returns the location of the first occurrence of pat in s. The following code prints the number 8 on the screen. string s = "abcdefghijklmnopqrstuvwxyz"; cout << s.find("ijk") << endl; What happens if find cannot find pat? The answer is complicated. To begin, we need to explain that find returns a value of type std::string::size_type. (If you include the statement using namespace std; then you may drop the prefix std::.) In most cases, we save the value returned by find in a variable for further processing. To do this, we use code such as this: string s = "I feel like a louse"; string pat = "eel"; string::size_type idx; // or std::string::size_type idx; idx = s.find(pat); In this case, idx is set equal to 3. If, however, pat is set to "house", then find returns a special value named std::string::npos. (The prefix std:: may be omitted if we have the state- ment using namespace std;.) Here is a short program that illustrates how to use find. #include <iostream> using namespace std; int main() { string s = "Mississippi"; string pat; cout << "Enter substring > "; cin >> pat; 296 C++ for Mathematicians string::size_type idx; // or std::string::size_type idx; idx = s.find(pat); if (idx != string::npos) { cout << "The substring \"" << pat << "\" was found at position " << idx << endl; } else { cout << "The substring \"" << pat << "\" was not found" << endl; } return 0; } Here are two runs of the program. ✞ ☎ Enter substring > ssi The substring "ssi" was found at position 2 ✝ ✆ ✞ ☎ Enter substring > sse The substring "sse" was not found ✝ ✆ Closely related to find is the rfind method. The statement s.rfind(pat) returns the index of the last occurrence of pat in s, or string::npos if pat cannot be found. Two additional string searching methods are provided: find_first_of and find_last_of. The expression s.find_first_of(pat) searches the string s for a character that is found in pat and returns its index. If none of the characters in pat is present in s, then string::npos is returned. Here is a program to illustrate how this works. #include <iostream> using namespace std; int main() { string s = "Mississippi"; string pat; cout << "Enter substring > "; cin >> pat; string::size_type idx; // or std::string::size_type idx; idx = s.find_first_of(pat); if (idx != string::npos) { cout << "One of the characters \"" << pat << "\" was found at position " << idx << endl; } else { cout << "None of the characters\"" << pat << "\" was found" << endl; } return 0; } Strings, Input/Output, and Visualization 297 Here are two executions of this code. ✞ ☎ Enter substring > aeiouy One of the characters "aeiouy" was found at position 1 ✝ ✆ ✞ ☎ Enter substring > wxyz None of the characters"wxyz" was found ✝ ✆ The expression s.find_last_of(pat) method gives the index of the last char- acter in s that is also in pat, or string::npos if no such character exists. 14.2.4 Converting between string and char * types Conversion from a null-terminated character array (type char * ) to a string is easy. If word is a char * (character array) and s is a string, the assignment s = word; does the job. Alternatively, we can convert word to a string when s is declared: string s(word); Finally, we can write string(word) to convert word into a string. The conversion from a string to a char * is more complicated. The string class includes a method called c_str for this purpose. The expression s.c_str() returns a pointer to an unmodifiable, null-terminated character array with the same contents as s. string s = "Leonhard Euler"; const char * word = s.c_str(); cout << word << endl; Notice that word is declared const; omitting this keyword results in an error. If you need to do further processing on the character array returned by c_str, you need to copy the characters into another char * array and work on that copy. Fortunately, one rarely needs to convert a string to a char * . The exception is when we wish to use a procedure that takes a char * argument, but no string alternative is available. (For an example, see Exercise 14.1.) 14.3 Command line arguments In all the programs we have presented thus far, data are entered into the program using a prompt/response paradigm: cout << "Enter n > "; cin >> n; An alternative mechanism for sending a few values to a program is to use com- mand line arguments. For example, a greatest common divisor program, named gcd, 298 C++ for Mathematicians would be invoked from the terminal by typing gcd 289 51. The arguments are sent to main as character arrays, "289" and "51". The main procedure then needs to convert these to integers, send those values to a gcd procedure, and print the result. Here is how all of this is accomplished. The first step is to declare main in a different manner. Thus far in this book, main has been always declared as int main(). In this version, no arguments are sent to main and an integer value is to be returned. The alternative declaration for main specifies arguments: int main(int argc, char ** argv) { } The first argument is an int value that specifies the number of arguments typed on the command line. The name of the program itself is considered an argument, so this number is always at least one. The name of this argument is not required to be argc (for “argument count”) but this convention is nearly universal, so you are encouraged to follow suit. The second argument, named argv , is an array of character arrays (hence the double star). This need not be named argv, but this name is also nearly universally used for this purpose. When main is invoked, this array is populated as follows: the character array in argv[0] is the name of the program. The arrays argv[1] through argv[argc-1] are the other arguments on the command line. An example makes this clear. Program 14.2: A program that illustrates how to access command line arguments in a main. 1 #include <iostream> 2 using namespace std; 3 4 int main(int argc, char ** argv) { 5 for (int k=0; k<argc; k++) { 6 cout << "argv[" << k << "] is " << argv[k] << endl; 7 } 8 return 0; 9 } Suppose this program is compiled and the executable is called test-main. If the program is run with the command line ./test-main one two 3 negative-four the following output results. ✞ ☎ argv[0] is ./test-main argv[1] is one argv[2] is two argv[3] is 3 argv[4] is negative-four ✝ ✆ Note that in this case, argc equals 5 accounting for the name of the program and the four additional arguments passed to the program. [...]... Plotter and perform other initialization including establishing a coordinate system and pen attributes, • Draw the image, and • Close the Plotter Finally, we need to compile and run the program 318 C++ for Mathematicians Choosing the appropriate plotter type The plotutils package is capable of producing various types of graphics files including gif, eps, and several others Fortunately, the methods for. .. objects, translating between mathematical coordinates and screen coordinates, printing, and so forth Still, visualization is too important to dismiss and so we offer guidance on how to use C++ to draw pictures in a platform-independent manner One strategy, which we consider only briefly, is to write a C++ program whose textual output is used as input to another system with built-in graphics capabilities For. .. characters (of the sort that can be held in a char variable); that is, lower- and uppercase Latin letters, numerals, punctuation, and blank space They do not contain letters from other character sets (e.g., Chinese) or other types of data Examples of plain text files are cc and h files for programming, TEX A and LTEX files, PostScript documents, and html Web pages Binary files, on the other hand, contain characters... video), PDF documents, and executable programs (built from your C++ code) We focus our attention solely on reading and writing plain text files Although C++ is capable of dealing with binary files, it is more complicated to handle such data For special situations, you may be able to find publicly available C++ procedures for reading and writing specific types of data (e.g., jpg files) To read and write from files,... parsing files In applied work, mathematicians often are given files containing data It can be an annoying chore simply to read the file into a program For example, a file might contain geometric information about a large molecule The input file specifies the molecule with various kinds of lines: ¥ 312 C++ for Mathematicians • Type and location of atoms: These lines have the following format: ATOM atom number... n2 to find the gcd of n1 and n2 $ /gcd hello Gauss 0 $ ¥ ¦ Notes: The dollar sign is the computer’s shell prompt (not something the user types and not considered a command line argument) The first invocation of the program is properly formatted and the result is typed on the screen The second invocation has an incorrect number of command line arguments; the program detects this and prints the error message... ¥ 316 C++ for Mathematicians 14.8.1 Introducing and installing the plotutils package Let’s start with an assumption We do not want to learn how graphics files (such as GIF, JPG, or EPS) work; we just want to think about drawing in mathematical terms Line segments should be specified by their end points and circles by their centers and radii Someone else should work out how these various graphics formats... creates them for you These subdirectories are named bin, lib, include, and so on The option enable-libpotter enables the C++ version of plotutils (Without this option, only the C version is built.) 5 The word tar is an acronym for tape archive; this file format provides a mechanism for packaging many files together and need not be associated with storing data on a tape Strings, Input/Output, and Visualization... fail and good If (and only if) the stream is in a good state, then good() returns true and fail() returns false Thus, if the file cannot be opened, my_in.fail() returns true It is important to do a test such as this or else the rest of your program may run into trouble A program also uses the good and fail methods to detect when an input file has been exhausted; see Section 14.4.3 302 C++ for Mathematicians. .. P.fircle(0.,0.,sqrt(2.)); (There is an analogous circle method that takes integer-valued arguments.) There are many other drawing methods in the plotutils package for creating rectangles, ellipses, circular and elliptical arcs, and Bezier curves These can be combined into compound paths (e.g., polygons) which, if closed, can contain a fill color One can also write text (in a variety of fonts) and plot individual points . >> n; An alternative mechanism for sending a few values to a program is to use com- mand line arguments. For example, a greatest common divisor program, named gcd, 298 C++ for Mathematicians would. Input/Output, and Visualization For the most part, mathematical work does not involve manipulation of character data. Nonetheless, it is useful to have a general understanding of how C++ handles character. another program) instead. Strings, Input/Output, and Visualization 301 Fortunately, it is not difficult to declare input and output streams. These are objects like cin and cout, but rather than

Ngày đăng: 12/08/2014, 12:20

Từ khóa liên quan

Tài liệu cùng người dùng

Tài liệu liên quan