Chapter 3. Strings, Vectors and Arrays
What does built-in types include?
- chapter 2
- array
- maybe more?
What is the characteristic of built-in types?
- These types represent facilities present in most computer hardware, such as numbers or characters.
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?
- Type, such as istream, defined by the standard library. Library types, such as istream and ostream, are classes.
C++ defines a rich library of abstract data types, what does it mean?
- they are abstractions of the more primitive built-in array type.
- like the string and vector types defined by the library.
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
3.1. Namespace using Declarations
namespace?
- Mechanism for putting names defined by a library into a single place. Namespaces help avoid inadvertent name *es. The names defined by the C++ library are in the namespace std.
How to use namespace?
- :: operator
- using declaration
- § 18.2.2 (p. 793) covers another way to use names from a namespace.
:: operator?
- Scope operator. Among other uses, the scope operator is used to access names in a namespace. For example, std::cout denotes the name cout from the namespace std.
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 <iostream> // 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
- The reason is that the contents of a header are copied into the including program’s text.
- If a header has a using declaration, then every program that includes that header gets that same using declaration. As a result, a program that didn’t intend to use the specified library name might encounter unexpected name conflicts.
-
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.
3.2 Library string Type
What is string?
- Library type that represents a sequence of characters.
- string is not a container type, but string supports many of the container
operations.
We assume this code is used in examples.
#include <string>
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.
3.2.1. Defining and Initializing strings
Class initialize features?
- A class may define many different ways to initialize objects of its type.
How to define many different ways(as stated above) to initialize?
- either by the number of initializers that we supply, or by the types of those initializers.
How to define and initialize string objects?
-
-
initializations can be divided into copy initialize and direct initialization.
what is copy initialize?
- Form of initialization that uses an =. The newly created object is a copy of the given initializer.
what is direct initialization?
- Form of initialization that does not include an =.
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.
-
3.2.2. Operations on strings
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?
- operations that are called by name
- what does operator symbols mean when applied to objects of the class’ type
the most common string operations is ?
- Table 3.2. string Operations
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?
- Function defined in the string header that takes an istream and a string.
- The function reads the stream up to the next newline, storing what it read into the string, and returns the istream.
- After getline sees a newline, even if it is the first character in the input, it stops reading and returns. If the first character in the input is a newline, then the resulting string is the empty string.
- The newline is read and discarded so not stored in the string.
-
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?
- Logical NOT operator. Returns the inverse of the bool value of its operand. Result is true if operand is false and vice versa.
How to know the length of a string?
- size member(function)– Member of string and vector. Returns the number of characters or elements, respectively. Returns a value of the size_type for the type.
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?(配套类型)
- The string class—and most other library types—defines several companion types. These companion types make it possible to use the library types in a machine-independent manner.
- it lets author of
std::string
to change member types later without you rewriting your code as long as you use them consistently
-
To 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 ?- Any variable used to store the result from the string size operation should be of type string::size_type.—returned by .size()
-
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
- others?
What do we need to remember when use size_type/string::size_type?
- Because size returns an unsigned type, it is essential to remember that expressions that mix signed and unsigned data can have surprising results. For example, if n is an int that holds a negative value, then s.size() < n will almost surely evaluate as true. It yields true because the negative value in n will convert to a large unsigned value.
- avoid problems due to conversion between unsigned and int by not using ints in expressions that use size() is one option.
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 !=
- Two strings are equal if they are the same length and contain the same characters
-
relational operators <, <=, >, >=
- 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.
- If any characters at 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.(ASCII value?)
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?
- plus operator +
- the result is a new string whose characters are a copy of those in the left-hand operand followed by those from the right-hand operand.
- compound assignment operator (+=)
- appends the right-hand operand to the left-hand string
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
3.2.3. Dealing with the Characters in a string
dealing with the individual characters in a string involved which two parts?
- One part of this kind of processing involves how we gain access to the characters themselves. Sometimes we need to process every character. Other times we need to process only a specific character, or we can stop processing once some condition is met. The best way to deal with these cases involves different language and library facilities.
- The other part of processing characters is knowing and/or changing the characteristics of a character. It is handled by a set of library functions defined in the cctype header, described in Table 3.3.
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
- the names defined in the cname headers are defined inside the std namespace, whereas those defined in the .h versions are not.
- C++ programs should use the cname versions of headers and not the name .h versions. That way names from the standard library are consistently found in the std namespace. Using the .h headers puts the burden on the programmer to remember which library names are inherited from C and which are unique to C++.
knowing and/or changing the characteristics of a character
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xsWrr8yJ-1606907867733)(C:\Users\SDA10\AppData\Roaming\Typora\typora-user-images\image-20201122111026806.png)]
gain access to the characters
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.
- The result of using an index outside this range is undefined. One way to simplify code that uses subscripts is always to use a variable of type string::size_type as the subscript. Because that type is unsigned, we ensure that the subscript cannot be less than zero. So when we use asize_type value as the subscript, we need to check only that our subscript is less than value returned by size().
-
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 */
- Whenever we use a subscript, we should think about how we know that it is in range. In this program, our subscript, n, is a string::size_type, which as we know is an unsigned type. As a result, we know that n is guaranteed to be greater than or equal to 0. Before we use n to subscript hexdigits, we only verify that it is less than the size of hexdigits.
-
3.3. Library vector Type
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 type whose objects hold a collection of objects of a given type.
-
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?
- When we use a template, we specify what kind of class or function we want the compiler to instantiate.We supply it inside a pair of angle brackets<> following the template’s name.
-
C++ has both class and function templates.
class template?
-
blueprint from which specific class types can be created.
How to use it?
- To use a class template, we must specify additional information. For example, to define a vector, we specify the element type: vector holds ints.
-
-
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 <vector>
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.
- We can define vectors to hold objects of most any type.
- Because references are not objects, we cannot have a vector of references.
- we can have vectors of most other (nonreference) built-in types and most class types. In particular, we can have vectors whose elements are themselves vectors.
- We can define vectors to hold objects of most any type.
-
vector<int> ivec; // ivec holds objects of type int vector<Sales_item> Sales_vec; // holds Sales_items vector<vector<string>> file; // vector whose elements are vectors //Some compilers may require the old-style declarations for a vector of vectors,like vector<vector<int> >. //in this example, the compiler generates three distinct types from the vector template: vector<int>, vector<Sales_item>, and vector<vector<string>>
3.3.1. Defining and Initializing vectors
As with any class type, the vector template controls how we define and initialize vectors.
How to initialize vectors?
-
default initialize
-
vector<string> 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<int> ivec; // initially empty // give ivec some values vector<int> ivec2(ivec); // copy elements of ivec into ivec2 vector<int> ivec3 = ivec; // copy elements of ivec into ivec3 vector<string> 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<string> 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<int> ivec(10, -1); // ten int elements, each initialized to -1 vector<string> 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<int> ivec(10); // ten elements, each initialized to 0 vector<string> 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<int> vi = 10; // error: copy form of initialization //must use direct initialization to supply asize vector<int> vi {10};//not Value Initialization
We specify which initialization we intend with direct initialization by whether we use curly braces or parentheses:
-
vector<int> v1(10); // v1 has ten elements with value 0 vector<int> v2{10}; // v2 has one element with value 10 vector<int> v3(10, 1); // v3 has ten elements with value 1 vector<int> 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<string> v5{"hi"}; // list initialization: v5 has one element vector<string> v6("hi"); // error: can't construct a vector from a string literal vector<string> v7{10}; // v7 has ten default-initialized elements vector<string> 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.
- Initializer provided as part of the declaration of a class data member. In-class initializers must follow an = symbol or be enclosed inside 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<string> v1{"a", "an", "the"}; // list initialization vector<string> v2("a", "an", "the"); // error
-
3.3.2. Adding Elements to a vector
Directly initializing the elements is suitable for?
as long as it is limited:
- we have a small number of known initial values
- we want to make a copy of another vector
- we want to initialize all the elements to the same value
Directly initializing the elements problems?
it is not limited:
- we don’t know how many elements we’ll need X
- don’t know value of elements. X
- number of different initial element values large X
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<int> 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<int> 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<string> text; // empty vector while (cin >> word) { text.push_back(word); // append word to text }
Usually used method of defining and initialize vector?
- Apart from solving the problems, If differing element values are needed, it is usually more efficient to define an empty vector and add elements as the values we need become known at run time.
- Because vectors grow efficiently, it is often unnecessary and can result in poorer performance to define a vector of a specific size(meaning initialization). The exception to this rule is if all the elements actually need the same value.
- Starting with an empty vector and adding elements at run time is distinctly different from how we use built-in arrays in C and in most other languages.
3.3.3. Other vector Operations
vector Operations includes?
-
In addition to push_back, there are:
-
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<int>::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<int> 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<unsigned> 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?
- same as that in string
- must be the same type
- But we can only compare two vectors only if we can compare the elements in those vectors. Some class types, such as string, define the meaning of the equality and relational operators but others not.
3.4. Iterators
What is iterators?
- A type used to access and navigate among the objects element in a container or character in a string.(like subscripts, but few of the library containers support subscripts)
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.
3.4.1. Using Iterators
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?
- Member of string and vector that returns an iterator to the first element.
- free-standing library function that takes an array and returns a pointer to the first element in the array.
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:
- The iterator returned by end that refers to a nonexistent element one past the end of a container.
-
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)
- compatible. all of the library containers have iterators that define the == and != operators. Most of those iterators do not have the < operator. By routinely using iterators and !=, we don’t have to worry about the precise type of container we’re processing.
Iterator Types are?
-
the library types that have iterators define types named iterator and const_iterator that represent actual iterator types.
-
vector<int>::iterator it; // it can read and write vector<int> elements string::iterator it2; // it2 can read and write characters in a string vector<int>::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.
- If a vector or string is const, we may use only its const_iterator type.
-
With a nonconst vector or string, we can use either iterator or const_iterator(by the method below).
-
vector<int> v; const vector<int> cv; auto it1 = v.begin(); // it1 has type vector<int>::iterator auto it2 = cv.begin(); // it2 has type vector<int>::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<int>::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
- Arrow operator. Combines the operations of dereference and dot operators: a->b is a synonym for (*a).b.
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.
3.4.2. Iterator Arithmetic
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.
-
They are described in Table 3.7.
-
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.
- The result type is a signed integral type named difference_type. Both vector and string define difference_type.
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<string> 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
}
3.5. Arrays
What is arrays?
- An array is a compound type/data structure/container of unnamed objects of a single type that we access by position with fixed size.
What does fix size influence arrays?
- sometimes offer better run-time performance for specialized applications.
- it lose flexibility
3.5.1. Defining and Initializing Built-in Arrays
How to define arrays?
-
declarator: a[d]
- a is the name being defined
- d is the dimension of the array(>0)
-
base type:
- When we define an array, we must specify a type for the array.
- We cannot use auto to deduce the type from a list of initializers.
- arrays hold objects. Thus, there are no arrays of references.
- number of elements in an array is part of the array’s type, so the dimension must be a constant expression (it must be known at compile time -y??)
-
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
- But As with variables of built-in type, a default-initialized array of built-in type that is defined inside a function(local scope)will have undefined values.
-
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.
pointers, references & arrays
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.
3.5.2. Accessing the Elements of an Array
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.
- Using a range for means that we don’t have to manage the traversal ourselves.
- the subscript operator is the one that is defined as part of the language. This operator can be used on operands of array type. The subscript operator used in vector was defined by the library vector template and applies to operands of type vector.)
**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?
- Machine-dependent unsigned integral type defined in the cstddef header (C++ version of the stddef.h header from the C library.) that is large enough to hold the size of the largest possible array.
- …like size_type?
3.5.3. Pointers and Arrays
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:
- In most places when we use an array(array name), the compiler automatically substitutes a pointer to the first element
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
- Machine-dependent signed integral type defined in the cstddef header that is large enough to hold the difference between two pointers into the largest possible array.
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?
- To do so, the new library includes two functions, named begin and end like the similarly named container members
- these functions are not member functions.
- These functions are defined in the iterator header.
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]
- parentheses are required
-
3.5.4. C-Style Character Strings
What is C-style character strings?
- Null-terminated(String whose last character is followed by the null character (’\0’).)character array. e.g. string literals are C-style strings.
- C-style strings are not a type. Instead, they are a convention for how to represent and use character strings.
- C-style strings are inherently error-prone. For most applications, in addition to being safer, it is also more efficient to use library strings rather than C-style strings.(like concatenating )
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?
- pointers
- C Library String Functions. These functions are defined in the cstring header, which is the C++ version of the C header string.h.
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<int> ivec(begin(int_arr), end(int_arr));
// copies three elements: int_arr[1], int_arr[2], int_arr[3]
vector<int> 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.
3.6. Multidimensional Arrays
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?
- In a two-dimensional array, the first dimension is usually referred to as the row and the second as the column.
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
- ia[2] returns the last row in ia. It does not fetch an element from that array but returns the array itself. We subscript that array, fetching element [3],which is the last element in that array.
Similarly, the right-hand operand has three dimensions. We first fetch the array at index 0 from the outermost array. The result of that operation is a (multidimensional) array of size 20. We take the first element from that 20-element array, yielding an array of size 30. We then fetch the first element from that array. - In the second example, we define row as a reference to an array of four ints. We bind that reference to the second row in ia.
- ia[2] returns the last row in ia. It does not fetch an element from that array but returns the array itself. We subscript that array, fetching element [3],which is the last element in that array.
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.
- To use a multidimensional array range for, all the loop control variable but the innermost array must be references.(array name cannot be totally replaced by pointer, using reference it is using array name so it can work out)
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; }