C++ Primer 读书笔记2

1 Reada set of integers into a vector. Print the sum of each pair of adjacent elements.Change your program so that it prints the sum of the first and last elements,followed by the sum of the second and second-to- last, and so on.

        vector<int> ivect;
	int value;

	while (cin >> value)
	{
		ivect.push_back(value);
	}
	for (decltype(ivect.size()) idx = 0; idx < ivect.size() - 1; idx += 2)
	{
		cout << ivect[idx] + ivect[idx + 1] << endl;
	}
	if (ivect.size() % 2 == 1)
		cout << ivect[ivect.size() - 1] << endl;

	//用迭代器实现
	vector<int> ivect;
	int value;

	while (cin >> value)
	{
		ivect.push_back(value);
	}
	auto iter = ivect.begin();
	for (; (iter != ivect.end()) && ((iter + 1) != ivect.end()); iter += 2)
	{
		cout << *iter + *(iter + 1) << " ";
	}
	if (iter != ivect.end())
	{
		cout << *iter << endl;
	}

	vector<int> ivect;
	int value;

	while (cin >> value)
	{
		ivect.push_back(value);
	}
	decltype(ivect.size()) i = 0, j = ivect.size() - 1;
	for (; i < j; ++i, --j)
	{
		cout << ivect[i] + ivect[j] << endl;
	}
	if (i == j)
	{
		cout << ivect[i] << endl;
	}

	//用迭代器实现
	vector<int> ivect;
	int value;

	while (cin >> value)
	{
		ivect.push_back(value);
	}
	auto ibegin = ivect.begin(), iend = ivect.end() - 1;
	for (; ibegin < iend; ++ ibegin, -- iend)
	{
		cout << *ibegin + *iend << " ";
	}
	if (ibegin == iend)
	{
		cout << *ibegin << endl;
	}

2 Allof the library containers have iterators, but only a few of them support thesubscript operator. C++ programmers use != as a matter of habit. They do so forthe same reason that they use iterators rather than subscripts: This codingstyle applies equally
well to various kinds of containers provided by thelibrary. As we’ve seen, only a few library types, vector and string being amongthem, have the subscript operator. Similarly, all of the library containershave iterators that define the == and != operators.
Most of those iterators donot have the < operator. By routinely using iterators and !=, we don’t haveto worry about the precise type of container we’re processing.

3 Thetype returned by begin and end depends on whether the object on which theyoperator is const. If the object is const, then begin and end return aconst_iterator; if the object is not const, they return iterator:

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

auto it3 = v.cbegin(); // it3 has type vector<int>::const_iterator

As do the begin and end members, thesemembers return iterators to the first and one past the last element in thecontainer. However, regardless of whether the vector (or string) is const, theyreturn a const_iterator.

4 Asa result, the dimension must be known at compile time, which means that thedimension must be a constant expression:

unsigned cnt = 42;          // not a constant expression
constexpr unsigned sz = 42; // constant expression
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

When we define an array, we must specify atype for the array. We cannot use auto to deduce the type from a list ofinitializers. As with vector, arrays hold objects. Thus, there are no arrays ofreferences.

5 Whenwe use a variable to subscript an array, we normally should define thatvariable to have type size_t. size_t is a machine-specific unsigned type thatis guaranteed to be large enough to hold the size of any object in memory. Thesize_t type is defined in
the cstddef header, which is the C++ version of thestddef.h header from the C library.

6

string nums[] = {"one", "two", "three"};  // array of strings
string *p = &nums[0];   // p points to the first element in nums
string *p2 = nums;      // equivalent to p2 = &nums[0]

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
auto ia2(&ia[0]);  // now it's clear that ia2 has type int*

// 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
7 int ia[] = {0,2,4,6,8};  // array with 5 elements of type int
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
int *p = ia;    // p points to the first element in ia
i = *(p + 2);   // equivalent to i = ia[2]
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]

Unlike subscripts for vector and string,the index of the built-in subscript operator is not an unsigned type.

7

string s1 = "A string example";
string s2 = "A different string";
if (s1 < s2)  // false: s2 is less than s1

const char ca1[] = "A string example";
const char ca2[] = "A different string";
if (ca1 < ca2)  // undefined: compares two unrelated addresses

For most applications, in addition to beingsafer, it is also more efficient to use library strings rather than C-stylestrings.

8

string s("Hello World");  // s holds Hello World
char *str = s; // error: can't initialize a char* from a string
const char *str = s.c_str(); // ok

The array returned by c_str is notguaranteed to be valid indefinitely. Any subsequent use of s that might changethe value of s can invalidate this array.

If a program needs continuing access to thecontents of the array returned by str(), the program must copy the arrayreturned by c_str.

Advice:Modern C++ programs should use vectors anditerators instead of built-in arrays and pointers, and use strings rather thanC-style array-based character strings.

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;
}
}
《==》
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
}

In the previous example, we used referencesas our loop control variables because we wanted to change the elements in thearray. However, there is a deeper reason for using references. As an example,consider the following loop:

for (const auto &row : ia)  // for every element in the outer array
for (auto col : row)    // for every element in the inner array
        cout << col << endl;

This loop does not write to the elements,yet we still define the control variable of the outer loop as a reference. Wedo so in order to avoid the normal array to pointer conversion.

Note: To use a multidimensional array in a range for, the loop controlvariable for all but the innermost array must be references.

10 Exercise 3.43: Write three different versions of a program toprint the elements of ia. One version should use a range for to manage theiteration, the other two should use an ordinary for loop in one case usingsubscripts and in the other
using pointers. In all three programs write all thetypes directly. That is, do not use a type alias, auto, or decltype to simplifythe code.

Exercise 3.44: Rewrite the programs fromthe previous exercises using a type alias for the type of the loop controlvariables.

Exercise 3.45: Rewrite the programsagain, this time using auto.

	const size_t row = 3;
	const size_t col = 4;
	int arr[row][col];
	int cnt = 0;

	//版本1
	for (int(&p)[4] : arr)
	{
		for (int &q : p)
		{
			q = cnt++;
		}
	}
	for (int(&p)[4] : arr)
	{
		for (int q : p)
		{
			cout << q << " ";
		}
		cout << endl;
	}
	cout << endl;

	//版本2
	for (size_t i = 0; i != row; ++i)
		for (size_t j = 0; j != col; ++j)
			arr[i][j] = i * 4 + j;

	for (size_t i = 0; i != row; ++i)
	{
		for (size_t j = 0; j != col; ++j)
		{
			cout << arr[i][j] << " ";
		}
		cout << endl;
	}

	//版本3
	for (int(*p)[4] = arr; p != arr + 3; ++p)
	{
		for (int *q = *p; q != *p + 4; ++q)
		{
			*q = cnt++;
		}
	}

	for (int(*p)[4] = arr; p != arr + 3; ++p)
	{
		for (int *q = *p; q != *p + 4; ++q)
		{
			cout << *q << " ";
		}
		cout << endl;
	}

	//练习3.44
	using int_arr = int[4];
	for (int_arr *p = arr; p != arr + 3; ++p)
	{
		for (int *q = *p; q != *p + 4; ++q)
		{
			*q = cnt++;
		}
	}

	for (int_arr *p = arr; p != arr + 3; ++p)
	{
		for (int *q = *p; q != *p + 4; ++q)
		{
			cout << *q << " ";
		}
		cout << endl;
	}

	//练习3.45
	for (auto &p : arr)
		for (auto &q : p)
			q = cnt++;

	for (auto &p: arr)
	{
		for (auto& q : p)
		{
			cout << q << " ";
		}
		cout << endl;
	}

11 Roughly speaking, when we use an object asan rvalue, we use the object’s value (its contents). When we use an object asan lvalue, we use the object’s identity (its location in memory).

Lvalues and rvalues also differ when usedwith decltype. When we apply decltype to an expression (other than a variable),the result is a reference type if the expression yields an lvalue. As anexample, assume p is an int*. Because dereference yields an lvalue,decltype(*p)
is int&. On the other hand, because the address-of operatoryields an rvalue, decltype(&p) is int**, that is, a pointer to a pointer totype int.&Pg121

12 Moreover,except for the obscure case where -m overflows, (-m)/n and m/(-n) are alwaysequal to -(m/n).

13

//  note s as a reference to const; the elements aren't copied and can't be changed
for (const auto &s : text) { // for each element in text
cout << s;        // print the current element
// blank lines and those that end with a period get a newline
    if (s.empty() || s[s.size() - 1] == '.')
        cout << endl;
    else
        cout << " ";  // otherwise just separate with a space
}

14

// the behavior of the following loop is undefined!
while (beg != s.end() && !isspace(*beg))
*beg = toupper(*beg++);   // error: this assignment is undefined
时间: 2024-08-23 22:59:54

C++ Primer 读书笔记2的相关文章

C++primer读书笔记11-多态

多态也是C++中的一个重要的方面,多态和动态类型,虚函数本质上是指相同的事情. 1 虚函数 类中的成员函数原型前面加上virtual 表面这个函数是个虚函数.虚函数的目的是为了在继承它的派生类中重新定义这个函数,以便于通过基类的指针或引用在运行时对派生类的函数进行调用. 2 派生类和虚函数 派生类一般情况下要重定义所继承的虚函数,有几个注意事项. <1>虚函数的声明必须和基类中的函数声明原型完全一致,例外的是当基类返回基类型的指针或者引用的时候,派生类可以派生类类型的指针或者引用 <2&

C++中的volatile(Primer读书笔记)

时间:2014.05.24 地点:基地 -------------------------------------------------------------------------- 一.简述 volatile限定符平时很少用到,今天倒是碰到了,所幸探个明白.volatile 英文字面意思是"不稳定的",确切的计算机含义时与机器相关,所以在对包含volatile的程序在移植到新机器或使用不同的编译器时往往还需要对编译器进行一些改变. -----------------------

C++ primer读书笔记10-继承

封装,继承,多态是C++的三大基本概念,这里着重总结一下继承相关的东西 1 类派生列表 类派生列表指定派生类要继承的基类,派生列表中有一个或者多个基类如: class B : public A1,protected A2,private A3 但是单继承时最常见的,多继承不多见 2 派生类的定义 派生类继承时,会包含父类的所有成员,即便私有成员不能被访问.父类中的虚函数,在派生类中一般也要定义,如 果不定义的话,派生类将继承基类的虚函数 3 基类必须是已经定义的 一个仅仅声明的类,是不能出现在派

C++primer读书笔记9转换与类类型

有时候指定了自己类类型来表示某种类型数据如SmallInt,那么为了方便计算就会指定一个转换操作符,将该类类型在某种情况下自动的转换为指定的类型 <1>转换操作符 operator type(); 转换函数必须是类成员函数,不能指定返回类型,并且形参列表必须为空,并且通常不应该改变转换对象,所以操作符通常定义为const成员. #include <iostream> using namespace std; class SmallInt { public: SmallInt(int

C++ Primer 读书笔记整理(一)

1.读取数量不定的输入数据时可以把cin语句放到条件判断语句中,如果流的状态有效则读取成功,否则读取失败. 例如: while(cin>>value) /* do something */ 2.顶层const与底层const的区别 1)顶层const表示任意的对象是const(即常量) 例如: const int value = 0; // i是顶层const常量 int i= 0; int *const ptr = &i; //ptr是顶层const常量 2)底层const一般用在引

c++ primer读书笔记之c++11(二)

1 新的STL模板类型,std::initializer_list<T> c++11添加了initializer_list模板类型,用于提供参数是同类型情况的可变长度的参数传递机制,头文件是<initializer_list>. 其具体接口可参考cplusplus.com的介绍,地址如下:http://www.cplusplus.com/reference/initializer_list/initializer_list/?kw=initializer_list 与vector不

c++ primer读书笔记之c++11(四)

1  带有作用域的枚举 scoped-enumeration 相信大家都用过枚举量,都是不带有作用域的,在头文件中定义需要特别注意不要出现重名的情况.为了解决这种问题,c++11提供了带作用于的枚举.可以使用class EnumName定义,示例代码如下: enum {ZERO, ONE, TWO}; enum class color {RED, BLUE, GREEN}; 上面的是没有作用域的枚举定义形式,下面是带有作用域的枚举定义形式,调用带有作用域的枚举必须指定作用域,否则会编译出错. 还

c++ primer读书笔记之c++11(三)

1 =default构造函数限定符 c++11针对构造函数提供了=default限定符,可以用于显式指定编译器自动生成特定的构造函数.析构或赋值运算函数.参考代码如下: class CtorDftType { public: CtorDftType()=default; CtorDftType(const CtorDftType&)=default; CtorDftType & operator = (const CtorDftType &)=default; ~CtorDftTy

函数(C++ Primer读书笔记)

C++ Primer 第五版课后题 练习6.32 :下面的函数合法吗?如果合法,说明其功能:如果不合法,修改其中的错误并解释原因. #include <iostream> using namespace std; int &get(int *arry, int index) { return arry[index]; } int main() { int ia[10]; for (int i = 0; i != 10; ++i) get(ia, i) = i; return 0; }

c++ primer读书笔记之c++11(一)

1 新的关键词nullptr c++11引入新的关键词nullptr,用于表示空指针,用于替换之前c提供的NULL(最初NULL是定义在stdlib中的宏定义,通常是0). 2 新的别名定义机制 alias declaration c++提供了使用typedef定义的别名机制,但是有时候很难理解.为了更好的使用别名机制,c++11提供了新的别名定义机制,类似代码如下: // alias declarations using VInt = int; // type alias using PInt