反转字符串¶
1.利用algorithm 的 reverse 方法
//就地操作
void reverse(string& str){
reverse(str.begin(),str.end());
}
2.自己实现, 1/2 遍历
//就地操作
void reverse(string& str){
int len=str.size();
//这个 for 循环写的很有意思
for(int i=0,j=len-1;i<j;i++,j--){
char temp=str[i];
str[i]=str[j];
str[j]=temp;
}
}
3.利用递归(尽量少用)
string reverse(string& str) {
if (str.size()<2)
return str;
else return reverse(str.substr(1)) + str.substr(0,1);
}
用 cout 打印指针地址¶
如果是会自动输出内容的指针,转换为 void 指针即可
char* ptr = "fuck";
cout << "ptr address: " << (void*)ptr << endl;
利用 # ifdef 等编译指令切换调试模式¶
for 循环和 while 循环¶
可以相互转换,嵌套 for 循环其实也不需要真的嵌套,其实可以统一使用 for 循环,见下面的例子
#include <iostream>
#include <vector>
#include <Windows.h>
using namespace std;
void display(vector<int> vec);
#define __main main
class Solution
{
public:
bool Find(vector<vector<int> > array, int target)
{
bool res = false;
int row = array.size();
int col = array[0].size();
// 我们从右上角的元素找起来
// 如果查找的元素比当前位置元素小, 就向左走
// 如果查找的元素比当前位置元素大, 就向下走
for (int i = 0, j = col - 1;
(i >= 0 && i < row) && (j >= 0 && j < col);)
{
if (target == array[i][j])
{
res = true;
break;
}
else if (target < array[i][j]) // 小的元素在当前位置左侧
{
#ifdef __tmain
display(array);
#endif // __tmain
j--;
}
else
{
#ifdef __tmain
display(array);
#endif // __tmain
i++;
}
}
return res;
}
};
void display(vector<int> vec)
{
int len = vec.size();
for (int i = 0; i<len; i++)
{
cout << vec[i] << ' ';
}
cout << endl;
}
int __main()
{
int a1[] = { 1, 2, 8, 9, };
int a2[] = { 2, 4, 9, 12, };
int a3[] = { 4, 7, 10, 13, };
int a4[] = { 6, 8, 11, 15, };
vector<vector<int>> array;
array.push_back(vector<int>(a1, a1 + 4));
array.push_back(vector<int>(a2, a2 + 4));
array.push_back(vector<int>(a3, a3 + 4));
array.push_back(vector<int>(a4, a4 + 4));
Solution solu;
cout << solu.Find(array, 7) << endl;
system("pause");
return 0;
}
!
的优先级¶
! 的优先级比 + - * / 等高
cout << !3-1 << endl << !(3-1);
//output -1(0-1) 0(!2)
迭代器的理解¶
拿 string 类举例来说,其
string str("abcdefg");
//删除第一个字符
str.erase(str.begin());
//删除第一个字符
str.erase(str.begin(),str.begin()+1);
//删除全部字符
str.erase(str.begin(),str.end());
//保留最后一个字符
str.erase(str.begin(),str.end()-1);
可以这样的理解,迭代器不同于普通的下标,而是一种类似于“隔板”一样的东西,str.begin() 返回的迭代器位于第一个字符前面,而 str.end() 返回的迭代器位于最后一个字符的后面,所以叫做”超尾迭代器“,如果成员函数的参数是首尾两个迭代器,那么删除的部分就位于这两个"隔板“之间。另外,string 类中的erase可以用int pos 作为参数,而其他的 STL 容器的 erase 好像只能用迭代器作为参数
NULL 和 nullptr¶
首先看一下 NULL 在 C 标准中的的定义
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
也就是说 NULL 在 C++ 中被 define 为 0. 而在 C 中 被 define 为 (void *)0。这在某些情况下是会出问题的
void f(int i){
cout << "take integer" << endl;
}
void f(int *p){
cout << "take pointer" << endl;
}
这两个重载函数,如果通过f(NULL)来调用 将调用第一个以 int 为参数的函数,而如果通过f(nullptr)来调用则会调用第二个函数 nullptr 是一个关键字 不存在上述问题
关于 cin 输入流¶
首先 关于 循环 while(cin) 的终止,似乎只能通过 EOF 也就是键盘上的 Ctrl + Z 来实现,如果你想对一段输入按空格拆分的时候如果是自己用键盘输入还好,可以输入 Ctrl + Z ,但是如果是测试题,那就没有机会输入 EOF 了。对于只有一行输入的情况,解决方法是
while(cin){
cin >> str;
if (cin.get()=='\n')
break;
}
cin.get() 和 cin.getline() 的区别是 cin.get 不会丢弃换行符而是留在输入流里,而 cin.getline 会读取并丢弃换行符。
const 和指针¶
const 只要不和指针混在一起,那么其表达的意思是很清楚的,但是只要和指针混在一块,通常对于 const 到底是修饰指针本身还是指针所指向的对象就要费一番周折了。
实际上,判断 const 修饰的对象最简单的方法就是看 const 位于 * 的左边还是右边。如果 const 位于星号的左侧,则 const 就是用来修饰指针所指向的变量,即指针指向为常量;如果 const 位于星号的右侧,const 就是修饰指针本身,即指针本身是常量。
int b = 500;
const int* a = &b; //[1]
int const *a = &b; //[2]
int* const a = &b; //[3]
const int* const a = &b; //[4]
[1]和[2]的情况相同,都是指针所指向的内容为常量(const放在变量声明符的位置无关).[3]为指针本身是常量,而指针所指向的内容不是常量.[4]为指针本身和指向的内容均为常量。
关于解除引用运算符的优先级¶
++ 的优先级比 解除引用运算符 * 要强,但是 ++ 运算符必须等上一操作结束了才会执行
int * ptr = new int[8]{ 1,3,5,7,9,11,13,15 };
int a = *ptr++; //a=1,ptr->3
cout << a << endl << *ptr++ << endl; //ptr->5
int b = *(ptr++); //b=5,ptr->7
cout << b << endl << *(ptr++) << endl; //ptr->9
int c = *ptr + 1; //c=10,ptr->9
cout << c << endl << *ptr + 1 << endl; //ptr->9
int d = *(ptr + 1); //d=11,ptr->9
cout << d << endl << *(ptr + 1) << endl;
// output: 1 3 5 7 10 10 11 11
总结,i++ 的优先级很高,但是必须保证在上一操作结束后执行这一点上有无括号并不影响,若是使用 ++i 结果又不一样。
C 中的内存对齐¶
从一个例子开始,下面这段代码,一样的结构体占用的空间大小却不一样。究其原因就是内存对齐。
内存对齐主要是因为
- 有些机器无法访问任意位置的内存
- 内存分块存取有利于提升效率
#include <iostream>
using namespace std;
struct st1
{
char a;
int b;
short c;
};
struct st2
{
short c;
char a;
int b;
};
int main()
{
cout << "sizeof(st1) is " << sizeof(st1) << endl;
cout << "sizeof(st2) is " << sizeof(st2) << endl;
system("pause");
return 0;
}
程序输出 分别为 12 8
内存对齐主要有两条原则
- 前面的地址(总和)必须是后面地址的整数倍
- 整个 struct 的地址必须是最大字节的整数倍
那么对于 st1 char(1) int(4),所以 char 后需添加 3 Byte,再然后 short(2) ,前面 int(4) 是其整数倍。
整个 st1 10 Byte,不是最大长度 int(4) 整数倍,故添加 3 Byte
对于 st2 第一个 short(2),第二个 char(1) 符合公式1,再然后的 int(4),那么前面必须额外添加 1 Byte 使前面有 4 Byte。
整个 st2 8 Byte 是最大长度 int(4) 的整数倍
函数声明有何意义呢,为什么不直接定义?¶
C/C++ 采用一种 分散编译的机制,把每个 .c 文件编译成一个二进制包然后再链接。这个机制是历史遗留产物,主要是由于当时的机器不足以维护整个项目的符号表。