Advanced C/C++ Programming - String, Array
←
→
Page content transcription
If your browser does not render page correctly, please read the page content below
Advanced C/C++ Programming String, Array
Goal of this lecture ▪ Get to know the string library and built-in arrays Dr. Juan J. Durillo
Namespaces ▪ Large problems tend to use independently developed libraries, which tend to define a large number of global names, such classes, functions or templates ▪ When using libraries from many different vendors is almost inevitable that some names will clash ▪ To avoid this, some programmers use very long names for classes, function, variables or any global entity that they define ▪ This solution makes code more complicate ▪ In C++, namespaces provide a much more controlling mechanism to avoid name collision Dr. Juan J. Durillo
Note In contrast with class declarations, Namespaces namespace declarations do not finish with a semilcolon ▪ A namespace definition begin with the keyword namespace followed by the namespace name ▪ Each name within a namespace must refer to a unique entity within that namespace Note Namespaces are scopes ▪ Different namespaces may have members with the same name ▪ Names within a namespace can be directly accessed by other members of the namespace, including nested scopes within these members ▪ Names outside namespace must must indicated the namespace where a name is located Dr. Juan J. Durillo
Namespaces ▪ Namespaces can be discontinuous ▪ A namespace declaration either declares a new namespace if no namespace exist or adds to an existing namespace Dr. Juan J. Durillo
Namespace using Declarations ▪ When working with libraries and namespaces, there are two alternatives to indicate that we want a name of a given namespace ▪ Using the complete name (including the namespace and the scope operator ::) ▪ std::cin, every time we want to refer to the cin name include in the standard (std) library ▪ With using declarations Note Header files should not include using ▪ using std::cin; declarations. The reason is that the code of the header is copied into the including ▪ once included a using declaration, the name (cin) is accessible directly program’s text. If a header has a using ▪ Each using declaration includes a single namespace member declaration, then every program that includes that header gets that using declaration. As a result, a program that using std::cout; using std::endl; didn’t intend to use the specific library name might encounter unexpected name conflicts Dr. Juan J. Durillo
Library string type Dr. Juan J. Durillo
C++ strings ▪ A string is a variable-length sequence of characters ▪ The string type is defined in the string header and it is defined in the standard (std) namespace ▪ Therefore, to work with string we need to #include using std::string; Ways to initialize a string string s1 Default initialization; s1 is the empty string string s2(s1) s2 is a copy of s1 string s2 = s1 Equivalent to s2(s1), s2 is a copy of s1 string s3(“value”) s3 is a copy of the string literal, not including the null string s3 = “value” Equivalent to s3(‘”value”), s3 is a copy of the string literal string s4(n,’c’) Initialize s4 with n copies of the character ‘c’
Performing operations with strings ▪ Reading and writing strings is possible by using the same IO operators defined in the iostream library to read built-in types string s; //empty string cin >> s; //read a whitespace-separate string cout
Performing operations with strings Note the operator >> reads and discards leading whitespace (spaces, newlines, tabs). It then reads the characters until the next ▪ How to read an unknown number of words/strings whitespace character is encountered Note string word; the condition of this program tests the while (cin >> word) stream after the read completes. If the cout
Performing operations with strings ▪ The empty() function returns a bool indicating whether a given string is or not empty. It is a member function of string // program to discard empty lines while (getline(cin,line)) if (!line.empty()) cout
Performing operations with strings ▪ When comparing strings, == compares whether two strings contains the same characters ▪ It is case sensitive ▪ Additionally we can compare whether a string is smaller or bigger than other using the following operators: 1. If two strings have different lengths and if every character in the shorter string is equal to the corresponding character of the longer string, then the shorter string is less than the longer one 2. If any characters at the corresponding positions in the two strings differ, then the result of the string comparison is the result of comparing the first character at which the strings differ string str = “Hello”; Note By rule 1, we see that str is less than phrase string phrase = “Hello World”; By rule 2, we see that slang is greater than string slang = “Hiya”; both str and phrase Dr. Juan J. Durillo
Performing operations with strings ▪ Most of the library types support assignment ▪ The string type is not an exception so we can assign a string object to another string st1(10,’c’), st2; // st1 is cccccccccc, st2 empty st1 = st2; // replace the contents of st1 with a copy of st2 // both st1 and st2 are now the empty string ▪ Adding two strings yields a new string that is the concatenation of the left-hand followed by the right-hand operand ▪ The string library let us to convert both character literals and character string literals to objects of the string class ▪ When mixing strings objects with string literals at lest one operand should be a string when using the concatenation operator + Dr. Juan J. Durillo
Dealing with characters in a string. Case 1: processing every character in a string ▪ By far the best approach is to use a range for statement available since C++11 for (declaration : expression) statement ▪ When dealing with a string object, a string represents a sequence of characters, so we can use it in a range for string str(“some string”) for (auto c : str) cout
Functions to deal with characters in the cctype library Ways to initialize a string isalnum(c) true is c is a letter or a digit isalpha(c) true if c is a letter iscntrl(c) true if c is a control character isdigit(c) true if c is a digit isgraph(c) true if c is not a space but is printable islower(c) true if c is a lowercase letter isprint(c) true if c is a printable character ispunct(c) true if c is a punctuation character isspace(c) true if c is whitespace isupper(c) true if c is an uppercase letter isxdigit(c) true if c is hexadecimal digit tolower(c) if c is uppercase, returns is lowercase equivalent toupper(c) if c is lowercase, returns is uppercase equivalent Dr. Juan J. Durillo
Dealing with characters in a string. Case 2: processing only some characters ▪ There are two ways to access individual characters in a string ▪ Using the subscript operator [] ▪ Using an iterator ▪ The subscript operator [] requires to provide an index that should be >= 0 and < that the string size // using a subscript for iteration for (decltype(s.size()) index = 0;index != s.size() && !isspace(s[index]); ++index) s[index] = toupper(s[index]); Dr. Juan J. Durillo
Additional string operations Dr. Juan J. Durillo
Other ways to construct a string Additional ways to construct strings string s(cp, n); s is a copy of the first n characters in the array to which cp points. That array must have at least n characters string s(s2,pos2); s is a copy of the characters in the string s2 starting at the index pos2; undefined if pos2>s2.size() string s(s2,pos2,len2); s is a copy of len2 characters from s2 starting at the index pos2; undefined if pos2> s2.size(); regardless of the value of len2, copies at most s2.size()-pos2 characters const char *cp = “hello world”; // null terminated array Note char noNull[] ={‘H’, ‘i’}; //not null terminated substr(pos,n) returns n characters from a string, string s1(cp); // copy up to the null in cp; s1==“hello world” starting from pos string s2(noNull,2); // copy two characters from noNull, s2==“Hi” string s3(noNull); // undefined: noNull is not terminated string s4(cp+6, 5); // copy 5 characters starting at cp[6]; s4==“world” string s8(s1,16); // throws an out_of_range exception
More operations in the string library ▪ A string is a sequential container, and therefore, it provides all the operations that Note can be performed on sequential containers we will devote a lecture to sequential containers in the future ▪ The append() member allows to insert. It is a shorthand of inserting at the end of a given string ▪ The replace() member is a shorthand way of calling erase and insert Dr. Juan J. Durillo
String search operations ▪ The string class provides six different search functions; they all return a Note string::size_type value, which is the index of where the match occurred searching is case sensitive ▪ If there is not match, the function returns a static member named string::npos ▪ find() does the simplest search: it looks for its argument and returns the index of the first match that is found, or npos if there is no match ▪ A slightly more complicated problem requires finding a match to any character in the search string; the member find_first_of allow us to do it Note All the search operations string numbers(“0123456789”), name(“r2d2”); are also available to // returns 1, i.e, the index of the first digit in name perform backward searches auto pos = name.find_first_of(numbers); Note ▪ Similarly, we have the function find_first_not_of(numbers); All of them also accept an optional parameter indicating from where to start the search Dr. Juan J. Durillo
Compare and numeric conversions ▪ In addition to the relational operators, the class string also provides a member called compare(), which perform in a similar way as strcmp() (the C library function) ▪ Strings frequently contain characters that represent numbers; the new standard introduces Conversions between strings and numbers to_string(val); Overloaded function returning the string representation of val, where can be any arithmetic type stoi(s,p,b); Return the initial substring of s that has numeric content as int, long, stol(s,p,b); usigned long, long long, unsigned long long, respectively. b indicates the stoul(s,p,b); numeric base to use for the conversion; b defaults to 10. p is a pointer ot stoll(s,p,b); a size_t in which to put the index of the first nonnumeric character in s; p stoull(s,p,b); defaults to 0, in which case the function does not store the index stof(s,p); Return the initial numeric as a float, double or long double, respectively. stod(s,p); p has the same behavior as described for the integer conversions stold(s,p); Dr. Juan J. Durillo
C-Style character string Dr. Juan J. Durillo
C-Style string ▪ Null-terminated character arrays C-style strings strlen(p) Returns the length of p, not counting the null strcmp(p1,p2) Compares p1 and p2 for equality; return 0 if p1==p2, a positive if p1> p2, a negative value if p1< p2 strcat(p1,p2) appends p2 to p1; return p1 strcpy(p1,p2) copies p2 into p1, returns p1 ▪ Comparing C-style strings using the relational operators will compare the pointer values, not the content of the string ▪ The solution is to use strcmp ▪ The strcmp and strcpy functions do not allocate any memory; the programmer is responsible
Mixing library string and C-style ▪ We can use a null-terminated character array anywhere that we can use a string literal ▪ To initialize or assign a string object ▪ As one operand (but not both) to the string addition operator or as the right-hand operand in the string compound assignment (+=) operator ▪ The reverse is not provided: there is no way to use a library string when a C-Style string is required ▪ However, there is a member function named c_str, which we can often use to accomplish what we want char *str = s; // error: cant’t initialize a char* from a string const char *str = s.c_str(); // ok Dr. Juan J. Durillo
Built-in arrays Dr. Juan J. Durillo
Arrays ▪ An array is a data structure that allow to store sequentially a collection of objects of a given type, offering a tradeoff between performance and flexibility ▪ Arrays have fixed-size ▪ An array declaration has the form a[d], where a is the name being defined and d is the dimension of the array ▪ The dimension specifies the number of elements and must be greater than zero ▪ The number of elements of the array is part of the array’s type; as a result it should be known in compile time, meaning that it needs to be a constant expression
Arrays unsigned cnt = 42; // not a constant expression constexpr unsigned sz = 42; // constant expression int array[10]; // array of ten ints int *parr[sz]; // array of 42 pointers to int string bad[cnt]; // error: cnt is not a constant expression string strs[get_size()]; // ok if get_size is constexp, error otherwise ▪ By default, the elements in an array are default-initialized ▪ An array hold objects; therefore there are no arrays of references ▪ We can list initialize the elements in an array, and in this case, omit the dimension ▪ If we do omit the dimension, the compiler infers it from the number of initializers ▪ If we specify a dimension, the number of initializer must not exceed that dimension
Arrays ▪ Character arrays can also be initialized from a string literal ▪ As string literals are null-ended, that null character is copied into the array (the array should be big enough to hold it) char a1[]={‘C’,’+’, ‘+’}; //list initialization, no null char a2[] = {‘C’,’+’, ‘+’,’\0’}; // list initialization, explicit null char a3[] = “C++”; // null terminator added automatically const char a4[6] = “Daniel”; // error: no space for the null ▪ We cannot initialize nor assign one array to another Dr. Juan J. Durillo
Understanding complicated array declarations ▪ Defining arrays that hold pointers is fairly straightforward; defining a pointer or reference to an array is a bit more complicated int *ptrs[10]; // ptrs is an array of ten pointers to int int &ref[10]; // error: no arrays of references int (*Parray)[10] = &arr; // Parray points to an array of ten ints int (&arrRef)[10] = arr; //arrRef refers to an array of ten ints ▪ By default, type modifiers bind right to left ▪ The definition of ptrs should be read as we are defining an array of size 10, named ptrs that holds pointer to int ▪ Reading from right to left is not always as useful with array declarations; reading them from inside out makes it much easier to understand the type of Parray for example Dr. Juan J. Durillo
Pointers and Arrays ▪ Pointers and arrays are closely related; in particular, when we use an array, the compiler ordinarily converts the array to a pointer ▪ Arrays have a special property- in most places when we use an array, the compiler automatically substitutes a pointer to the first element string nums[] = {“one”, “two”, “three”}; string *p2 = nums; // equivalent to p2 = &nums[0]; ▪ Actually, when we use an array as initializer for a variable defined using auto, the deduced type is a pointer not an array int ia[]={0,1,2,3,4,5,6,7,8,9}; // ia is an array of ten ints auto ia2(ia); // ia2 is an int* that points to the first element in ia ia2 = 42; // error: ia2 is a pointer, and we can’t assign an int to a pointer ▪ The conversion to pointer does not happen when we use decltype; the type returned by it is an array of ten ints Dr. Juan J. Durillo
Pointers are iterators ▪ Pointers that address elements in an array have additional operations; in particular they have the same operations as provided by iterator ▪ An example is the use of the increment operator to move to one element in the array to the next ▪ In an array of ten elements, the end pointer can be obtained as &array[10]; since it points to one past the last valid element in the array (which is array[9]) ▪ Since C++11, the library provide already the functions begin() and end() which return a pointer to the first and one past the last element in an array Dr. Juan J. Durillo
Pointers arithmetic ▪ Adding (or subtracting) an integral value to or from a pointer, the result is a new pointer, which points to the element the given number ahead (or behind) the original pointer ▪ After adding an integral value to a pointer, the result is an element in the same array or a pointer past the end of the array Note remember that the compiler transform the constexpr size_t sz = 5; name of the array as a pointer to the first int arr[sz] = {1, 2, 3, 4, 5}; element of the array int *ip = arr; //equivalent to int *ip = &arr[0]; int *ip2 = ip + 4; // ip2 points to arr[4], the last element in arr ▪ Subtracting two pointers give us the difference between those pointers; the pointers must point to elements in the same array ▪ Pointer arithmetic is also valid for the null pointer (which has a 0 value) Dr. Juan J. Durillo
You can also read