临时整理的,有些可能不对。
1)如果一个类里面有const-qualifier或reference, compiler不会为它生成default copy assignment operator函数。
2) Hidden是指子类和父类有同名函数,但又没有virtual关键字。这里函数只要同名就可以了,参数并不需要match。也就是说,compiler只要在子类看到有这个函数名,即使参数不match,也不会再往父类找了。
3) delete function, default function 都是C++ 11新加的函数属性。
4) Decision of constructor happens at compile time。
5) Non-member function 不能在它后面加const。
6) macro的缺点: a) macros不会放进symbol table; b) macros 不管scope; c) macro 替换有时可能不是想要的地方。
Enum的缺点应该也包含上面的a)和b)。
7) delete p 和 free p都不会改变p的值。
8) 在line 2后放断点,x在symbol table里面是数组还是指针? 答案是一个数组。sizeof(x)=10*sizeof(int)。p是一个指向int的指针。
int main {
int x[10]; //line 1
int *p; //line 2
}
9) pragma once 不portable。
10) 在copy constructor和copy assignment operator中,如果类中有一个member是数组,当数组成员不包含指针时,用memcpy是安全的,否则要用loop挨个调用copy assignment operator初始化。
11) C++中,private是对class而言。同一个class的不同object可以互相访问对方的private member。
12) 类的static成员不增加类实例的大小。
13) 通常不需要显式调用destructor。
14) static 成员在类中出现只是声明(declaration),应该还要另外definition。为什么呢? 因为类的definition都是放在头文件内,如果算definition则包含该头文件的每个.cpp文件都有一个copy。
15) 如果两个pointer刚好相等(first==last),delete ptr危险!因为对应的析构函数调用两次!
16) inline是一个request, 编译器可以选择拒绝。
17)
int *p;
int const *q; //值const
int *const r; //指针const
p=q; //no, invalid conversion from 'const int*' to 'int *'
p=r; //ok
q=p; //ok
q=r; //ok
r=p; //no
r=q ;//no
18) int const * const p = &x; 指针和值都const。典型例子是read-only register。
19) T& const r 不合法,因为引用&本身自带const属性,即一个引用不能再指向别人???
20) 引用相当于const pointer。
21) lvalue 是addressable,可以找到地址。
22) Compiler 会自行决定是否给const object 分配地址 。
23)
int &ri=3; //no
int const &ri=3; //OK
24)
void fun(int n) {
int a[n];
...
}
这种写法C99和C++14都是支持的。但像TurboC和VC平台仅支持C89的不支持这种写法。
25) C/C++的堆上变量若未初始化,缺省值为0。栈上变量若未初始化,缺失值为未定义。
26)
struct A {
...
};
C要用struct A a; C++可以直接用A a;
27) C++11定义的大括号初始化
class Test{
int a;
int b;
public:
C(int i, int j);
};
Test t{0,0}; //C++11 only,相当于 Test t(0,0);
Test* pT=new Test{1,2}; //C++11 only,相当于 Test* pT=new Test{1,2};
int* a = new int[3]{ 1, 2, 0 }; //C++11 only
// C++11 container initializer
vector vs={ "first", "second", "third"};
map singers ={ {"Lady Gaga", "+1 (212) 555-7890"},{"Beyonce Knowles", "+1 (212) 555-0987"}};
下面这两种方法都可以
vector
和
vector
result = {2,3,7};
下面这个写法也是返回一个vector
vector
但27)这些写法一般只用于POD(plain old data) 变量。
28) vector
vector
vector
如果用数组,那么
int a[10] = {0}; //表示把a数组10个元素全部清零。
int a[10] = {1}; //表示把a[0]=1, a[1]-a[9]清零。
其实int a[10] = {0} 也是表示把a[0]=0, a[1]-a[9]清零。效果就等价于把a[0]-a[9]全部清零。
另外,二维数组呢?也是一样的。
int a[3][4] = {3}; //表示a[0][0]=3, 其他所有元素都是0。
int a[3][4] = {0}; //表示a[0][0]=0, 其他所有元素都是0。当然所有元素也都是0了。
vector
指定值初始化,ilist5被初始化为包含7个值为3的int
29) int *a, b; 其中a是指针,b是integer.
30) vector
vector
这里sol和results的值都是[]。那么怎么才能让results的值变成[[]]呢?
results.push_back(vector
当然用
result.push_back(sol);
也可以。
将result变成空集可以用result = {}。
返回一个空vector:
方法1: return vector
方法2:return {} //since C++ 11
返回一个2D的空vector:return {{}}
举例如下:
vector
int n = strs.size();
if (n == 0) return {{}};
...
}
31) 关于C里面 数字0,字符'0',字符串"0",字符串结尾标志符'\0' 的区别。参考了
关于C里面 数字0,字符'0',字符串"0",字符串结尾标志符'\0'_wmlhust的博客-CSDN博客
字符‘0’:
在这个表中,字符零,也就是C中的 ‘0’ 对应的是48,即,字符零在计算机中的存储是48。也就是说以下代码执行结果是48。
执行结果: czero = 48
数字0:
数字类型的数据在计算机中存储即是本身,就是0,应该是对应ASCII码里面的NULL。
int izero = 0;
这里的izero和上面的czero是两码事。
字符串“0”:
字符串“0” 相当于存了两个符号,一个是字符‘0’,一个是字符串结尾标志‘\0’,其存储的十进制数就是数字0。
字符串结尾标志‘\0’:
这里 '\0' 中的反斜线 \ 可以当做转义符,跟 \\ 表示 \,\' 表示 ' 一样,\0 表示的就是 0。
别忘记了这里的 \0 是字符类型的,相当于裸0(我自己想的名字==),也就是数字0,数字0对应着哪个字符呢,查看下ASCII表格,发现第一个就是,NULL,这样也好理解了,在读取字符串的时候,末尾是NULL,但是必须有这个NULL,才能告诉编译器字符串结束了。
对于memset,
memset(*dst, 0, size) 和 memset(*dst, '\0', size)效果是一样的,但是和memset(*dst, '0', size)不一样。
32) int a[] = {1,4,5,2,8,6,0};
sizeof(a)=4*7=28
sizeof(a)/sizeof(int) = 7
char c[]="a";
cout<
cout<
char d[]="";
cout<
cout<
33) 关于for循环:
for(表达式1;表达式2;表达式3){
循环语句
}
首先执行表达式1,一般是进行变量初始化操作,然后执行表达式2,即对循环条件进行判断,如果结果为真,则执行循环体;循环体执行完毕后,执行表达式3,改变循环变量的值,再次执行表达式2;结果为真,继续循环;如果结果为假,则终止循环,执行后面的语句。
vector |
v1是一个空vector,它潜在的元素是T类型的,执行默认初始化 |
vector |
v2中包含有v1所有元素的副本 |
vector |
等价于v2(v1),v2中包含有v1所有元素的副本 |
vector |
v3包含了n个重复的元素,每个元素的值都是val |
vector |
v4包含了n个重复地执行了值初始化的对象 |
vector |
v5包含了初始值个数的元素,每个元素被赋予相应的初始值 |
vector |
等价于v5{a,b,c...} |
42) stringstream tokenize 模板:
只用空格来隔开:
stringstream ss(doc.content);
string buf;
vector tokens; // Create vector to hold our words
while (ss >> buf) tokens.push_back(buf);
如果还需要考虑','的话
stringstream ss(s);
string buf;
vector words;
while(getline(ss, buf, ',')) {
words.push_back(buf);
}
43) 下面这种写法不对。因为vector的size未定,空间还未分配,不能直接用下标定位。
vector nums;
nums[0] = 3;
44) C++ double_min 的定义是
#include
constexpr double lowest_double = std::numeric_limits::lowest();
std::numeric_limits::max
C++ double_min的定义是std::numeric_limits::min
45) stl::multimap里面的equal_range(key)表示这个key所有的pairs。
//The function equal_range returns a pair, whose member pair::first is the lower bound of the range (the same as lower_bound), and pair::second is the upper bound (the same as upper_bound).
用法如下:
std::multimap mymm;
mymm.insert(std::pair('a',10));
mymm.insert(std::pair('b',20));
mymm.insert(std::pair('b',30));
mymm.insert(std::pair('b',40));
mymm.insert(std::pair('c',50));
mymm.insert(std::pair('c',60));
mymm.insert(std::pair('d',60));
std::cout << "mymm contains:\n";
for (char ch='a'; ch<='d'; ch++)
{
std::pair ::iterator, std::multimap::iterator> ret;
ret = mymm.equal_range(ch);
std::cout << ch << " =>";
for (std::multimap::iterator it=ret.first; it!=ret.second; ++it)
std::cout << ' ' << it->second;
std::cout << '\n';
}
46) C++ stl里面把string 变 int 用stoi(), 把int变string用to_string()
47)
在C++98标准里,只有static const声明的整型成员能在类内部初始化,并且初始化值必须是常量表达式。这些限制确保了初始化操作可以在编译时期进行。例如:
int var = 7;
class X {
static const int m1 = 7; // 正确
const int m2 = 7; // 错误:无static
static int m3 = 7; // 错误:无const
static const int m4 = var; // 错误:初始化值不是常量表达式
static const string m5 = “odd”; //错误:非整型
// …
};
C++11的基本思想是,允许非静态(non-static)数据成员在其声明处(在其所属类内部)进行初始化。这样,在运行时,需要初始值时构造函数可以使用这个初始值。考虑下面的代码:
class A {
public:
int a = 7;
};
class A {
public:
int a;
A() : a(7) {}
};
48) lower_bound()的意义是对于给定的已经排好序的a,key最早能插入到那个位置
upper_bound()的意义是对于给定的已经排好序的a,key最晚能插入到那个位置**
举例:
int a[]={0,1,2,2,3};
lower_bound(a,a+5,2)-a); //=2
upper_bound(a,a+5,2)-a); //=4
结果:2 4
0 1 | 2 2 3 所以2最早插入到2号位置
0 1 2 2 | 3 所以2最晚插入到4号位置0 1 | 2 2 3 所以2最早插入到4号位置
6) lower_bound()和upper_bound()还可以加入cmp函数。
49) vector子段赋值是
vv.push_back(vector
v2 = vector
void f() {
int a; //a 初始化值不确定
int b = int(); //b被初始化为0, 注意不能写成 int b(); 这是函数声明
int * c = new int; // c指向的值不确定
int * d = new int(); // d指向值是0
int e; //e 初始化不确定
new (&e) int() ; // 使用placement new
}
struct Foo{
Foo() : g() {} // f 不确定, g初始化为0
int f;
int g;
}
50) 关于C语言的取整:
double x;
printf("%d",int(x)) 取整;
printf("%d",int(x+0.5)) 四舍五入
直接赋值给整数变量
int i = 2.5; 或 i = (int)2.5; //舍去小数部分。
注意:
int i = 2.5 (i=2)
int i = 2.9 (i=2)
int i = -2.3 (i=-2)
int i = -2.5(i=-2)
int i = -2.6(i=-2)
注意对负数的取整!!! 我的总结就是不管对正数还是负数,取整就是把小数部分截去。
C/C++中的整数除法运算符“/”本身就有取整功能(int /int)。整数除法对正数的取整是舍去小数部分。但是整数除法对负数的取整结果和使用的C编译器有关。
floor(x)返回的是小于或等于x的最大整数, 即向负无穷大舍入。 如:
floor(2.5) = 2
floor(-2.1) = -3
floor(-2.5) = -3
floor(-2.6) = -3
ceil(x)返回的是大于x的最小整数,即向正无穷大舍入,如:
ceil(2.1) = 3
ceil(2.5) = 3
ceil(2.9) = 3
ceil(-2.1) = -2
ceil(-2.5) = -2
ceil(-2.9) = -2
关于floor()有一个有趣的应用,即如何判断一个整数的位数呢?
可以用下面的函数,基于log10()。
int digit(int x) {
return (int)floor(log10(x)) + 1;
}
注意
1) floor()函数返回double。
2) 注意要#include
3) 为什么是floor()+1,而不是ceil()呢?
一个例子是log10(100)=2,但是ceil()后还是2。
51) C++里面,unordered_map不可以用 for (auto m : mp),只有map才可以。
即下面的代码为错:
unordered_map
for (auto a : ump) { //wrong!
if (a.second > 0) {
...
}
注意:这里可能不对。有时候也可以用auto遍历unordered_map。那什么时候可以,什么时候不可以呢?
注意:unordered_set是基于hash table,所以要重载operator == (不需要重载opertor <),并且要定义NodeHash结构体,这样hash table才知道调用哪个hash function。
具体参考 LintCode 778: Pacific Atlantic Water Flow (BFS好题)_roufoo的博客-CSDN博客
//具体看LintCode 171 ”Anagrams“那题(不可以) 和 LintCode 78 "Longest Common Prefix"那题(可以)。
52) C++操作符重载好像不能用指针做参数?
也就是说
inline bool operator < (TreeNode & a, TreeNode & b) {
return a.val < b.val;
}
不能写成
inline bool operator < (TreeNode * a, TreeNode * b) {
return a->val < b->val;
}
53) 产生一定范围随机数的通用表示公式
取得[a,b)的随机整数,使用(rand() % (b-a))+ a;
取得[a,b]的随机整数,使用(rand() % (b-a+1))+ a;
取得(a,b]的随机整数,使用(rand() % (b-a))+ a + 1;
通用公式:a + rand() % n;其中的a是起始值,n是整数的范围。
取得a到b之间的随机整数,另一种表示:a + (int)b * rand() / (RAND_MAX + 1)。
取得0~1之间的浮点数,rand() / double(RAND_MAX)。
54) C++里面,
如果用for (auto a : A),这里面的a都是一个个的A里面的成员,不是指针。
如果是auto
iter = A.begin();
while(iter != a.end()) {
++iter;
}
这里面的iter是指针,指向A中的一个个成员。
55) C++里面的容器,如何删掉了iter之后还能遍历呢?
参考网页:
c++如何遍历删除map/vector里面的元素 - 大宝pku - 博客园
代码1:
auto iter = a.begin();
while (iter != a.end()) {
if (iter->second > 30) {
a.erase(iter++);
}
else {
++iter;
}
}
代码2:
auto iter = a.begin();
while (iter != a.end()) {
if (*iter > 30) {
iter = a.erase(iter);
}
else {
++iter;
}
}
56) C++ multiset, 如果参数是iterator,只删除对应iterator的元素;如果参数是值,删掉所有等于该值的元素。
// erasing from multiset
#include
#include
int main ()
{
std::multiset
std::multiset
// insert some values:
mymultiset.insert (40); // 40
for (int i=1; i<7; i++) mymultiset.insert(i*10); // 10 20 30 40 40 50 60
it=mymultiset.find (40);
mymultiset.erase (it);
std::cout << "mymultiset contains:";
for (it=mymultiset.begin(); it!=mymultiset.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
结果为:mymultiset contains: 10 30 40 50 60
把代码改成:
int main ()
{
std::multiset
std::multiset
// insert some values:
mymultiset.insert (40); // 40
for (int i=1; i<7; i++) mymultiset.insert(i*10); // 10 20 30 40 40 50 60
//it=mymultiset.find (40);
mymultiset.erase (40);
std::cout << "mymultiset contains:";
for (it=mymultiset.begin(); it!=mymultiset.end(); ++it)
std::cout << ' ' << *it;
std::cout << '\n';
return 0;
}
结果为:mymultiset contains: 10 20 30 50 60
57) *m.rbegin(); 可返回set/multiset最大值。也可以用*(m.end()-1)。
但注意,multiset的erase()支持iterator参数,但不支持reverse iterator rbegin(),也不支持m.end()-1这种操作。
58) pair的初始话的方法有
pair
pair
pair
即很多场合make_pair(x, y)可以直接用{x,y}代替。
59)
a) 一维和二维vector都有iterator,一维vector的iterator就好比指向每个元素的指针,二维vector的iterator就好比指向其中每个一维vector的指针。
b) 空的一维和二维vector的begin()和end()相等。
c) *(iter++)先返回\*iter,然后iter++。
跟*(i++)一回事。
d) iter像指针,但不能与指针比较。一个未初始化的iter不能与NULL比较。如果非要初始化,可将其初始化为对应container的end()。
即vector
vector
60) vector a的front()相当于a[0], back()相当于a[a.size()-1];
vector 61) 关于set的一个大坑。 当set元素为结构体时,必须要重载<,即结构体之间的排序以某字段为准。但此时切记set就只认该字段了,即如果两个节点,该字段一样,但其他字段不一样,set就认为它们是一个节点! 62) 只有当某个函数是class里面的函数时,后面才能加const int distance (const Point & a, const Point & b) { 写成下面就错了。 int distance (const Point & a, const Point & b) const { 63) 下面的针对奇数偶数的不同处理 int thresh = (n & 0x1) ? n / 2 + 1 : n / 2; 可以简化为 int thresh = (n + 1) / 2; 下面这个方式也可以: 但下面两种方式都不对: queue 65) 以下代码在Online C++ Compiler - online editor
cout<#include
return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
}
return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
}
64) queue的初始化必须是一个container,诸如list。比如下面的queue初始化必须3个{}。
queue
queue
queue
#include
也可以string sol = string(1, a);
67) 数组离散化例子,用来将类似将[3,2,100000]的稀疏数组简化为[2,1,3]
vector
sort(sortedA.begin(), sortedA.end());
uniqLen = unique(sortedA.begin(), sortedA.end()) - sortedA.begin();
//discrete A[]
for (int i = 0; i < A.size(); ++i) {
A[i] = lower_bound(sortedA.begin(), sortedA.begin() + uniqLen, A[i]) - sortedA.begin() + 1;
}
68) c=(KT-1)/100+1 是表示不小于KT/100的最小整数。比如说KT=33, 那么KT/100=0, c=1。KT=1, KT/100=0, c=1。
那么为何不直接用KT/100+1呢?因为如果KT/100刚好为1的话,那么c=2,但实际上c应该等于1。
69) 对pair
bool operator < (const pair & a, const pair & b) {
cout<<"compare "<<"("< b.second;
return a.first < b.first;
}
然后sort数组如下
vector
//nums[] initialization
sort(nums.begin(), nums.end());
上面的sort()里面根本不会调用重载的operator<,sort()还是用的pair
写成下面这样倒是可以,
struct compare {
bool operator () (const pair & a, const pair & b) {
if (a.first == b.first) return a.second > b.second;
return a.first < b.first;
}
}cmp;
sort(nums.begin(), nums.end(), cmp);
或者重定义一个struct Node来搞也可以。
struct Node {
int x;
int y;
Node(int _x, int _y) : x(_x), y(_y) {}
};
bool operator < (const Node & a, const Node & b) {
cout<<"compare "<<"("< b.y;
return a.x < b.x;
}
int main()
{
vector nodes;
nodes.push_back(Node(4,5));
nodes.push_back(Node(4,6));
sort(nodes.begin(), nodes.end());
return 0;
}
70) 科学计数法1E+6 必须保存为double型,不能是integer或long long。
为什么呢?想想1E-6必须是double型就知道了。
71) C++的引用内部实现可能是用const ptr来实现的。
int & r = i;
在背后的实现可能为
int * const ptr = &i;
然后
r=9;
等价于
*ptr = 9;
详见通过引用实现C++多态 - 屠戮者 - 博客园
72) 注意atoi和stoi的区别。atoi是C语言用的,因为C语言不知道string,所以atoi的参数如果是string类型必须还要加个.basic_string()将其转换成C语言的字符串。stoi可以直接用于C++的string。
73)
struct compare{
bool operator()(node a, node b){
return a.key > b.key;
}
} cmp;
priority_queue, compare> q;
sort(nums.begin(), nums.end(), cmp);
如果是sort,需要用类实例cmp。
如果是priority_queue,需要用类名compare。
74) 2的n次方用1< 75) 对比C++的array和vector的用法 对应于 76) 寻找数组a是否有在数组b中的元素。可以用find_first_of()。 77) C 语言printf格式占位符 79) 另外,如果我们在数组声明时进行了初始化,我们则可以不在方括号内说明数组的长度。也就是说,int b[2] = {5, 8};可以被我们简写为int b[] = {5, 8}。 80) 1. 十进制。如56。 b=010;//八进制 cout<<"b="<
//输出8 C/C++中二进制是不直接支持的。想输入二进制,可以用bitset 81)下面两种写法的输出结果没有什么区别。 但是,它们的工作原理是不同的,char *string2 = "Hello";的写法实际上是在string2这个变量中保存了"Hello"这个字符串字面量在程序运行时在内存中的地址。 同时,请注意,因为string2指向的"Hello"是一个字符串常量,所以我们没有办法直接通过string2来对字符串做修改。 而string1我们可以直接修改。 输出结果 我的理解是string是一个变量,所以printf("%p\n", &string)和printf("%p\n", string)的结果是一样的。 下面是一个参考程序 输出为 总结: 指针指向常量字符串(位于常量存储区),常量字符串的内容是不可以被修改的,企图修改常量字符串的内容而导致运行错误。所以这个问题出现的原因是char*str=”abcdefg”,赋值的是字符串常量,存储在常量存储区,而常量存储区的内容是无法修改的。 如果使用数组来代替的话,数据就存储在堆栈空间,堆栈空间的内容是可以修改的,就不会出现运行时错误。 程序的内存分配: 上代码: 82) calloc和 malloc的不同: 83) 带有空格的输入,可以使用 scanf 读入时可以逐字符读入,第一个参数使用 "%c",每行读入以 \n 字符被读入来判断结束。对于是否还有新的行没有读入的情况,可以用: while (scanf(/* 这部分省略*/) != EOF) { ... } 的方式进行。 example: 下面程序实现一个读入有空格的字符串并print出来。其中scanf("%[^\n]s", str)) != EOF) { //除了换行符号\n之外的所有字符都允许输入,包括空格。比如读入"Hello World",它会一直读到Hello World之后的那个\n换行符,然后打印出来。注意这里需要一个 getchar()吃掉那个\n换行符,不然while循环会卡在\n换行符这里陷入死循环,因为\n != EOF。 下面程序实现输入一个带空格的字符串并将其包含字符数打印出来。因为printf函数的返回值就是打印的字符数。 printf("%g\n", x)可以输出浮点数x的有效位数,不用补0。而printf("%lf\n", x)会补0,printf("%?d\n", n)也会补0。 输出结果为 84) 注意C语言里面EOF是文件结束符,'\0'是字符串结束符,'\n'是换行符。它们的值都是整型。 输出结果为 85) 在语法上,构造函数具有这样的性质: 我们在定义构造函数的时候,可以有参数表,也可以让参数表空着——同样,即使是一个构造函数有参数,我们也可以给它的所有参数都设置一个默认值。这样的构造函数,称为默认构造函数。同一个类中不能出现两个默认构造函数。下面的代码编译器会报错。 86) 如果我们定义一个类的时候,不声明任何构造函数,那么编译器在编译的时候,就会为我们自动生成一个默认构造函数,它具有这样的特点: 88) C99后有int8_t, int16_t, int32_t, int64_t等类型。其打印方法如下 (以int32_t为例,用PRId32宏): 89) For语句 90) C 语言里面只要condition非0就是true, 0就是false。 输出结果为 91) Unix系统里,每行结尾只有"<换行>",即"\n";Windows系统里面,每行结尾是"<回车><换行>",即"\r\n";Mac系统里,每行结尾是"<回车>"。一个直接后果是,Unix/Mac系统下的文件在Windows里打开的话,所有文字会变成一行;而Windows里的文件在Unix/Mac下打开的话,在每行的结尾可能会多出一个^M符号。 93) 如何编写一个打印日志宏? 94) 如何编写一个打印结构体offset宏? 95) g++ -E a.cpp 可以显示宏展开的结果。 97) fprintf, sprintf和printf区别。 fprintf向文件输出, fp为文件指针 sprintf向字符串buffer输出, buff为字符数组 printf是标准输出流(stdout)的输出函数,向屏幕标准设备输出, 相当于: 98) 关于printf打印字符串的一些格式: 输出为: 99) C的main函数的argc和argv都包括./a.out 100) C的printf函数里面有表达式或函数的话,结合顺序通常是从右往左。 printf("pop %d from the Queue = %d\n", front(q), pop(q)); 101) 如何将一个文件或标准输入中的字符串(空格隔开)输入给一个字符数组? 102) 数组指针和指针数组的区别 数组指针(也称行指针) 如要将二维数组赋给一指针,应这样赋值: 所以数组指针也称指向一维数组的指针,亦称行指针。 指针数组 这样两者的区别就豁然开朗了,数组指针只是一个指针变量,似乎是C语言里专门用来指向二维数组的,它占有内存中一个指针的存储空间。指针数组是多个指针变量,以数组形式存在内存当中,占有多个指针的存储空间。 优先级:()>[]>* 103) 同一平台下指针大小都相同,不同类型的指针步长不同;比如PC x86上是4字节,x64上是8字节, 不过这个结论不包括void* (实践中void *的大小在x64上也是8)。 在64位机下上面显示结果全为8。 105) 如何读入有空格的字符串? 106) 如何舍掉小数点后2位?不能用printf因为会四舍五入! 107) 关于sort函数里面的cmp函数的写法: sort函数对于cmp函数的特殊要求"strict weak ordering"。 应该写成如下: 108) 几种根据输入来自动截止的方法: 2)用getchar(), 它的作用是从stdin流中读入一个字符,getchar()函数等待输入直到按回车才结束(前提是缓冲区没有数据),回车前的所有输入字符都会逐个显示在屏幕上。但只有第一个字符作为函数的返回值。 3) 在 Windows 系统中,通过键盘输入时,按 Ctrl+Z 组合键后再按回车键,就代表输入结束。 在windows中输入数据后, 然后在按下 Ctrl+Z 组合键(可以在当前行,也可以在新的一行),接着按下回车键,输入就结束了,此时 cin 返回 false,循环结束,得到了最大值。 109) 如果char数组作为函数参数,求其长度可以用strlen,但必须定义i为size_t,而不是int。 110) strstr()是返回原字符串的一个字串,注意它不会重新分配一个字串。 111) 关于C字符串以下写法等价: 那char *str4 = "toad"跟它们有什么区别呢? 下面的程序 输出结果为 注意在64位机器上指针长度为8。//上面表格中显示sizeof(p)长度是4, 因为是32位机器 111) cout << "some"[2] << endl; //o 113) cout设置精度 保留小数点后**位数 cout.setf(ios::right); // 设置对齐方式 114) 两个object大小不一样,但类型一样,也可以用swap 输出9 115) signed 和 unsigned 相加,返回unsigned。 116) C++ 的类成员函数参数的默认值是在声明里赋值,还是在实现里面赋值? 117) 64位编译,结果为: 118) 注意x=+a 和 x+=a的区别 119) C++的内部类型和stl自带类型比如int, string,不能重载它们的类内的操作符,但是可以做类似这样 sort(words2.begin(), words2.end(), cmp()); 的重载。 120. 对齐宏,参考的Linux Loader script 里面的ALIGN()宏。仅限于2的幂次方对齐。 结果如下: 121. 又看了一下指针。数组名和函数名本身就是指针,在前面加上&也还是指针,其值不变。 结果如下:int main() {
int a[10];
int b[10] = {0};
int c[] = {1, 2, 3, 4, 5};
int x = c[2];
c[3] = x;
return 0;
}
int main() {
vector
vector
vector
auto it = find_first_of(begin(a), end(a), begin(b), end(b));
bool found = (it != end(a));
上面的例子中*it会返回3。
有符号整数型: %d或%i, example: -392
字符型: %c
无符号整数型: %u, example: 392
浮点数: %f或%F, example: 39.2
科学计数法浮点数: %e或%E, example, 3.9265e+2
实数(不显示无意义0): %g或%G, example, 39.2 和 1.2e+02
内存地址: %p, example: b8000000
字符串 %s
78) scanf的格式:
程序将会接受的一组整数是由空格分隔开的,我们无需在 scanf 中将描述输入格式的第一个参数写成"%d %d" 或者 "%d %d\n",而只需要写 "%d%d" 即可。这是因为 scanf 在处理输入时,如果格式占位符不是用于读入单个字符的 %c,它就会将空白字符(空格符、制表符和换行符)都视为一次输入的终止标记。 例如,当我们输入形如 3 5 这样的输入时,"%d%d" 会先用第一个 %d 匹配到 3,遭遇到一个空白字符(空格符)后,第二个 %d 会再匹配到 5,完成两个数字的读入。如果,我们的输入不是 3 5 而是先输入 3,回车后再输入 5,最终完成的输入效果也会是一样的(因为回车带来的换行符 \n 也是一个等效的空白字符)。
2. 十六进制,以0x开头,比如0x7a。输出十六进制hex关键字格式化,如cout<#include
#include
#include
Hello
Hello
0x7ffd196fca82 //printf("%p\n", &string);
0x7ffd196fca78 //printf("%p\n", &string2); //指针的地址,二级指针
0x7ffd196fca82 //printf("%p\n", string);
0x400754 //printf("%p\n", string2); //指针的值,即地址
0x400754 //printf("%p\n", &"Hello"); //string2所指字符串常量的地址
注意:
string的地址是内存栈区的地址,string2直接关联到"Hello"字符串常量在内存中管理字符串常量的那个位置。
这里string和string2这2个变量都分配在栈内存上,所以&string的地址(0x7ffd196fca82)和&string2的地址(0x7ffd196fca78)比较接近。
而string2实际上是指针,它指向内存中存储常量字符串的那个地址(0x400754)。#include
0x3
0x7ffe2c239afc
0x7ffe2c239afc
0x3
可见对于非指针变量a,printf("%p\n", a)的结果就是a的值, printf("%p\n", &a)是a的地址。
对于指针变量p, printf("%p\n", p)的结果是p的值,即p所指向的地址。printf("%p\n", *p)的结果是p所指向的那个地址所含变量的值。
指针为何不能修改其指向的常量字符串_wxywxywxy110的博客-CSDN博客
1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其
操作方式类似于数据结构中的栈。
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回
收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的
全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另
一块区域。 - 程序结束后由系统释放。
4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放
5、程序代码区—存放函数体的二进制代码。//main.c
int a = 0; 全局初始化区
char *p1; 全局未初始化区
main()
{
int b; 栈
char s[] = "abc"; 栈
char *p2; 栈
char *p3 = "123456"; 123456\0在常量区,p3在栈上。
static int c =0; 全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
分配得来得10和20字节的区域就在堆区。
}
calloc函数申请的内存空间是经过初始化的,全部被设成了0,而不是像malloc所申请的空间那样都是未经初始化的。 calloc函数适合为数组申请空间,我们可以将第二个参数设置为数组元素的空间大小,将第一个参数设置为数组的元素数量。 char names[20][100];
char c;
scanf("%d\n", &n);
for (int i = 0; i < n; ++i) {
j = 0;
//读取一个字符,直到是\n或者是EOF停止, 等价于 scanf("*[^\n]");
while((c = getchar()) != '\n' && c != EOF) {
names[i][j++] = c;
}
names[i][j] = '\n';
}
1 #include
#include
#include
2.3
2.300000
23
int main()
{
printf("%d\n", '\0');
printf("%d\n", '\n');
printf("%d\n", EOF);
return 0;
}
0 =>'\0'
10 =>'\n'
-1 =>EOF
1) 函数名与类名完全相同
2) 不能定义返回值类型,也不能有return语句
3)可以有形参,也可以没有形参,可以带有默认参数
4)可以重载。class Clock{
public:
Clock();
Clock(int newH = 0, int newM = 0, int newS = 0);
};
1) 参数列表为空,不为数据成员赋初值
2) 如果类内定义了成员的初始值,则使用内类定义的初始值
3) 如果没有定义类内的初始值,则以默认方式初始化
4) 基本类型的数据默认初始化的值是不确定的(类似于我们在主函数中声明一个类却不赋初始值的情况)
简而言之,这样一个构造函数,它的特点就是“什么都不做”,单纯只是创建一个类而已——相当于这样的一个形式:
Clock(){}
需要注意的是,如果我们在类中已经定义了一个构造函数(可以是任意形式)的话,那么编译器就不会再为我们定义默认构造函数了——这个时候,如果我们需要使用到默认构造函数的话,不要忘记自己再定义它。
87)关于构造函数的选择题:答案是1)4)6)
1) 如果没有需要的话,构造函数可以什么都不做
2) 构造函数的返回值类型为void
3) C++ 语言中,空的默认构造函数会把成员变量初始化为0
4)同一个类可以重载多个不同参数列表的构造函数
5)已经定义了其他构造函数的话,编译器仍然会为我们提供一个默认构造函数
6)如果不写构造函数的话编译器会为我们自动生成一个#include
for (初始化;循环条件;执行后操作) {
代码块;
}
内部执行如下:
Step 1: 初始化
Step 2: 循环条件判断
Step 3: 执行代码块
Step 4: 执行后操作
Step 5: 跳转到Step2 1 #include
a is true
b is true
c is false
d is true
对于a=3, b=-1这样的不标准的true condition, 怎么把他们标准化呢?答案就是!!(a), !!(b)。
这里!!(a)=1, !!(b)=1。
详见 回车和换行 - 阮一峰的网络日志
92) memset函数是按byte来设置。
把a指针开头的地址连续n个字节的对应bit全部置1。不能用
memset(a, 1, n)
而必须用
memset(a, -1, n)
因为1对应0b00...1,而-1对应0b11...1。#define log(frm, argc...) {\
printf("[%s : %d] ", __func__, __LINE__);\
printf(frm, ##argc);\
printf("\n");\
}
#define offset(T, a) (long)(&(((T*)(NULL))->a))
struct Data {
int a;
double b;
char c;
};
96) #define和typedef并不等价。
比如#define ppchar char *
typedef char * pchar;
pchar p1, p2;
ppchar p3, p4; //p4 is defined as char
fprintf(fp,"%s",name);
sprintf(buff,"%s",name);
printf("%s", name);
fprintf(stdout,"%s",name);
#include
abcdefg1
abcdefg1
ab1
ab1
./a.out -a -l abc xyz
argc=5, argv[0]="./a.out", argv[1]="-a", argv[2]="-l", argv[3]="abc", argv[4]="xyz"
由于printf的执行顺序是从右到左(至少在我的机器上是这样),所以pop(q)先执行,使得head已经加1,这样打印front(q)的时候实际上是queue的新head,而不是pop掉的那个数。
string name[6005];
while (cin >> name[n]) {
n++;
}
原链接在 数组指针和指针数组的区别 - hongcha_717 - 博客园
定义 int (*p)[n];
()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。
int a[3][4];
int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组。
p=a; //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0]
p++; //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][]
定义 int *p[n];
[]优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组,它有n个指针类型的数组元素。这里执行p+1是错误的,这样赋值也是错误的:p=a;因为p是个不可知的表示,只存在p[0]、p[1]、p[2]...p[n-1],而且它们分别是指针变量可以用来存放变量地址。但可以这样 *p=a; 这里*p表示指针数组第一个元素的值,a的首地址的值。
如要将二维数组赋给一指针数组:
int *p[3];
int a[3][4];
for(i=0;i<3;i++)
p[i]=a[i];
这里int *p[3] 表示一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2]
所以要分别赋值。
还需要说明的一点就是,同时用来指向二维数组时,其引用和用数组名引用都是一样的。
比如要表示数组中i行j列一个元素:
*(p[i]+j)、*(*(p+i)+j)、(*(p+i))[j]、p[i][j]
#include
104)
n & 1 等价于 n % 2
n & 3 等价于 n % 4
n & 7 等价于 n % 8
n & (2^i - 1) 等价于 n % (2^i)
scanf("%[^\n]s", str);
12.12345 => 12.12
方法1: 12.12345 * 100 = 1212.345, 1212.345/100.0 = 12.12
double x = 12.12345
printf("%.2f\n", (int)(l * 100) / 100.0);
方法2:12.12345 - 0.005 = 12.11845,再printf%.2f
参考链接
http://www.cplusplus.com/reference/algorithm/sort/
a) 反自反性,也就是cmp(x,x)必须返回false
b) 非对称性,也就是cmp(x,y)和cmp(y,x)结果必须相反
c) 可传递性,也就是cmp(x,y)=true, cmp(y,z)=true, 则cmp(x,z)=true.
所以,下面的写法可能有问题,因为违反了a)b)bool cmp(Node a, Node b) {
return a.val <= b.val;
}
bool cmp(Node a, Node b) {
if (a.val == b.val) return a.val2 > b.val2;
return a.val < b.val;
}
1)
struct node {
char s[4];
int num; //flag 表示直接清空,间接清空还是没清空
};
node b[15];
//如果
for (int i = 0; cin >> b[i].s; i++) {
...
}
char c;
while((c=getchar())!='\n') //每个getchar()依次读入一个字符
printf("%c",c); //按照原样输出
在 UNIX/Linux/Mac OS 系统中,Ctrl+D 代表输入结束。#include
int hash(HashTable *h, char value[]) {
int code = 0;
for (size_t i = 0; i < strlen(value); i++)/* strstr example */
#include
char str1[5] = {'g', 'e', 'e' ,'k' , '\0'}; //注意着一些要加后面的'\0'
char str2[5] = "geek";
char str3[] = "geek";
下面表格引用自What's difference between char s[] and char *s in C? - GeeksforGeeks#include
main.cpp:20:18: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]
main.cpp:22:18: warning: ISO C++ forbids converting a string constant to ‘char*’ [-Wwrite-strings]
666
555
8 6
8 1
8 6
8 1
cout << *("some" + 3) << endl; //e
112) C++大括号优化
#include
参考关于C++的cout输出小数的精度控制_杨领well的专栏-CSDN博客_cout 精度
cout.width(8); //设置输出宽度
cout.fill('0'); //将多余的空格用0填充
cout.flags(ios::fixed);
cout.precision(4); //设置输出精度,#include
只能是类的声明里面赋值!
下面这个链接讲的不错。
C++类/函数默认参数_VioletHan7的博客-CSDN博客_c++ 成员函数默认参数
而如果不是类的成员函数,即普通函数的话,函数参数的默认值可以是在声明里面,也可以是在实现里面。
#include
sizeof(char *) = 8
sizeof(C)=24
sizeof(D)=16
int x=10, a=-3;
x=+a;
cout << x << endl; // x=-3
struct cmp {
bool operator() (const string &a, const string &b) {
...
}
};#define ALIGN(X, Y) ((X + Y - 1) & ~(Y - 1))
int main()
{
//(. + exp - 1) & ~(exp - 1)
printf("ALIGN(9, 2) = %d\n", ALIGN(9, 2));
printf("ALIGN(19, 2) = %d\n", ALIGN(19, 2));
printf("ALIGN(22, 8) = %d\n", ALIGN(22, 8));
printf("ALIGN(26, 4) = %d\n", ALIGN(26, 4));
printf("ALIGN(26, 8) = %d\n", ALIGN(26, 8));
printf("ALIGN(26, 16) = %d\n", ALIGN(26, 16));
return 0;
}
ALIGN(9, 2) = 10
ALIGN(19, 2) = 20
ALIGN(22, 8) = 24
ALIGN(26, 4) = 28
ALIGN(26, 8) = 32
ALIGN(26, 16) = 32
#include
a = 0x7ffe5726b030, &a = 0x7ffe5726b030
func = 0x55e8794e4169, &func = 0x55e8794e4169