What does built-in types include?
What is the characteristic of built-in types?
What is library, how is it defined?
library is an abbreviation of standard library. Collection of types and functions that every C++ compiler must support. The library provides the types that support IO.
C++ programmers tend to talk about “the library,” meaning the entire standard library. They also tend to refer to particular parts of the library by referring to a library type, such as the “iostream library,” meaning the part of the standard library that defines the IO classes.
The library uses mechanisms that C++ provides to let us define our own data types/data structure–class (and etc.?))to define more complicated types such as variable-length character strings, vectors, and so on.
What is library type?
C++ defines a rich library of abstract data types, what does it mean?
What is the characteristic of library types?
Have a higher-level nature that computer hardware usually does not implement directly.
the standard also imposes efficiency requirements on implementor in addition to specifying the operations that the library types provide,
As a result, library types are efficient enough for general use.
What does built-in types characteristic/library types characteristic bring?
sometimes built-in types are less convenient to use
e.g. Like other built-in types, arrays represent facilities of the hardware.
As a result, arrays are less convenient to use than the library string and vector types.
What are two of the most important library types?
string: A string is a variable-length sequence of characters.
vector: A vector holds a variable-length sequence of objects of a given type.
companion types known as iterators are used to access the characters in a string or the elements in a vector
namespace?
How to use namespace?
:: operator?
How to avoid repeatly using Scope operator :: ?
using declaration
What is using declaration?
Make one name from a namespace accessible directly. It makes name accessible without the namespace:: prefix.
using namespace::name;
A Separate using Declaration Is Required for Each Name
#include
// using declaration; when we use the name cin, we get the one from the namespace
std
using std::cin;
int main()
{
int i;
cin >> i; // ok: cin is a synonym for std::cin
cout << i; // error: no using declaration; we must use the full name
std::cout << i; // ok: explicitly use cout from namepsace std
return 0;
}
Headers Should Not Include using Declarations
N.B. From this point on, To keep the code examples short, we won’t show the using declarations, nor will we show the necessary #include directives. Table A.1 (p. 866) in Appendix A lists the names and corresponding headers for standard library names we use in this Primer.
What is string?
We assume this code is used in examples.
#include
using std::string;//Because it is part of the library, string is defined in the std namespace.
This section describes the most common string operations; § 9.5 (p. 360) will cover additional operations.
Class initialize features?
How to define many different ways(as stated above) to initialize?
How to define and initialize string objects?
initializations can be divided into copy initialize and direct initialization.
what is copy initialize?
what is direct initialization?
string s5 = "hiya"; // copy initialization
string s6("hiya"); // direct initialization
string s7(10, 'c'); // direct initialization; s7 is cccccccccc
When we have a single initializer, we can use either the direct or copy form of initialization.
When we initialize a variable from more than one value, such as in the initialization of s4 above, we must use the direct form of initialization
NOT RECOMMENDED we can also indirectly use the copy form of initialization by explicitly creating a (temporary) object to copy:
string s8 = string(10, 'c'); // copy initialization; s8 is cccccccccc
//The initializer of s8—string(10, 'c')creates a string of the given size and character value and then copies that value into s8. It is as if we had written
string temp(10, 'c'); // temp is cccccccccc
string s8 = temp; // copy temp into s8
Although the code is legal, it is less readable and offers no compensating advantage over the way we initialized s4.
Along with defining how objects are created(defined) and initialized,
a class also defines the operations that objects of the class type can perform.
What kinds of operations can the class define?
the most common string operations is ?
How to Read and Write strings?
use the IO operators to read and write strings:
<< operator: Output operator. Writes the right-hand operand to the output stream indicated by the left-hand operand: cout << “hi” writes hi to the standard output. Output operations can be chained together: cout << “hi” << “bye” writes hibye.
“>>” operator: Input operator. Reads from the input stream specified by the lefthand operand into the right-hand operand: cin >> i reads the next value on the standard input into i. Input operations can be chained together: cin “>>” i “>>” j reads first into i and then into j.
// Note: #include and using declarations must be added to compile this code
int main()
{
string s; // empty string
cin >> s; // read a whitespace-separated string into s
cout << s << endl; // write s to the output
return 0;
}
The string input operator reads and discards any leading whitespace (e.g., spaces, newlines, tabs). It then reads characters until the next whitespace character is encountered. So, if the input to this program is" Hello World! "(note leading and trailing spaces), then the output will be only “Hello” with no extra spaces.
Like the input and output operations on the built-in types, the string operators return their left-hand operand as their result. Thus, we can chain together multiple reads or writes:
string s1, s2;
cin >> s1 >> s2; // read first input into s1, second into s2
cout << s1 << s2 << endl; // write both strings
If we give this version of the program the same input, Hello World! , our output would be “HelloWorld!”
What exactly is this <<, >>??? what does it mean?string input operator? Input operator? depends on different situation? -todo
How to Read an Unknown Number of strings?
int main()
{
string word;
while (cin >> word) // read until end-of-file
cout << word << endl; // write each word followed by a new line
return 0;
}
The condition tests the stream after the read completes. If the stream is valid—it hasn’t hit end-of-file or encountered an invalid input—then the body of the while is executed.
How not to ignore the whitespace in our input?
use the getline function instead of the >> operator
What is getline function?
int main()
{
string line;
// read input a line at a time until end-of-file
while (getline(cin, line))
cout << line << endl;//Because line does not contain a newline, we must write our own. As usual, we use endl to end the current line and flush the buffer.
return 0;
}
Q: two getline. input two result of first 2 or the two except the middle one? -todo
How to know whether the string is empty?
empty function — Member function of string and vector. Returns bool, which is true if size is zero, false otherwise.
To call this function, we use the dot operator to specify the object on which we want to run the empty function.
while (getline(cin, line))
if (!line.empty())
cout << line << endl;
! operator?
How to know the length of a string?
string line;
// read input a line at a time and print lines that are longer than 80 characters
while (getline(cin, line))
if (line.size() > 80)
cout << line << endl;
What is size_type?
Name of types defined by the string and vector classes
They are capable of containing the size of any string or vector, respectively. Library classes that define size_type define it as an unsigned type
The type size_type is one of the companion types.
companion types usage?(配套类型)
std::string
to change member types later without you rewriting your code as long as you use them consistentlyTo use the size_type defined by string, we use the scope operator to say that the name size_type is defined in the string class.
where does string::size_type exist ?
we can ask the compiler to provide the appropriate type by using auto or decltype
auto len = line.size(); // len has type string::size_type
What do we need to remember when use size_type/string::size_type?
How to comparing strings?
The string class defines several operators that compare strings.
The comparisons are casesensitive—uppercase and lowercase versions of a letter are different characters.
equality operators == and !=
relational operators <, <=, >, >=
string str = "Hello";
string phrase = "Hello World";
string slang = "Hiya"
Using rule 1, we see that str is less than phrase. By applying rule 2, we see that slang is greater than both str and phrase.
How to assign a string?
Assignment operator =
string st1(10, 'c'), st2; // st1 is cccccccccc; st2 is an empty string
st1 = st2; // assignment: replace contents of st1 with a copy of st2
// both st1 and st2 are now the empty string
How to add(connect) two strings?
string s1 = "hello, ", s2 = "world\n";
string s3 = s1 + s2; // s3 is hello, world\n
s1 += s2; // equivalent to s1 = s1 + s2
For historical reasons, and for compatibility with C, string literals are not standard library strings. It is important to remember that these types differ when you use string literals and library strings.
So How to Add Literals and strings?
We can use one type where another type is expected if there is a conversion from the given type to the expected type.
-The string library lets us convert both character literals and character string literals (§ 2.1.3, p. 39) to strings.
When we mix strings and string or character literals, at least one operand to each + operator must be of string type
chain them together is ok
string s1 = "hello", s2 = "world"; // no punctuation in s1 or s2
string s3 = s1 + ", " + s2 + '\n';
string s4 = s1 + ", "; // ok: adding a string and a literal
string s5 = "hello" + ", "; // error: no string operand
string s6 = s1 + ", " + "world"; // ok: each + has a string operand same as string s6 = (s1 + ", ") + "world";
string s7 = "hello" + ", " + s2; // error: can't add string literals same as string s7 = ("hello" + ", ") + s2; // error: can't add string literals
dealing with the individual characters in a string involved which two parts?
How to Use the C++ Versions of C Library (Headers) ?
the C++ library incorporates the C library
Headers in C have names of the form name .h
The C++ versions of these headers are named ‘c’+‘name’
cctype has the same contents as ctype.h
both are ok but
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xsWrr8yJ-1606907867733)(C:\Users\SDA10\AppData\Roaming\Typora\typora-user-images\image-20201122111026806.png)]
How to Process/access Every Character?
the range for statement
syntactic form?
for (declaration/* of loop control/variable loop/variable control variable*/ : expression)//expression is an object of a type that represents a sequence; declaration defines the variable that we’ll use to access the underlying elements in the sequence. On each iteration, the variable in declaration is initialized from the value of the next element in expression.
statement
A string represents a sequence of characters, so we can use a string as the expression in a range for.
string str("some string");
// print the characters in str one character to a line
for (auto c : str) // for every char in str
cout << c << endl; // print the current character followed by a newline
string s("Hello World!!!");
// punct_cnt has the same type that s.size returns; see § 2.5.3 (p. 70)
decltype(s.size()) punct_cnt = 0;// string::size_type
// count the number of punctuation characters in s
for (auto c : s) // for every char in s
if (ispunct(c)) // if the character is punctuation
++punct_cnt; // increment the punctuation counter
cout << punct_cnt
<< " punctuation characters in " << s << endl;
How to change every characters in a string ?
string s("Hello World!!!");
// convert s to uppercase
for (auto &c : s) // for every char in s (note: c is a reference)
c = toupper(c); // c is a reference, so the assignment changes the char in s
cout << s << endl;
The output of this code is
HELLO WORLD!!!
we can call the library toupper function, which takes a character and put the result back in that character and return it.
If we want to change the value of the characters in a string, we must define the loop variable as a reference type. When we use a reference as our control variable, that variable is bound to each element in the sequence in turn.
How to Process/access Only Some Characters in a string?
We can use a subscript to subscript a string or: an iterator
What is subscript operator(the [ ] operator)/usage?syntax?
Subscript operator returns an element at given position from the container object. If p is a pointer and n an integer, p[n] is a synonym for *(p+n).
For string object subscript returns returns a reference to the character at the given position.
syntax: obj[i]
The value in the subscript
It is referred to as “a subscript” or “an index.”
In string, the index is a string::size_type value but can be any expression that yields an integral value.
If our index has a signed type, its value will be converted to the unsigned type that string::size_type represents.
But the values we use to subscript a string should>= 0 and < size(): It counts from zero—the first element is element 0 and the last is the element indexed by obj.size() - 1.
When subscripting, the library is not required to check the value of an subscript/string.
By implication, subscripting an empty string is undefined. Any time we use a subscript, we must ensure that there is a value at the given location.
if (!s.empty()) // make sure there's a character to print
cout << s[0] << endl; // print the first character in s
access one char?
string s("some string");//the string is not const
if (!s.empty()) // make sure there's a character in s[0]
s[0] = toupper(s[0]); // assign a new value to the first character in s
access multiple char in sequence?(Iteration)
// process characters in s until we run out of characters or we hit a whitespace
for (decltype(s.size()) index = 0;
index != s.size() && !isspace(s[index]); ++index)
s[index] = toupper(s[index]); // capitalize the current
character
Random Access?(not in sequence)
calculate an subscript and directly fetch the indicated character.
const string hexdigits = "0123456789ABCDEF"; // possible hex digits
cout << "Enter a series of numbers between 0 and 15"
<< " separated by spaces. Hit ENTER when finished: "
<< endl;
string result; // will hold the resulting hexify'd string
string::size_type n; // hold numbers from the input
while (cin >> n)
if (n < hexdigits.size()) // ignore invalid input
result += hexdigits[n]; // fetch the indicated hex digit
cout << "Your hex number is: " << result << endl;
/*
If we give this program the input
12 0 5 15 8 15
the output will be
Your hex number is: C05F8F
*/
What is vector, usage?
Library type that holds a collection of elements of the same specified type. Every object in the collection has an associated index, which gives access to that object.
A vector is often referred to as a container because it “contains” other objects.
container?
A vector is a class template
template?
Templates are not themselves functions or classes. they can be thought of as instructions to the compiler for generating classes or functions. When we use a template, we specify what kind of class or function we want the compiler to instantiate. The process that the compiler uses to create classes or functions from templates is called instantiation(Compiler process that generates a specific template class or function.)
How to use it?
C++ has both class and function templates.
class template?
blueprint from which specific class types can be created.
How to use it?
NB To use a vector, we must include the appropriate header. In our examples, we also assume that an appropriate using declaration is made:
#include
using std::vector;
How to create specific vector type?
vector is a template, not a type. (but this book call it class type/container, confusing)Types generated from vector must include the element type, for example, vector.
vector ivec; // ivec holds objects of type int
vector Sales_vec; // holds Sales_items
vector> file; // vector whose elements are vectors
//Some compilers may require the old-style declarations for a vector of vectors,like vector >.
//in this example, the compiler generates three distinct types from the vector template: vector, vector, and vector>
As with any class type, the vector template controls how we define and initialize vectors.
How to initialize vectors?
default initialize
vector svec; // default initialization; svec has no elements
default initialize is empty
an empty vector would be of great use. We can (efficiently) add elements to a vector at run time. The most common way of using vectors is to define an initially empty vector to which elements are added as their values become known at run time.
copy elements from another vector
vector ivec; // initially empty
// give ivec some values
vector ivec2(ivec); // copy elements of ivec into ivec2
vector ivec3 = ivec; // copy elements of ivec into ivec3
vector svec(ivec2); // error: svec holds strings, not ints
The two vectors must be the same type
list initialize
initialize by a list of zero or more initial element values enclosed in curly braces:
vector articles = {"a", "an", "the"};
Creating a Specified Number of Elements
initialize a vector from a count and an element value. count determine the number of initializers, the value provides the same initial value for every initializers.
vector ivec(10, -1); // ten int elements, each initialized to -1
vector svec(10, "hi!"); // ten strings; each element is "hi!"
Value Initialization for vector?
**Value Initialization (值初始化) principle? for what use? **
Initialization Used to initialize a container’s elements when a size, but not an element initializer, is specified. Elements are initialized as a copy of this compiler-generated value: built-in types are initialized to zero and class types are initialized by the class’s default constructor. Objects of a class type can be value initialized only if the class has a default constructor or it will be a error, we must supply initializer value. (see default initialize in chapter 2)
omit the value and supply only a size. as to the value: the library(isn’t it compiler?) creates a value-initialized element initializer for us
vector ivec(10); // ten elements, each initialized to 0
vector svec(10); // ten elements, each an empty string
some classes require that we always supply an explicit initializer(i.e. cannot default initialize, no default constructor)
when we supply an element count without also supplying an initial value, we must use the direct form of initialization:
vector vi = 10; // error: copy form of initialization
//must use direct initialization to supply asize
vector vi {10};//not Value Initialization
We specify which initialization we intend with direct initialization by whether we use curly braces or parentheses:
vector v1(10); // v1 has ten elements with value 0
vector v2{10}; // v2 has one element with value 10
vector v3(10, 1); // v3 has ten elements with value 1
vector v4{10, 1}; // v4 has two elements with values 10 and 1
When we use parentheses, we are saying that the values we supply are to be used to construct the object.
When we use curly braces, {…}, if possible (like values inside braces must match the element type), we want to list initialize the object: if there is a way to use the values inside the curly braces as a list of element initializers, the class will do so.
if it is not possible to list initialize the object will the other ways to initialize the object be considered.(like those values will be used to construct the object.)
//to list initialize a vector of strings, we must supply values that can be used as strings.so:
vector v5{"hi"}; // list initialization: v5 has one element
vector v6("hi"); // error: can't construct a vector from a string literal
vector v7{10}; // v7 has ten default-initialized elements
vector v8{10, "hi"}; // v8 has ten elements with value "hi"
initialize conclusion?
when we use the copy initialization form (i.e., when we use =) (§ 3.2.1, p. 84), we can supply only a single initializer
when we supply an in-class initializer (§ 2.6.1, p. 73), we must either use copy initialization or use curly braces.
we can supply a list of element values only by using list initialization in which the initializers are enclosed in curly braces. We cannot supply a list of initializers using parentheses:
vector v1{"a", "an", "the"}; // list initialization
vector v2("a", "an", "the"); // error
Directly initializing the elements is suitable for?
as long as it is limited:
Directly initializing the elements problems?
it is not limited:
How to solve this?
create an empty vector and add elements at run time.
How to add elements?
use a vector member named push_back
push_back?
Member of vector. Appends elements to the back of a vector.
wrong: subscripting a vector to add elements. The subscript operator on vector (and string) fetches an existing element; it does not add an element.
vector ivec; // empty vector
for (decltype(ivec.size()) ix = 0; ix != 10; ++ix)
ivec[ix] = ix; // disaster: ivec has no elements
for (decltype(ivec.size()) ix = 0; ix != 10; ++ix)
ivec.push_back(ix); // ok: adds a new element with value ix
vector v2; // empty vector
for (int i = 0; i != 100; ++i)
v2.push_back(i); // append sequential integers to v2
// at end of loop v2 has 100 elements, values 0 . . . 99
// read words from the standard input and store them as elements in a vector
string word;
vector text; // empty vector
while (cin >> word) {
text.push_back(word); // append word to text
}
Usually used method of defining and initialize vector?
vector Operations includes?
most of them are similar to the corresponding operations on strings.
exception: The size member returns a value of the size_type defined by the corresponding vector type.
To use size_type, we must name the type in which it is defined. A vector type always includes its element type (§ 3.3, p. 97):
vector::size_type // ok
vector::size_type // error
How to access the elements of a vector?
the same way that we access the characters in a string
range for
vector v{1,2,3,4,5,6,7,8,9};
for (auto &i : v) // for each element in v (note: i is a reference)
i *= i; // square the element value
for (auto i : v) // for each element in v
cout << i << " "; // print the element
cout << endl;
subscript operator: same. but the type of a subscript is the corresponding size_type(see above). assuming the vector is nonconst—we can write to the element returned by the subscript operator.
example for Computing a vector Index
// count the number of grades by clusters of ten: 0--9, 10--19, . .. 90--99, 100
vector scores(11, 0); // 11 buckets, all initially 0
/*unsigned a和unsigned int a等价。
singed a和singed int a等价。*/
unsigned grade;
while (cin >> grade) { // read the grades
if (grade <= 100) // handle only valid grades when we use a subscript, we should think about how we know that the indices are in range: we verify that the input is a valid grade in the range between 0 and 100. Thus, we know that the indices we can compute are between 0 and 10.
++scores[grade/10]; // increment the counter for the current cluster good example of the kind of terse code characteristic of C++ programs.
}
!!! Security Problems Caution: Buffer Overflow
So-called buffer overflow errors are the result of subscripting elements that don’t exist.
may use the subscript operator (the [] operator) to fetch only elements that actually exist.
It is an error to subscript an element that doesn’t exist, but it is an error that the compiler is unlikely to detect. Instead, the value we get at run time is undefined.
Such bugs are the most common cause of security problems in PC and other applications.
A good way to ensure that subscripts are in range is to avoid subscripting altogether by using a range for whenever possible.
How to compare two vectors?
What is iterators?
iterators usage?
We can use an iterator to fetch an element and iterators have operations to
move from one element to another.
when iterator valid?
As with pointers, an iterator may be valid or invalid. A valid iterator either denotes an element or denotes a position one past the last element in a container. All other iterator values are invalid.
How to define the iterators?
we don’t care about the type, iterators are defined by auto.
we use types members named begin and end that return iterators (types should have/support iterators).
begin?
end?
Member of string and vector that returns an off-the-end iterator.(abbreviated as “the end iterator.”)
The iterator returned by end is an off-the-end iterator:
freestanding library function that takes an array and returns a pointer one past the last element in the array.
If the container is empty, the iterators returned by begin and end are equal —they are both off-the-end iterators.
// the compiler determines the type of b and e; see § 2.5.2
// b denotes the first element and e denotes one past the last element in v
auto b = v.begin(), e = v.end(); // b and e have the same type
Iterator Operations?
all the library container should support:(Iterators for string and vector support additional operations)
like pointers, we can dereference (*) an iterator to obtain the element denoted by an iterator. Also, we may dereference only a valid iterator that denotes an element . Dereferencing an invalid iterator or an off-the-end iterator has undefined behavior.
Iterators are equal if they denote the same element or if they are both off-the-end iterators for the same container. Otherwise, they are unequal.
string s("some string");
if (s.begin() != s.end()) { // make sure s is not empty
auto it = s.begin(); // it denotes the first character in s
*it = toupper(*it); // make that character uppercase
}
/*the output of this loop will be:
Some string */
How to move Iterators from One Element to Another?
use the increment (++) operator
iterator returned from end does not denote an element, it may not be incremented or dereferenced.
// process characters in s until we run out of characters or we hit a whitespace
for (auto it = s.begin(); it != s.end() && !isspace(*it);++it)
*it = toupper(*it); // capitalize the current character
why not use < instead of !=?(Generic Programming)
Iterator Types are?
the library types that have iterators define types named iterator and const_iterator that represent actual iterator types.
vector::iterator it; // it can read and write vector elements
string::iterator it2; // it2 can read and write characters in a string
vector::const_iterator it3; // it3 can read but not write elements
string::const_iterator it4; // it4 can read but not write characters
A const_iterator behaves like a pointer to const. It may read but not write the element it denotes. an object of type iterator can both read and write.
The term iterator is used to refer to three different entities. We might mean the concept of an iterator, or we might refer to the iterator type defined by a container, or we might refer to an object as an iterator.
How does the library define iterator types?
If the object is const, then begin and end return a const_iterator; if the object is not const, they return iterator.
With a nonconst vector or string, we can use either iterator or const_iterator(by the method below).
vector v;
const vector cv;
auto it1 = v.begin(); // it1 has type vector::iterator
auto it2 = cv.begin(); // it2 has type vector::const_iterator
cbegin and cend return const iterators to the first and one past the last element in the container.
auto it3 = v.cbegin(); // it3 has type vector::const_iterator
How to use iterator to access the member of a class object?
(*it).empty()
the parenthesis is necessary
*it.empty() // error: attempts to fetch the member named empty from it
// but it is an iterator and has no member named empty
for the same purpose, also can use -> operator
Some vector Operations Invalidate Iterators
any operation, such as push_back, that changes the size of a vector potentially invalidates all iterators into that vector.
For now, we only need to know it is important to realize that loops that use iterators should not add elements to the container to which the iterators refer.
What is iterator arithmetic?
Operations on(and only available for) vector or string iterators: Adding or subtracting an integral value and an iterator yields an iterator that many elements ahead of or behind the original iterator. Subtracting one iterator from another yields the distance between them. Iterators must refer to elements in, or off-the end of the same container.
subtract two iterators that refer to elements in, or one off the end of, the same vector or string. The result is the distance between the iterators: the amount by which we’d have to change one iterator to get the other.
Using Iterator Arithmetic example: binary search
// text must be sorted
// beg and end will denote the range we're searching
//We initialize these iterators to denote the entire range in a vector named text.
auto beg = text.begin(), end = text.end();
auto mid = text.begin() + (end - beg)/2; // original midpoint
while (mid != end && *mid != sought) {//If mid is equal to the current value of end, then we’ve run out of elements to search. In this case, the condition fails and we exit the while. Otherwise, mid refers to an element and we check whether mid denotes the one we want. If so, we’re done and we exit the loop.At the end of the while, mid will be equal to end or it will denote the element for which we are looking. If mid equals end, then the element was not in text.
if (sought < *mid) // is the element we want in the first half?
end = mid; // if so, adjust the range to ignore the second half
else // the element we want is in the second half
beg = mid + 1; // start looking with the element just after mid
mid = beg + (end - beg)/2; // new midpoint
}
What is arrays?
What does fix size influence arrays?
How to define arrays?
declarator: a[d]
base type:
unsigned cnt = 42; // not a constant expression
constexpr unsigned sz = 42; // constant expression
// constexpr see § 2.4.4 (p. 66)
int arr[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 constexpr, error otherwise
How to initialize arrays?
no initializers, then the elements in an array are default initialized
list initialize
we can omit the dimension when use this: the compiler infers it from the number of initializers.
if the dimension is specified, the numbers of initializers should not exceed the specified size. When the number of initializers is smaller, the remaining are value initialized.
const unsigned sz = 3;
int ia1[sz] = {0,1,2}; // array of three ints with values 0, 1, 2
int a2[] = {0, 1, 2}; // an array of dimension 3
int a3[5] = {0, 1, 2}; // equivalent to a3[] = {0, 1, 2, 0, 0}
string a4[3] = {"hi", "bye"}; // same as a4[] = {"hi", "bye", ""}
int a5[2] = {0,1,2}; // error: too many initializers
We can initialize character arrays from a string literal(end with a null character).
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 an array as a copy of another array, nor is it legal to assign one array to another:
int a[] = {0, 1, 2}; // array of three ints
int a2[] = a; // error: cannot initialize one array with another
a2 = a; // error: cannot assign one array to another
Some compilers allow array assignment as a compiler extension. BUT Don’t do this.
How to define array of pointers ?
int *ptrs[10]; // ptrs is an array of ten pointers to int
By default, type modifiers bind right to left. Reading the definition of ptrs from right to left is easy: We see that we’re defining an array of size 10, named ptrs, that holds pointers to int.
How to define a pointer or reference to an array?
int (*Parray)[10] = &arr; // Parray points to an array of ten ints
int (&arrRef)[10] = arr; // arrRef refers to an array of ten ints
int *(&arry)[10] = ptrs; // arry is a reference to an array of ten pointers
read array declarations from the inside out rather than from right to left.
We start by observing that the parentheses around *Parray mean that Parray is a pointer. Looking right, we see that Parray points to an array of size 10. Looking left, we see that the elements in that array are ints. Thus, Parray is a pointer to an array of ten ints. Similarly, (&arrRef) says that arrRef is a reference. The type to which it refers is an array of size 10. That array holds elements of type int.
How to access elements of an array?
With the exception that arrays are fixed size, it is the same as vector and string.
like use a range for or the subscript operator.
**buffer overflow: **As with string and vector, it is up to the programmer to ensure that the subscript value is in range. It is possible for programs to compile and execute yet still be fatally wrong.(buffer overflow bugs. a program fails to check a subscript and mistakenly uses memory outside the range of an array or similar data structure.)
// count the number of grades by clusters of ten: 0--9, 10--19, ... 90--99, 100
unsigned scores[11] = {}; // 11 buckets, all value initialized to 0
unsigned grade;
while (cin >> grade) {
if (grade <= 100)
++scores[grade/10]; // increment the counter for the current cluster
}
```c++
for (auto i : scores) // for each counter in scores
cout << i << " "; // print the value of that counter
cout << endl
How to use a variable to subscript an array?
define that variable to have type size_t
size_t?
NB. Here ,the pointer is not like this:
int ia[4]; // array of size 3; each element is an array of ints of size 4
int (*p)[4] = ia; // p points to an array of four ints
*p is an array with size 4
it is like this:
int *p = ia// pointer to the first element
int *e = &arr[10]; // pointer just past the last element in arr
*p is an array element
or pointer that address a element in an array.
p.s. the meainng of ia depend on the situation it should be.
How does C++ realize arrays?
In C++ pointers and arrays are closely intertwined. When we use an array, the compiler ordinarily converts the array to a pointer.
implications of the fact that operations on arrays are often really operations on pointers:
auto 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
decltype array?
// ia3 is an array of ten ints
decltype(ia) ia3 = {0,1,2,3,4,5,6,7,8,9};
ia3 = p; // error: can't assign an int* to an array
ia3[4] = i; // ok: assigns the value of i to an element in ia3
What’s special in Pointer that address a element in an array?
Pointer Arithmetic
All The results(which is the member of the array) should be in range or just past the end of the array.
pointers to array elements support the same operations as iterators on vectors or strings. It is iterators.
int *p = ia// pointer to the first element ,like begin()
int *e = &arr[10]; // pointer just past the last element in arr, like end()
we can use the increment operator to move from one element in an array to the next
int arr[] = {0,1,2,3,4,5,6,7,8,9};
int *p = arr; // p points to the first element in arr
++p; // p points to arr[1]
When we add (or subtract) an integral value to (or from) a pointer, the result is a new pointer. That new pointer points to the element the given number ahead of (or behind) the original pointer.
constexpr size_t sz = 5;
int arr[sz] = {1,2,3,4,5};
int *ip = arr; // equivalent to int *ip = &arr[0]
int *ip2 = ip + 4; // ip2 points to arr[4], the last element in arr
// ok: arr is converted to a pointer to its first element; p points one past the end of arr
int *p = arr + sz; // use caution -- do not dereference!
int *p2 = arr + 10; // error: arr has only 5 elements; p2 has undefined value.the compiler is unlikely to detect such errors.
use subscripts
mechanism:
int i = ia[2]; // ia is (converted to) a pointer to the first element in ia
// i = ia[2] actually is:
i = *(ia + 2);
we can use subscripts to access the underlying object
int *p = &ia[2]; // p points to the element indexed by 2
int j = p[1]; // p[1] is equivalent to *(p + 1),
// p[1] is the same element as ia[3]
int k = p[-2]; // p[-2] is the same element as ia[0]
The library types such as vector and string force the index used with a subscript to be an unsigned value. The built-in subscript operator does not.
As with iterators, subtracting two pointers gives us the distance between those pointers. The pointers must point to elements in the same array:
the result type is a library type named ptrdiff_t
auto n = end(arr) - begin(arr); // n is 5, the number of elements in arr
We can use the relational operators to compare pointers that point to elements of an array, or one past the last element in that array. We cannot use the relational operators on pointers to two unrelated objects.
int *b = arr, *e = arr + sz;
while (b < e) {
// use *b
++b;
}
it is worth noting that pointer arithmetic is also valid for null pointers and for pointers that point to an object that is not an array. the pointers must point to the same object, or one past that object.
If p is a null pointer, we can add or subtract an integral constant expression whose value is 0 to p. We can also subtract two null pointers from one another, in which case the result is 0.
int i = 0, sz = 42;
int *p = &i, *e = &sz;
// undefined: p and e are unrelated; comparison is meaningless!
while (p < e)
Pointer Arithmetic e.g. we can use pointers like iterators to traverse the elements in an array.
we need to obtain pointers to the first and one past the last element.
pointer to the first element by using the array itself or by taking the address-of the first element.
obtain an off-the-end pointer: use the subscript operator to index a non-existing element. Similarly an off-the-end pointer does not point to an element. we may not dereference or increment an off-the-end pointer.
int *e = &arr[10]; // pointer just past the last element in arr
// traverse the elements in an array
for (int *b = arr; b != e; ++b)
cout << *b << endl; // print the elements in arr
How to safely and easily use off-the-end pointer of arrays?
int ia[] = {0,1,2,3,4,5,6,7,8,9}; // ia is an array of ten ints
int *beg = begin(ia); // pointer to the first element in ia
int *last = end(ia); // pointer one past the last element in ia
How to Dereference Pointer Arithmetic?
int ia[] = {0,2,4,6,8}; // array with 5 elements of type int
int last = *(ia + 4); // ok: initializes last to 8, the value of ia[4]
What is C-style character strings?
C-style character strings instance?
Character string literals (it is array? it should only be when we store it in an array)
const char ca1[] = "A string example";
const char ca2[] = "A different string";
How to manipulate C-style character strings?
What parameters do C Library String Functions receive?
parameters are array names/pointer point to the first element (must point to null-terminated array).
char ca[] = {'C', '+', '+'}; // not null terminated
cout << strlen(ca) << endl; // disaster: ca isn't null terminated
The result is undefined. strlen will keep looking through the memory that follows ca until it encounters a null character.
they do not verify their string parameters.
What do C Library String Functions includes?
How to Compare C-style Strings?
strcmp returns 0 if the strings are equal, or a positive or negative value, depending on whether the first string is larger or smaller than the second just like < > == in string
Not like comparing two library strings(if (p1 < p2) etc.) when we use operators like <, we are comparing pointers. LIke below, those pointers do not address the same object, so the comparison is undefined.
const char ca1[] = "A string example";
const char ca2[] = "A different string";
if (ca1 < ca2) // Those pointers do not address the same object, so the comparison is undefined.
if (strcmp(ca1, ca2) < 0) // same effect as string comparison s1 < s2
Concatenating or copying C-style strings?
we cannot use + like strings
the expression ca1 + ca2 tries to add two pointers, which is illegal and meaningless.
= maybe ok but that is not copy but become the same object?
We use strcat and strcpy.
The array we pass must be large enough to hold the generated string, including the null character at the end.
// disastrous if we miscalculated the size of largeStr
strcpy(largeStr, ca1); // copies ca1 into largeStr
strcat(largeStr, " "); // adds a space at the end of largeStr
strcat(largeStr, ca2); // concatenates ca2 onto largeStr
***The problem is that we can easily miscalculate the size needed for largeStr.**
**Moreover, any time we change the values we want to store in largeStr, we have to remember to double-check that we calculated its size correctly. So it is fraught with potential for serious error.**
### 3.5.5. Interfacing to Older Code
**Library strings, vectors and C-Style Strings Mixing restriction?**
- **we can use a null-terminated character array anywhere that we can use a *string literal***
- We can use a null-terminated character array to initialize or assign a string.
- We can use a null-terminated character array as one operand (but not both operands) to the string addition operator or as the right-hand operand in the string compound assignment (+=) operator
- we can use an array to initialize a vector. To do so, we specify the address of the first element and one past the last element that we wish to copy:
```c++
int int_arr[] = {0, 1, 2, 3, 4, 5};
// ivec has six elements; each is a copy of the corresponding element in int_arr
vector ivec(begin(int_arr), end(int_arr));
// copies three elements: int_arr[1], int_arr[2], int_arr[3]
vector subVec(int_arr + 1, int_arr + 4);
There is no direct way to use a library string when a C-style string is required.
For example, there is no way to initialize a character pointer from a string.
But string member function c_str can do this
char str = s; // error: can’t initialize a char from a string
const char *str = s.c_str(); // ok
it returns a pointer to the beginning of a null-terminated character array that holds the same data as the characters in the string.
The type of the pointer is const char*, which prevents us from changing the contents of the array.
The array returned by c_str is not guaranteed to be valid indefinitely. Any subsequent use of s that might change the value of s can invalidate this array.
If a program needs continuing access to the contents of the array returned by str(), the program must copy the array returned by c_str.
What do we choose? Arrays(including C-style array-based character strings),vectors,strings?
Use Library Types Instead of Arrays
Modern C++ programs should use vectors and iterators instead of built-in arrays and pointers, and use strings rather than C-style array-based character strings.
Pointers and arrays are surprisingly error-prone. Pointers are used for low-level manipulations and it is easy to make bookkeeping mistakes. Other problems arise because of the syntax, particularly the declaration syntax used with pointers.
There are no multidimensional arrays in C++. They are actually arrays of arrays.
How to define multidimensional arrays?
//reading them from the inside out.
int ia[3][4]; // array of size 3; each element is an array of ints of size 4
// array of size 10; each element is a 20-element array whose elements are arrays of 30 ints
int arr[10][20][30] = {0}; // initialize all elements to 0
There is no limit on how many subscripts are used.
two-dimensional array jargon?
How to initialize multidimensional arrays?
providing a bracketed list of initializers.
specifying bracketed values for each row:
int ia[3][4] = { // three elements; each element is an array of size 4
{0, 1, 2, 3}, // initializers for the row indexed by 0
{4, 5, 6, 7}, // initializers for the row indexed by 1
{8, 9, 10, 11} // initializers for the row indexed by 2
};
no specifying bracketed values for each row:
// equivalent initialization without the optional nested braces for each row
int ia[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
We can initialize only the first some element of each row, rest are default initialized.
// explicitly initialize only element 0 in each row
int ia[3][4] = {{ 0 }, { 4 }, { 8 }};
// explicitly initialize row 0; the remaining elements are value initialized
int ix[3][4] = {0, 3, 6, 9};
all elements are the same(0-which is value initialize):
int arr[10][20][30] = {0}; // initialize all elements to 0 -default initialize
//other value? plz use for(){}...
How to Subscript a Multidimensional Array?
use separate subscripts
If we supply fewer subscripts than there are dimensions, then the result is the inner-array element at the specified index
// assigns the first element of arr to the last element in the last row of ia
ia[2][3] = arr[0][0][0];
int (&row)[4] = ia[1]; // binds row to the second four-element array in ia
How to process the elements in a multidimensional array?
constexpr size_t rowCnt = 3, colCnt = 4;
int ia[rowCnt][colCnt]; // 12 uninitialized elements
// for each row
for (size_t i = 0; i != rowCnt; ++i) {
// for each column within the row
for (size_t j = 0; j != colCnt; ++j) {
// assign the element's positional index as its value
ia[i][j] = i * colCnt + j;
}
}
range for
size_t cnt = 0;
for (auto &row : ia) // for every element in the outer array
for (auto &col : row) { // for every element in the inner array
col = cnt; // give this element the next value
++cnt; // increment cnt
}
we declare our control variables as references to change the value. the type of row is a reference to an array of four ints.
for (auto row : ia)
for (auto col : row)
this program would not compile
Because row is not a reference, when the compiler initializes row it will convert each array element (like any other object of array type) to a pointer to that array’s first element. the type of row is int*.
-The inner for loop is illegal. It attempts to iterate over an int*.
How to point to multidimensional arrays?
As with any array, when we use the name of a multidimensional array, it is automatically converted to a pointer to the first element in the array.
the pointer to the multidimensional array is a pointer to the first inner array
int ia[3][4]; // array of size 3; each element is an array of ints of size 4
int (*p)[4] = ia; // p points to an array of four ints
p = &ia[2]; // p now points to the last element in ia
// print the value of each element in ia, with each inner array on its own line
// p points to an array of four ints
for (auto p = ia; p != ia + 3; ++p) {
// q points to the first element of an array of four ints; that is, q points to an
int
for (auto q = *p; q != *p + 4; ++q)
cout << *q << ' ';
cout << endl;
}
multidimensional arrays oprations/arithmetic?
The increment, ++p, has the effect of moving p to point to the next row (i.e., the next element) in ia. (one array not one element.)
***The result of p is an array of four ints.**(like int (*p)[4] = ia)
//simplified version
// p points to the first array in ia
for (auto p = begin(ia); p != end(ia); ++p) {
// q points to the first element in an inner array
for (auto q = begin(*p); q != end(*p); ++q)
cout << *q << ' '; // prints the int value to which q
points
cout << endl;
}
//In the outer loop, that type is a pointer to an array of four ints. In the inner loop, that type is a pointer to int.
Simplify Pointers to Multidimensional Arrays Declaration?
using int_array = int[4]; // new style type alias declaration; see § 2.5.1 (p.68)
typedef int int_array[4]; // equivalent typedef declaration; § 2.5.1 (p. 67)
// print the value of each element in ia, with each inner array on its own line
for (int_array *p = ia; p != ia + 3; ++p) {
for (int *q = *p; q != *p + 4; ++q)
cout << *q << ' ';
cout << endl;
}
array of four ints
p = &ia[2]; // p now points to the last element in ia
- ```c++
// print the value of each element in ia, with each inner array on its own line
// p points to an array of four ints
for (auto p = ia; p != ia + 3; ++p) {
// q points to the first element of an array of four ints; that is, q points to an
int
for (auto q = *p; q != *p + 4; ++q)
cout << *q << ' ';
cout << endl;
}
multidimensional arrays oprations/arithmetic?
The increment, ++p, has the effect of moving p to point to the next row (i.e., the next element) in ia. (one array not one element.)
The result of *p is an array of four ints (like int (*p)[4] = ia)
//simplified version
// p points to the first array in ia
for (auto p = begin(ia); p != end(ia); ++p) {
// q points to the first element in an inner array
for (auto q = begin(*p); q != end(*p); ++q)
cout << *q << ' '; // prints the int value to which q
points
cout << endl;
}
//In the outer loop, that type is a pointer to an array of four ints. In the inner loop, that type is a pointer to int.
Simplify Pointers to Multidimensional Arrays Declaration?
using int_array = int[4]; // new style type alias declaration; see § 2.5.1 (p.68)
typedef int int_array[4]; // equivalent typedef declaration; § 2.5.1 (p. 67)
// print the value of each element in ia, with each inner array on its own line
for (int_array *p = ia; p != ia + 3; ++p) {
for (int *q = *p; q != *p + 4; ++q)
cout << *q << ' ';
cout << endl;
}