C++自修入門實境秀、C++ Primer 5版研讀秀 19/ 陣列與指標之算術操作~3.5.4. C-Style Character Stri...





Pointers Are Iterators 指標是迭代器(iterator)

In particular, pointers to array elements support the same operations as iterators on vector s or string s (§ 3.4 , p. 106 ).

迭代器(iterator)能做的,指標指針也能做

3:00

就跟指標一樣,我們可以對一個迭代器進行解參考(dereference)來取得一個迭代器所代表 的元素。此外,就像指標,我們能夠解參考的,只有代表了一個元素的有效迭代器(§2.3.2)。 解參考一個無效的迭代器或off-the-end迭代器會有未定義的行為。(頁107)



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]

用陣列給一個指標初始化,就是將陣列的第一個元素的位址(address)給該指標當作初始值



Just as we can use iterators to traverse the elements in a vector , we can use pointers to traverse the elements in an array.

可見traverse和迭代(iterate)仍然是一個意思

9:10

12:00

We can obtain an off-the-end pointer by using another special property of arrays.

前面有尾端後迭代器(off-the-end iterator),這裡是尾端後指標指針(off-the-end pointer)

陣列的性質(property)還真多,還special的咧!

We can obtain an off-the-end pointer by using another special property of arrays. We can take the address of the nonexistent element one past the last element of an array:

Click here to view code image

int *e = &arr[10]; // pointer just past the last element in arr

16:00 難怪,我們當初在測試練習3.30時超出一個索引值竟然沒有錯誤出現,要出迴圈後,Visual Studio才會顯示錯誤!原來就是因為指標可以指向一個尾端後的「不存在的元素」

Exercise 3.30: Identify the indexing errors in the following code:

Click here to view code image

constexpr size_t array_size = 10;

int ia[array_size];

for (size_t ix = 1; ix <= array_size; ++ix)

ia[ix] = ix;



int ia[] = { 0,1,2,3,4,5, 6,7,8,9 };

auto *pia(ia);

auto* piae(&ia[10]);

for (auto pia(ia) ; pia !=piae; ++pia)

{

cout << *pia << " ";

}

cout << endl;

auto很像C#中的var



33:00

27:40

The Library begin and end Functions

34:10為了要更方便且安全地使用指標指針(pointer),新的C++標準程式庫納入了兩個begin與end函式

這兩個函式的行為能力和容器中的begin、end兩個成員函式是一樣的

However, arrays are not class types, so these functions are not member functions.

因為陣列不是類別型別,所以這兩個函式並不算是成員函式。

陣列不是類別型別而是一種資料結構

三種:

1.資料結構 array struct

2.類別型別(class type) struct

3.模板型別(template type) vector



和容器的begin、end不帶引數不同,程式庫的這兩個函式是要帶一個陣列作引數

看要取得哪個陣列的begin 和 end 就傳那個陣列作引數給begin和end這兩個函式

頁119

53:00

These functions are defined in the iterator header.

可見要用此二函式,得#include<iterator>先才行

然而我們這樣寫也沒用,反而要像下列黃色塊處:

#include <iostream>

//#include<iterator>

using namespace std;

//using std::cout; using std::cin;using std::endl;



void test() {

int ia[] = { 0,1,2,3,4,5, 6,7,8,9 };

auto *pia(begin(ia));

auto* piae(end(ia));

for (pia ; pia !=piae; ++pia)

{

cout << *pia << " ";

}

cout << endl;

}

note

1:11:50

Pointer Arithmetic

1:13:50

address 定址

1:27:00

頁120

1:29:35

auto n = end (arr) - begin (arr); // n 為 5,即 arr 中元素的數目

1:38:00

The result of subtracting two pointers is a library type named ptrdiff_t. Like size_t, the ptrdiff_t type is a machine-specific type and is defined in the cstddef header.

機器特定型別(machine-specific type)

cstddef ①斷句

c.std.def 1:44:30

typedef int ptrdiff_t;

ptrdiff_t也不過是int的別名

std::ptrdiff_t is the signed integer type of the result of subtracting two pointers. https://en.cppreference.com/w/cpp/types/ptrdiff_t

1:50:00 對陣列指針作關係運算

2:53:00 對二個不相干的指標作關係運算是沒有意義的

2:59:00 非陣列指標要做算術運算也應該是指向同一個非陣列物件(或那個物件後的一個位置)的數個指標來故計算,而不是指向不同物件的指標來做運算。對指向不同物件的指標做的運算,就是上述的不相干、無意義的。

3:5:20

Interaction between Dereference and Pointer Arithmetic

3:11:00

int arr[] = { 0,1,2,3,4,15 };

int last = *(arr + 5);

直接對arr做運算,即是對arr的第一個元素的指標做運算:

As we’ve seen, in most places when we use the name of an array, we are really using a pointer to the first element in that array.

(arr + 5)結果型別是指標int*

所以對一個陣列的解參考(dereference),也就是對它第一個元素的指標作解參考,其結果就是該元素的值。

last = *ia + 4; // ok:last = 4,等同於 ia[0] + 4



頁121

3:19:55

Subscripts and Pointers



int i = ia[2]; // ia is converted to a pointer to the first element in ia

// ia[2] fetches the element to which (ia + 2) points

所以陣列名一出現的地方,實際上編譯器是先將該陣列轉成對該陣列第一元素的指標,然後再對其進行運算;在做下標(subscript)運算時,當然也是如此。因此,諸如ia[2],這樣的表示,在編譯器看來就是先將ia轉成對ia第一元素的指標,然後再對此指標進行下標(指定它往後移動2個位置)

3:32:00

只要一個指標是一個有效的指向某個陣列元素的指標,就可以對該指標做下標(subscript)運算,對它的下標運算,就好像對該陣列做下標一樣,因為對一個陣列做運算實際上就是對該陣列的第一元素做運算也。

下標在此的意義就是對該指標進行位移的指定。

3:41:20

程式庫型別(library type)vector string 下標值不可能是負的,但陣列(其元素之指標下標值)卻可以

The library types force the index used with a subscript to be an unsigned value.

3:42:59

練習3.34

int arr[] = { 0,1,2,3,4,15 };

int* p1;

int* p2;

for (size_t i = 0; i < 7; i++)// 7=sizeof(arr) / sizeof(*arr)+1

{

p1=&arr[i];

for (size_t j = 0; j < 7; j++)

{

p2= &arr[j] ;

p1 += p2 - p1;// is equivalent to

//p1=p1+(p2-p1);

/*兩個指標相減就是ptrdiff_t型別的位移值

而這個位移值是再加到p1本身去的*/

cout << *p1 << endl;

}

}

//int* p1{ &arr[2] }, * p2{&arr[2]};





if (p1!=p2)

{

p1 = p2;

}

最後結果p1都是等於p2,且沒有不合法的結果,只要p1、p2給定的值都是合法的

練習3.35

4:37:58

int arr[] = { 0,1,2,3,4,15 };

int* p = arr, * e{end(arr)};

for (auto i : arr)

cout << i << " ";

cout << endl;

while (p<e)

{

*p = 0;

++p ;

}

for (auto i : arr)

cout << i << " ";

cout << endl;

練習3.36

4:45:40

int arr[] = { 0,1,2,3,4,15 };

int arr1[] = { 0,1,2,3,4,15 };

size_t sz = sizeof(arr) / sizeof(*arr);

for (size_t i = 0; i <sz ;++i){

if (arr[i]!=arr1[i])

{

return;

}

}

cout << "arr and arr1 are equal" << endl;

改寫成vector的: 4:53:52

vector<int> arr{ 0,11,2,3,4,15 };

vector<int> arr1{ 0,11,2,3,4,15 };

size_t sz = arr.size();

for (size_t i = 0; i <sz ;++i){

if (arr[i]!=arr1[i])

{

cout << "arr and arr1 are NOT equal" << endl;

return;

}

}

cout << "arr and arr1 are equal" << endl;

頁122

3.5.4. C-Style Character Strings

留言

熱門文章