namespace::成员
的形式以外,还可以通过 using 指令来指定命名空间甚至是命名空间中的具体成员 。格式分别如下:using namespace::name; //这是指定命名空间内的具体成员
using namespace; //这是只指定命名空间
namespace::
即可使用。string s1; //默认初始化,s1 是个空字符串
string s2{ "ss" }; //s2 是字面值 "ss" 除了最后的空字以外的副本
string s3(s1); //s3 是 s1 的副本
string s4 = s1; //s4 是 s1 的副本
string s5("ss"); //s5 是字面值 "ss" 除了最后的空字以外的副本
string s6 = "ss"; //s6 是字面值 "ss" 除了最后的空字以外的副本
string s7 = ("ss"); //s7 是字面值 "ss" 除了最后的空字以外的副本
string s8 = { "ss" }; //s8 是字面值 "ss" 除了最后的空字以外的副本
string s9 (n, 'c'); //使用 n 个连续的 'c' 字符组成的字符串初始化 s9
string a = string(10, 's');
其本质等价于:
string temp (10,'c');
string a = temp;
os << s //将 s 写到输入流 os 中,并返回 os
is >> s // 将 is 输入流中读取一个字符串赋值给 string 对象 s ,该字符串在第一、二处空白之间,最后返回 is
getline(is, s) // 从 is 中读取一行字符串赋值给 s ,字符串以换行符为结尾
s.empty() // s 为空字符串返回 true ,否则返回 false
s.size() // 返回 string 对象内的字符个数
s[n] // 返回 s 中第 n+1 个字符的引用,n 从0开始
s1+s2 // 两个 string 对象相连,返回一个更长的 string
s1=s2 // 拷贝 s2 的值,然后赋值给 s1
s1==s2 // 判断两 string 对象是否完全相同。完全相同:长度相等,字符相同
s1!=s2 // 判断两 string 对象是否不相同
<,<=,>,>= // ①首先判断,谁长就谁大 ②如果一样长,按字典alphabet顺序排序
string a,b,c;
cin >> a >> b >> c;
cout << a << b << c;
s.empty()
。
- 如果两个 string 对象的长度不同,而且两个 string 对象相同位置上的字符相同,则较短的 string 对象小于较长 string 对象。
- 如果两个 string 对象在某些位置上不同,则 string 对象比较的结果其实就是 string 对象中第一对不同字符比较的结果(字符比较是指编码值的比较)。
s1 = s2 ;
。函数 | 作用 |
---|---|
isalnum( c ) | 当 c 是字母或数字时,返回 true ,否则返回 false |
isalpha( c ) | 当 c 是字母时,返回 true ,否则返回 false |
iscntrl( c ) | 当 c 是控制字符时,返回 true ,否则返回 false |
isdigit( c ) | 当 c 是数字时,返回 true ,否则返回 false |
isgraph( c ) | 当 c 不是空格但可以打印时,返回 true ,否则返回 false |
islower( c ) | 当 c 是小写字母时,返回 true ,否则返回 false |
isprint( c ) | 当 c 是可打印字符时,返回 true ,否则返回 false |
ispunct( c ) | 当 c 是标点符号时(即 c 不是控制字符、数字、字母、可打印空白中的一种),返回 true ,否则返回 false |
isspace( c ) | 当 c 是空白时,返回 true ,否则返回 false |
isupper( c ) | 当 c 是大写字母时,返回 true ,否则返回 false |
isxdigit( c ) | 当 c 是十六进制数字时,返回 true ,否则返回 false |
tolower(c ) | 如果 c 是大写字母,则返回对应的小写字母,否则原样输出 |
toupper( c ) | 如果 c 是小写字母,则返回对应的大写字母,否则原样输出 |
for (declaration : expression)
statement
其中 expression 部分是一个对象,用于表示一个序列。 declaration 部分负责定义一个变量,它将被用于访问序列中的元素, 确保类型相融最简单的方法是使用 auto 类型说明符。
注意:
- 每次迭代 , decvlaration 部分的变量会被初始化为 expression 部分的下一个元素值。
- 如果想通过 range for 修改对象内的值,就得将 range for 的变量声明为引用类型 。
- range for 语句不能修改序列的长度
int n[] = {2,3,4,5,6,7,8,9,0};
for (auto &nn : n)
{
nn += nn;
}
vector<int> in1;
vector<string> s1;
vector<vector<string>> vecs1; //元素类型为 vector 对象
vector<vector<int> > a;
vector<T> v1; //v1 是一个空 vector 对象,潜在的元素是 T 类型,执行默认初始化。
vector<T> v2(v1); //v2 包含 v1 的全部副本
vector<T> v3 = v1; //等价于上条语句
vector<T> v4(n, val); //v4 包含了 n 个重复的元素,每个元素值为 val
vector<T> v5(n); //v5 包含了 n 个重复的元素,每个元素都执行了默认初始化
vector<T> v6{a,b,c......} //v6 包含了初始值个数的元素,每个元素都被赋予了相应的初始值
vector<T> v7 = {a,b,c......} //与上条语句等价
vector v1;
的方式默认初始化 vector 对象,从而创建一个指定类型的空 vector 。vector<T> vv(n, val); //正确
vector<T> vvss = (n, val); //错误
{}
)进行直接初始化(不能用 = ) 。vector<string> s1{"正确"};
vector<string> s2("错误"); //报错
vector<string> s3{10}; //只指定元素数量直接初始化
vector<string> s4{10, "正确,指定元素值和数量直接初始化"};
vector<string> s5 = {10, "正确,指定元素值和数量拷贝初始化"};
v.empty() 检查 v 是否为空,是返回 true ,否返回 false
v.size() 返回 v 中元素个数,返回值类型为头文件 vector 里定义的 size_type 类型
v.push_back() 向 v 的结尾添加元素
v.[n] 返回 v 中第 n+1 个元素的引用,注意是引用
v1 = v2 将 v2 的值拷贝到 v1 中
v1 = {a,b,c......} 用列表中的元素进行赋值,不是添加
v1 == v2 判断两 vector 对象的元素数量和对应元素是否都相同
v1 != v2 判断两 vector 对象的元素数量和对应元素是否有不同
> 、 < 、 >= 、 <= 按字典顺序比较
- 如果两个 vector 对象的长度不同,而且两个 vector 对象相同位置上的值相同,则较短的 vector 对象小于较长 vector 对象。
- 如果两个 vector 对象在某些位置上不同,则 vector 对象比较的结果其实就是 vector 对象中第一对不同值比较的结果(。
如果容器或 string 对象为空,则成员函数 begin 和 end 返回的迭代器是 同一个迭代器 。
*iter 返回迭代器 iter 所指元素的引用
iter -> mem 解引用迭代器 iter 并获取该元素的名为 mem 元素的成员,等价于 (*iter).mem
++iter 令迭代器 iter 指向容器或 string 对象的下一个元素
iter++ 令迭代器 iter 指向容器或 string 对象的下一个元素
--iter 令迭代器 iter 指向容器或 string 对象的上一个元素
iter-- 令迭代器 iter 指向容器或 string 对象的上一个元素
iter1 == iter1 判断两个迭代器是否相等(或不相等)
iter1 != iter2 如果两个迭代器指向同一个容器或同一 string 对象的相同元素,或它们是同一个容器或同一 string 对象的尾后迭代器,则相同。
vector<int>::iterator it1; //定义一个 iterator 类型的迭代器 it1 ,指向 vector 对象
string::iterator it2; //定义一个 iterator 类型的迭代器 it2 ,指向 string 对象
auto it3 = a.begin(); //定义一个 iterator 类型的迭代器 it3 ,指向 a 的第一个元素
vector<int>::const_iterator it4; //定义一个 const_iterator 类型的迭代器 it4 ,指向 vector 对象
string::const_iterator it5; //定义一个 const_iterator 类型的迭代器 it5 ,指向 string 对象
iter + n 迭代器加上一个整数的结果是一个迭代器。迭代器指向的元素位置与原来相比向后移动 n 个元素。
iter - n 迭代器减去一个整数的结果是一个迭代器。迭代器指向的元素位置与原来相比向前移动 n 个元素。
iter += n 迭代器加法的复合赋值语句
iter -= n 迭代器减法的复合赋值语句
iter1 - iter2 相减的前提是指向同一个容器对象或 string 对象的元素,或者指向同一个容器对象或 string 对象的尾元素的下一位。两个迭代器相减的结果是它们之间的距离。
< 、 > 、 <= 、 >= 迭代器的比较,如果两个迭代器所指向的位置,越靠前的越小。前提是指向同一个容器对象或 string 对象的元素,或者指向同一个容器对象或 string 对象的尾元素的下一位。
mid = beg + (end - beg)/2
,而非 mid = (end + beg)/2
。
- 前者不会产生溢出,而后者可能会。
- 前者适用于对迭代器的操作(迭代器相减),而后者(迭代器相加)不行,这个操作未定义,编译报错。
T a[d]
,其中 T 是存放的数据类型,a 是数组名,d 是数组的维度,也就是元素个数。 d 必须大于 0 。// 下面两种初始化形式是一样的,都是聚合初始化
int a[10] = {1, 2, 3}; //初始化前三个元素,其它被初始化为 int 的默认初始值
int a[10] {1, 2, 3};
由上面的可知, 如果想初始化全部为 0 ,可以使用空的列表初始化:
unsigned scores[11]{};
unsigned scores[11] = {};
char ss[] = "12345"; //一共有6个元素,最后一个为空字符'\0'
a = b;
int *ptrs[10]; // ptrs 是含有10个 int 指针的数组
int &refs[10] = /* ?*/; //错误,不存在引用的数组
int (*Parray)[10] = &arr; // Parray 指向一个含有10个 int 变量的数组
int (&arrRef)[10] = arr; // arrRef 引用一个含有10个 int 变量的数组
int a[10];//此时a的类型为 int[10]
,并不是 int* ,只是有时候可以隐式将其转换成 int *。当初始值为数组名时,使用 auto 推断,返回类型是一个指向数组元素类型的指针。
int scores [10]{};
auto b(scores); // b 的类型为 int * 。
使用 decltype() 推断数组名时,返回的是数组类型和维度与该数组相同的数组类型。
int scores [10]{};
decltype(scores) a; // a 的类型为 int [10] 。
数组名和&数组名 :设数组名为 array ,那么 array 和 &array 的值实际上是相等的,当然是数值相等,而它们代表的含义则是完全不同的: array 的值是数组首元素的地址, &array 的值是一个指向数组的指针;假设 array 是一个 int[10]
类型的数组,那么 array 的类型为 int[10]
, &array 的类型为 int[10]*
,是一个指针
例如有以下计算结果:
容器 vector 和 string 类的迭代器支持的运算,数组的指针全都支持。
尾后指针: 数组尾元素指向的下一个位置,尾后指针不指向具体元素,所以 不能执行解引用或递增操作。
C++11新增了关于数组的函数 begin() 和 end() ,与容器模板和 string 类不同的是,它们为 非成员函数 , 返回值分别是首元素和尾元素下一位置的指针(地址) 。它们定义于头文件 iterator 。
指针比较: 仅当内置指针指向同一对象的成员或同一数组的元素时,才严格定义指向对象的指针的关系比较(用于小于或大于比较),数组下标越高越大。
指针相减的前提是两个指针 指向同一类型对象或数组(维度可以不一样) ,相减的结果的类型是一种名为 ptrdiff_t 的标准库类型。与 size_t 一样定义在 cstddef 头文件,因为结果可能为负值,所以它是一种 带符号整型 ,表示两指针之间差了多少个该类型元素。
虽然指向相同类型不同对象的指针之间可以比较,但是 两个指向不同对象的指针比较一般是没有意义的 。
直接比较两个无关指针(即不指向同一对象或数组)将产生未定义的行为
指针运算使用于 空指针 。
解引用和指针运算的交互: a[4]
等价于 *(a+4)
。
标准库类型限定使用的下标类型必须是无符号类型(也就是不能为负数) ,而 内置类型的下标不作限制 。 比如数组的下标可以处理负值。
int a[4];
int* p = &a[3];
int d = p[-2];
strlen(p) 返回 p 的长度,不包括空字符。
strcmp(p1, p2) 比较 p1 和 p2 是否相等,相等返回 0 ,如果 p1>p2 ,返回一个正值,如果 p1<p2 ,返回一个负值
strcat(p1, p2) 将 p2 附加到 p1 之后,返回 p1
strcpy(p1, p2) 将 p2 拷贝给 p1 ,返回 p1
const char ca1[] = "hanhan";
const char ca2[] = "asasas";
ca1 < ca2 ; //比较的是地址,没有意义
- 允许使用C风格字符串来初始化 string 对象或为 string 对象赋值;
- 标准库允许把字符串字面值和字符字面值转换成 string 对象。当把 string 对象和字符字面值以及字符串字面值混在同一天语句中使用时,必须保证(+)的两个运算对象至少有一个是 string 对象。
- string 对象在使用复合赋值运算符时,右侧运算对象可以是C风格字符串。
const char *a;
a = ss.c_str(); //此时 a 为 "hanhan"
ss = "ss"; //此时 a 为 "ss"
所以最好别像上面代码一样使用 c_str() ,一旦 string 对象被析构,之前 c_str 返回的指针就成了无效指针。
注意:一定要使用 strcpy() 函数等方法操作 c_str() 返回的指针
char a[20];
strcpy(a, ss.c_str()); //此时 a 为 "hanhan"
int a [] = {1,2,3,4};
std::vector<int> aa ( begin(a), end(a) );
用于初始化 vector 对象的值可能也仅仅是数组的一部分。
int b [] = {1,2,3,4,5,6,7};
std::vector<int> bb ( &b[3], &b[5] );
使用 (首地址,尾地址)
和 直接初始化 ,可以使用数组的一部分或整个数组初始化 vector 对象。
int ia [3][4] = {
{1,2,3,4}
{1,2,3,4}
{1,2,3,4}
}
//等价于
int ia [3][4] = {1,2,3,4,1,2,3,4,1,2,3,4}
如果想初始化全部元素为默认初始值 ,可以像下面代码一样定义。这样就不怕是在块内还是在全局作用域了(内置类型在块内不会执行默认初始化)。
int b[4][2][2] = {};
与一维数组一样,无论以什么形式初始化多维数组,只要初始化时未被初始化的元素,就执行默认初始化。
4. 当 数组名含有的下标运算符数量 比数组的第二个维度(几维数组)小,表达的是一个内层数组;一样多,表达的就是一个给定类型的元素。
int a[3][3][3] = {};
int (&aa)[3][3] = a[0]; // aa 是指向 a 内第一个二维数组的引用
int aa[3][3] = {};
for (auto &n : aa)
{
for (auto nn : n)
{
std::cout << nn <<std::endl;
}
}
如果不设置除了最内层外的控制变量为引用,会出现什么情况?——无法通过编译
for (auto n : aa)
for (auto nn : n)
因为 range for 语句中的对象没被声明成引用类型 ,编译器初始化它时, 会将数组形式的元素转换成指向该数组的首元素的指针 。比如在这里 n 会被声明为 int * ,而后续则是想在 int * 内遍历,这是错误的。
7. 多维数组的名字,其实也是指向数组首元素的指针,也就是指向第一个内层数组的指针。如此类推。
8. C++ 使用多维数组名时,通常也会自动将其转换成指向数组首元素的指针。
9. 使用类型别名,简化多维数组的指针声明。
using int_array4 = int[4];
等价于
typedef int int_array4 [4];