[C++ 面试基础知识总结]字符串,向量和数组
来源:互联网 发布:数控车床gsktdb编程 编辑:程序博客网 时间:2024/06/05 06:25
[C++ 面试基础知识总结]字符串,向量和数组
参考书籍:《C++ Primer》
目录
- C 面试基础知识总结字符串向量和数组
- 目录
- string
- string的读写
- stringsize_type类型
- string对象和字面值相加
- vector容器
- vector的初始化
- 使用vector的注意事项
- 迭代器
- 迭代器运算符
- 使用迭代器实现二分查找
- 数组
- 初始化和赋值
- 字符数组
- 数组与指针
- C风格字符串
- 多维数组中的指针
string
string的读写
#include <iostream>using namespace std;int main(int argc, const char * argv[]) { string s; cin >> s; cout << s << endl; return 0;}
如果输入” Hello World! “,得到的结果为“Hello”,因为在执行读取操作时,string对象会自动忽略开头的空白(空格符,换行符,制表符等)并从第一个真正的字符开始读起,直到遇到下一处空白为止。
string::size_type类型
string类型的size()函数返回类型为string::size_type,这个类型是一个无符号类型的值,且能足够放下任何string对象的大小。所以尽量不要在一个表达式中混用string::size_type和int,不然可能会带来问题。
#include <iostream>using namespace std;int main(int argc, const char * argv[]) { string s = "Hello"; int n = -1; bool flag = s.size() < n; cout << flag << endl; return 0;}
从表面上看,字符串s的长度应该为5(用字面值给字符串赋值时,不会复制字面值最后的那个空字符,所以不是6),而n为-1,5>-1,flag值应为0(假),但实际输出的值却是1(真),这是由于string::size_type是一个无符号整数,在与-1进行比较的时候会将-1转换成一个很大的无符号整数,导致最后结果为真。
string对象和字面值相加
当string对象和字符串字面值混在一条语句中使用时,必须保证每个加法运算符都至少有一运算对象为string,两个字符串字面值不能直接相加。
string s1 = "Hello", s2 = "World";//正确string s3 = s1 + "!" + s2;//错误 不能把字符串字面值直接相加string s4 = "Hello" + "!" + s2;//正确string s5 = "Hello" + ("!" + s2);
注意:字符串字面值和string是不同的类型,如上述的s1和”Hello”的类型是不同的!
vector容器
vector的初始化
用一个整数来初始化vector<int>
时,整数的含义可能是vector对象的容量也可能是元素的值,如果用圆括号,可以说提供的值是用来构造vector对象的,而用花括号,可以表述成列表初始化vector对象。具体区别如下所示:
// v1有10个元素,每个元素的值都为0(int类型的默认初始值)vector<int> v1(10);// v2有1元素,值为10vector<int> v2{10};// v3有10个元素,每个元素值都为1vector<int> v3(10,1);// v4有2个元素,值分别为10和1vector<int> v4{10,1};
如果使用花括号但提供的值又不能列表初始化时,会用这样的值来构造vector对象。
// 错误,不能用字面值来构建vector对象vector<string> v1("hi");// v2有1元素,值为"hi",列表初始化vector<string> v2{"hi"};// v3有10个元素,每个元素值都为空string对象,不能列表初始化,用默认值构造vector对象vector<string> v3{10};// v3有10个元素,每个元素值都为"hi",不能列表初始化,用提供的值构造vector对象vector<string> v4{10,"hi"};
使用vector的注意事项
vector的size()函数与string的同名函数功能完全一致,但要使用size_type时,需指定它是由哪种类型定义的,vector对象的类型总是包含着元素的类型。
vector<int>::size_type //正确vector::size_type //错误
不能用下标的形式添加元素,在vector对象中使用下标运算符时一定要保证该元素确知已存在,不然会产生很严重的后果。
vector<int> v;for (decltype(v.size()) i = 0; i != 10; i++) { v[i] = 1; //错误,v初始为空,不包含任何元素}
vector<int> v;for (decltype(v.size()) i = 0; i != 10; i++) { v.push_back(1); //正确}
迭代器
迭代器运算符
#include <iostream>using namespace std;int main(int argc, const char * argv[]) { string s("Hello"); //确保字符串s非空 if (s.begin() != s.end()) { auto t = s.begin(); ++*t; cout << *t << endl; ++t; if (t != s.end()) { cout << *t << endl; } } return 0;}
++*t是将t指向的字符加1,而++t是将t移动到下一个元素。所以两次输出的结果分别为I(第一个字符H加1),e(第二个字符)。
使用迭代器实现二分查找
示例,在有序的int型vector对象中找到等于2的元素,并打印出查找路径上的元素。
#include <iostream>#include <vector>using namespace std;int main(int argc, const char * argv[]) { vector<int> v{1,2,3,4,5,6,7,8,9,10}; auto begin = v.begin(), end = v.end(); auto mid = begin + (end - begin)/2; while (mid != end) { cout << *mid << endl; if (*mid == 2) { cout << "success" << endl; break; } else if (*mid > 2){ end = mid; } else{ begin = mid + 1; } mid = begin + (end - begin)/2; } return 0;}
运行结果:
632success
需要注意的是,由于v.end()指向的是v中尾元素的的下一位置,所以第一次查找的数是6,而不是5。调整范围时end = mid;
begin = mid + 1;
有区别,begin是指向mid的后一个元素,而end是直接指向mid的元素。
数组
初始化和赋值
数组声明时必须初始化维度(数组中的元素个数)或进行列表初始化根据初始值的数量计算并推测出来,且维度必须是一个常量表达式(什么是常量表达式?)
unsigned sz1 = 10;constexpr unsigned sz2 = 10;// 正确,声明一个含有10个整数的数组int a1[10];// 错误,sz1不是常量表达式int a2[sz1];// 正确,声明一个含有10个整数的数组int a3[sz2];// 错误,未初始化维度int a4[];// 正确,维度是3的数组int a5[] = {0,1,2};// 错误,不能用数组内容拷贝给其他数组作为其初始值,也不能用数组为其他数组赋值int a6[] = a5;
字符数组
字符串字面值结尾处有一个空字符,赋值给字符数组时会一起拷贝过去。
// 列表初始化,没有空字符char a1[] = ['C','+','+'];// 列表初始化,含有显式空字符char a2[] = ['C','+','+','\0'];// 自动添加结尾处的空字符char a3[] = "C++";// 错误,没有空间存放空字符char a4[3] = "C++";
数组与指针
// 含有10个整型指针的数组int *p1[10];// 指向一个含有10个整数的数组的指针int (*p2)[10];// 指向一个含有10个整型指针的数组的指针int *(*p3)[10];int a[2] = {1,2};//因为无法用数组的内容初始化另一个数组,所以用auto可以推断出p4类型为整型指针,指向a的第一个元素auto p4 = a;
数组的指针支持vector和string的迭代器的全部运算。C++11还引入了两个名为begin和end的函数,功能与容器中的两个同名函数类似。
int a[5] = {0,2,4,6,8};// 以下3种写法等价,都是将指针指向数组的第一个元素int *p1 = a;int *p2 = &a[0];int *p3 = begin(a);// n1值为8(将p1前进4个元素后解引的值即a[4])int n1 = *(p1 + 4);// n2值为4(将p1解引后加4的值即a[0]+4)int n2 = *p1 + 4;
C风格字符串
字符数组是C风格字符串,充满安全风险,容易引发严重错误,所以推荐使用标准库string。
char a[] = {"C","+","+"};// strlen函数是计算字符串长度的,这里会出错,因为没有以空字符结尾,函数将可能沿着数组的内存位置不断向前寻找,直到遇到空字符才停下来。count << strlen(a) << endl;
比较和拼接字符串的时候要注意:
char s1[] = "Hello", s2[] = "World";//错误,这里比较的将是s1和s2的地址,而不是字符串本身if (s1 < s2)//正确比较字符串if (strcmp(s1,s2))//错误,s1和s2是两个指针相加char s3[] = s1 + s2;//声明一个足够放下s1和s2的字符数组,如果无法估计准确,会出现安全风险char s4[11];//将s1复制到s4之后返回s4strcpy(s4,s1);//将s2加到s4之后返回s4strcat(s4,s2);
多维数组中的指针
#include <iostream>int main(int argc, const char * argv[]) { int a[2][3] = {{0,2,4},{6,8,10}}; // 等价于 int (*p)[3] = a,p指向含有3个整数的数组 auto p = a; cout << **(p+1) << endl; cout << *(*p+1) << endl; cout << (**p+1) << endl; return 0;}
输出结果分别为:
621
**(p+1)
是将指针p向后推进1个元素再进行两次解引,第一解引结果*(p+1)
为指向数组{6,8,10}首元素的指针,再次解引则为整数6。 *(*p+1)
是先将p进行解引,解引结果*p
为指向数组{0,2,4}首元素的指针,往后推进1个元素后指向第二个元素,解引得整数2。 (**p+1)
是将p连续解引两次,得到数组{0,2,4}首元素0,加1后得到整数1。
- [C++ 面试基础知识总结]字符串,向量和数组
- c++primer要点-字符串、向量和数组
- 字符串、向量和数组
- 字符串和数组经典面试问题总结
- 《c++primer》笔记 第3章 字符串、向量和数组
- Java数组、向量和字符串
- 三、字符串、向量和数组
- C++字符串向量和数组
- 待续:字符串、向量和数组
- ch3 字符串、向量和数组
- 3-字符串向量和数组
- Chapter3 字符串、向量和数组
- S03字符串、向量和数组
- 编程基础知识——C/C++字符串和字符数组
- 第3章 字符串、向量和数组
- 第三章 字符串、向量和数组
- 第三章 字符串、向量和数组
- c++11(2):字符串、向量和数组
- poj 3009 深搜
- 利用AXIS开发Webservice(一)
- 一天一个设计模式——开篇概述
- Android 消息机制学习
- Jmockit对接口与基类的mock
- [C++ 面试基础知识总结]字符串,向量和数组
- python版opencv入门
- 从sal_listen_port()研究linphone
- bzoj 1055
- 九度-1087 约数的个数[数论]
- ofbiz架构的分布式改造(一)
- eclipse maven创建web project
- 【Android数据传递】Intent传递List和Object和List<Object>(附源码)(转)
- 安卓滑动冲突的理解和一些解决思路