命名空间
标准库的命名空间
1 #include <iostream> 2 #include <string> 3 using std::cout; 4 using std::cin; 数组和指针
数组声明时候的下标类型
整型常量 枚举常量 整型const常量
指针声明应该注意的
1 string* s1, s2;
s2 不是指针的了
安全声明方式为
1 string *s1, s2;
关于NULL
从C语言继承下来的 在cstdlib中定义的 不属于标准控件
std::NULL 是错误的
void 指针
void指针只能读 不要写 不允许赋值
C++支持指针相减
1 ptrdiff_t p1 – p2;
返回类型是 ptrdiff_t 和 size_t 类似 与机器相关
只不过ptrdiff_t 是signed整型
在文件 cstddef中定义
指针的下标可以为负数
因为指针的下标表示的就是加减的含义
1 int *p = &ia[2];
2 int k = p[-2]; // 正确 相当于 *(p - 2)
指针是数组的迭代器
1 const size_t arr_sz = 5;
2 int int_arr[arr_sz] = {0, 1, 2, 3, 4};
3 for(int *pbegin = int_arr, *pend = int_arr + arr_sz; pbegin != pend; pbegin++)
4 {
5 cout<<*pbegin<<endl;
6 }
指针和const
1 // 指针常量 指针指向的单元不能修改 const修饰的是int *p
2 const int *p;
3 int const *p;
这种指针只能指向任何对象 但是const对象的地址也只能赋给const 指针
虽然可以指向任何对象 一旦指向了某对象就不能通过该指针的解引用修改对象的值
4 // 常量指针 指针本身不能修改 const修饰的是 p
5 int *const p;
这种情况下 解引用的值是可以改变的
typedef的情况
1 typedef string *pstring;
2 const pstring cstr;
const 修饰的是cstr 所以等价于 string * const cstr
字符串操作
strlen是不包括NULL在内的字符串的长度
new出来数组
1 int *p = new int[10]; 2 delete [] p; c语言数组和string混合
1 char * sz = “abcdef”; 2 string str1(sz); 3 string str2; 4 str2 = sz; 5 str2 = str1 + sz; 也可以获得string的c方式存储
因为返回的是const char*所以定义必须是const char*
1 const char *sz = str.c_str(); 数组可以初始化vector
1 const size_t arr_size = 4; 2 int sz[arr_size] = {0, 1, 2, 3}; 3 vector<int> ivec(sz + 1, sz + arr_size); 多维数组
多维数组实际上就是数组的数组
1 int a[3][4]; // 数组有3个元素 每个元素是 int[4]的数组 2 int (*p)[4]; // 指向4个单元元素的数组指针 3 p = &a[2]; // 表明p指向a二维数组的第三个元素 typedef定义指向数组的指针
1 int ia[3][4]; 2 typedef int int_array[4] 3 int_array *ip = ia; 4 for(int_array *p = ia; p != ia + 3; p++) 5 { 6 for(int *q = *p; q != *p + 4; q++) 7 { 8 cout<<*q<<endl; 9 } 10 } 标准库string类型
c语言是 string.h
c++库是cstring.h
1 #include <string> 2 using std::string; 初始化
1 string s1; 2 string s2(s1); 3 string s3("value"); 4 string s4(n, 'c'); 输入输出
1 while(cin>>word) 2 { 3 cout<<word<<endl; 4 } 输入时会过滤字符串前面的空格
遇到空格时输入完毕
输入一行
1 string s; 2 while(getline(cin, s)) 3 { 4 cout<<s<<endl; 5 } getline是以换行符为标准的 遇到换行符就停止输入
string对象的操作
1 s.empty(); // 判断字符串是否为空 2 s.size(); // 字符个数 这里的返回值是 string::size_type string 库里定义的类型 不能赋值给int 但是可以赋值给unsigned 3 s[n]; // 从0开始的第n个字符 既可以输入也可以输出 4 s1 + s2; // 还有+=操作符 5 s1 = s2; 6 v1 == v2 // >= <= == != > < 采用的是字典序 unsigned int 和 unsigned long 表示的是一样的意思
+是可以连着加的,但是+左右必须至少有一个是string类型的
1 s3 = "Hello" + "world"; // error 2 s4 = s1 + "Hello" + "world"; // OK 3 s4 = "Hello" + "world" + s1; // error 最后一个字符是
1 s[s.size - 1]; // 因为是从0开始的下标 输出每一个字符
1 for(string::size_type i = 0; i != s.size(); i++) 2 { 3 cout<<s[i]<<endl; 4 } 也可以输入
1 s[0] = 'a'; 索引的范围是 0倒s.size() – 1
string为空的时候size()是0
索引的类型是 unsigned 的 string::size_type
string 还可以对其中的单个字符 进行判断处理
这些函数在 cctype 头文件中加以定义
cctype.h 和 ctype.h 是一样的
只是一个是cpp 方式定义的 还有命名空间 std 一个是 c 方式定义的
也
标准库vector类型
容器类型 模板
1 #include <vector> 2 using std::vector; vector本身是一个类型 用来定义对象
1 vector<int> ivec; 初始化
1 vector<int> ivec1; // 初始化为空 empty 2 vector<int> ivec2(ivec1); // 用一个初始化另一个 3 vector<int> ivec3(10, -1); // 初始化10个元素 每一个为-1 4 vector<int> ivec4(10); // 初始化10个元素 每一个为默认值 这里为0 vector本身初始化的 虽然有初始化 但通常是定义一个空的对象 然后动态增长
操作
1 v.empty(); // 判断空否 2 v.size(); // 获取元素个数 3 v[n]; // 和string类似 4 v1 = v2; // 赋值 5 v1 == v2; // 判断相等 > < != >= <= 6 v.push_back(t); // 末尾加入元素 虽然size返回的也是size_type 但要注意类型
1 vector<int>::size_type; // OK 2 vector::size_type; // error
一个push_back的例子
1 #include <string> 2 #include <vector> 3 using std::string; 4 using std::vector; 5 6 string word; 7 vector<string> text; 8 while(cin>>word) 9 { 10 text.push_back(word); 11 } 为什么在循环体中每次都调用size() 而不是调用一次 保存size的值每次都使用呢
因为很多类型的size都是动态增长的 所以这么做才是合理的
为什么用 != 作为判断循环的结束 而不是 < 之类的呢
迭代器
迭代器可以起到和下标一样的功能 可以对容器中的元素进行操作
下标操作只有少数容器支持 迭代器对于所有的容器都可以支持
要使用迭代器 首先要定义该容器下的迭代器变量
1 vector<int>::iterator iter;
容器的位置获取
1 vector<T>::iterator vector::begin(); 2 vector<T>::iterator vector::end();
返回值是迭代器类型哦~
1 vector<int> ivec; 2 ivec.begin(); // 指向第一个元素 ivec[0]的位置 3 ivec.end(); // 指向最后一个元素的 后一个元素 这是一个不存在的元素 如果为空
1 ivec.begin() == ivec.end(); 迭代器操作
1 vector<T>::iterator iter; 2 3 iter++ ++iter 4 iter-- --iter 5 *iter // 相当于ivec[]操作 也可以被赋值 6 iter + n; // 返回该容器的iterator类型 n 是该容器的size_type 类型 或者 difference_type 类型 7 iter – n; // 返回该容器的iterator类型 n 是该容器的size_type 类型 或者 difference_type 类型 8 iter1 – iter2; // 返回difference_type 类型 difference_type类型和size_type类型唯一不同在于它是signed的
例子
1 for(vector<T>::iterator iter = ivec.begin(); iter != ivec.end(); iter++) 2 { 3 *iter = 0; 4 } 对于*iter 有const_iterator这样的迭代器类型的变量 *iter的时候 不能改写变量
标准库bitset类型
1 #include <bitset> 2 using std::bitset; 定义
1 bitset<32> b; // 默认每一个位都是0 初始化
1 bitset<n> b; // 初始化一个元素 每一位都是0 2 bitset<n> b(u); // 用unsigned初始化 直接拷贝 低位保留 高位补0 或者截断 3 bitset<n> b(s); // 用string类型初始化 string的值必须是像“10101010101”这样的 string的低位被截断了 4 bitset<n> b(s, pos); // 用string类型初始化 从string型的 pos位置开始到string::size() - 1 5 bitset<n> b(s, pos, n); // 用string类型初始化 从string型的 pos位置开始到 pos + n 高低位的顺序
1 bitset<32> b; b[31],b[30],…,b[0]
而string型是 s[0],s[1],…,s[s.size() - 1]
函数
默认实参
可以在函数声明中采用默认实参
也可以在函数实现中采用
但是2者只能取其一
如果在函数实现中采用的话 应当包含源文件 否则默认实参是无效的
静态局部变量
1 static int a; 在函数生命期外仍然有效
但是函数外部无法访问到
下次调用该函数的时候
该数据还存在
内联函数
产生原因
和单纯写语句相比,写成函数的方式
好理解 好改 好重用 好统一 但是比语句要慢
内联好处
在内联处展开 效率高
在头文件中声明
1 inline int fun(); 在函数体中实现
1 inline int fun() 2 { 3 } 宏不能访问对象的私有成员。
宏的定义很容易产生二意性。