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. DurilloNamespaces
▪ 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. DurilloNote
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. DurilloNamespaces
▪ 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. DurilloNamespace 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. DurilloLibrary 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
coutPerforming 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
coutPerforming 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())
coutPerforming 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. DurilloPerforming 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. DurilloDealing 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)
coutFunctions 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. DurilloDealing 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. DurilloAdditional string
operations
Dr. Juan J. DurilloOther 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 exceptionMore 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. DurilloString 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. DurilloCompare 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. DurilloC-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
responsibleMixing 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. DurilloBuilt-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 dimensionArrays
▪ 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. DurilloUnderstanding 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. DurilloPointers 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. DurilloPointers 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. DurilloPointers 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. DurilloYou can also read