C/C++
学习要点总结(未整理)
1. 内存对齐问题(struct a{ int a//4 ;char b//1 ;double c//8;}; //sizeof(a)=16
2. Continue语句的使用
3. 拷贝构造函数的作用
4. 多继承且有内嵌对象时的构造函数
派生类名::派生类名(基类1形参,基类2形参,...基类n形参,本类形参):基类名1(参数), 基类名2(参数), ...基类名n(参数),对象数据成员的初始化
{
本类成员初始化赋值语句;
};
5. void f() const ->const 表明f不能改变类的成员变量的值
6. 运算符重载
ostream& operator<< (ostream &os, A &a)
{
os<<a.i;
return os;
}
7. 使用free或delete释放了内存后,没有将指针设置为NULL。导致产生“野指针”
8. 栈是向低地址扩展的数据结构
堆是向高地址扩展的数据结构
9. Static 声明的变量/函数是有作用域的全局变量和函数。
Static 最大的作用在于控制访问
在C中如果一个函数或是一个全局变量被声明为static,那么,这个函数和这个全局
变量,将只能在这个C文件中被访问,如果别的C文件中调用这个C文件中的函数,
或是使用其中的全局(用extern关键字),将会发生链接时错误。这个特性可以用于
数据和程序保密。
10. 遇到typedef时,从左到右进行扫描,找到第一个“陌生”的标志符,这个标志符就应该是语句所声明的类型名称。
11. typedef char * pstr;
int mystrcmp(const pstr, const pstr);
我们希望表达的是int mystrcmp( const char*, const char* )
2个指向常量 char的指针
可它被解释后的实际表达式变成了:int mystrcmp( char* const, char* const ) 2个指向char的常量指针
const修饰的是pstr,而pstr代表了char *不是char,也就是把指针转换为常量
12. const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝。
编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。
13. char a[10];
strlen(a);
未初始化 '/0' 的位置是随机的 所以strlen(a)的值是不定的
14. 智能指针不能用于数组
智能指针是个对象 只不过就有指针的功能
智能指针不能和STL混用,当智能指针做实参传递给函数时,函数返回时智能指针自动释放。
15. 右左法则----复杂指针解析
16. C语言可以有三种方法定义一个常量:#define、const和枚举,但只有枚举才是真正的常量,什么是真正的常量?真正的常量是没有存储空间的,是一个右值,这意味着通过任何合法的手段也不会被修改
17. stl:
STL
提供
6
大组件,彼此可以组合套用:
1.
容器
(containers):
各种资料结构,如
Vector
、
List
、
Map
等,用来存储各种数据。
2.
演算法
(algorithms):
各种常用的算法,如
sort
、
search
、
copy
等,它的作用是为提供各种常用的操作。
3.
迭代器
(iterators):
一个非常重要的组件,用来将容器和演算法联系起来。也就是通常所说的泛型指针。
4.
仿函数
(functors):
行为类似函数,可作为演算法的某种策略
(policy)
。
5.
配接器
(adapters):
一种用来修饰容器或仿函数界面的东西。
6.
配置器
(allocators):
负责空间配置与管理,用来保证容器空间的正确分配。
容器:1.序列容器 2.关联容器 3.容器适配器
标准的连续内存容器是vector、string和deque
表现为链表的容器——比如list和slist——是基于节点的,所有的标准关联容器也是(它们的典型实现是平衡树)
是随机访问迭代器,在技术上只能限于vector、deque和string
18. cin cout cerr(无缓冲) clog(带缓冲)
19. 清空缓冲 flush endl
20. 内存对齐
在默认情况下,VC规定各成员变量存放的起始地址相对于结
构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数
VC 中提供了#pragma pack(n)来设定变量以n字节对齐方式
21. bss段和.data段的区别 :两者的区别在于:全局的未初始化变量存在于.bss段中,具体体现为一个占位符;全局的已初始化变量存于.data段中;而函数内的自动变量都在栈上分配空间。.bss是不占用.exe文件空间的,其内容由操作系统初始化(清零);而.data却需要占用,其内容由程序初始化
22. 当表达式中存在有符号类型和无符号类型时所有的操作数都自动转换为无符号类型
23. int型变量循环左移k次
a=a<<k|a>>16-k
(设sizeof(int)=2 * 8 = 16)
int型变量a循环右移k次
a=a>>k|a<<16-k
(设sizeof(int)=2 * 8 =16)
对2的倍数取模:
类似上面的方法。对2的倍数取模,只要将数与2的倍数-1做与运算就可以了。如:
a % 8 = a & 8-1
节省乘除法可以提高效率。
类似上面的方法。对2的倍数取模,只要将数与2的倍数-1做与运算就可以了。如:
a % 8 = a & 8-1
节省乘除法可以提高效率。
24. 合理结构体成员定义顺序:按照类型从小到大,相同类型连续存放
25. 数组名是一个地址,而且,还是一个不可修改的常量,完整地说,就是一个地址常量。数组名跟枚举常量类似,都属于符号常量。数组名这个符号,就代表了那块内存的首地址。注意了!不是数组名这个符号的值是那块内存的首地址,而是数组名这个符号本身就代表了首地址这个地址值,它就是这个地址,这就是数组名属于符号常量的意义所在。由于数组名是一种符号常量,因此它是一个右值,而指针,作为变量,却是一个左值,一个右值永远都不会是左值,那么,数组名永远都不会是指针!
26.
在
C
程序中,用
非
0
的数
表示逻辑值
"
真
"
。
27.
使用前向引用声明虽然可以解决一些问题,但它并不是万能的。需要注意的是,尽管使用了前向引用声明,但是在提供一个完整的类声明之前,不能声明该类的对象,也不能在内联成员函数中使用该类的对象。请看下面的程序段:
class Fred; //
前向引用声明
class Barney {
Fred x; //
错误:类
Fred
的声明尚不完善
};
class Fred {
Barney y;
};
应该记住:当你使用前向引用声明时,你只能使用被声明的符号,而不能涉及类的任何细节
28. // 赋值函数
String & String::operate =(const String &other)
{
// (1) 检查自赋值
if(this == &other)
return *this;
// (2) 释放原有的内存资源
delete [] m_data;
// (3)分配新的内存资源,并复制内容
int length = strlen(other.m_data);
m_data = new char[length+1];
strcpy(m_data, other.m_data);
// (4)返回本对象的引用
return *this;
29. 在析构函数里对指针成员进行delete。《Effective C++ 条款6》
并在释放后,马上将指针置为NULL。
30.
【实例
2
】从键盘上输入一个正整数给整型变量
a
,按二进制位输出该数。
#include<stdio.h>
main()
{
int a,b,i;
printf("
请输入一个整型数:
");
scanf("%d",&a);
b=1<<15; /*
构造一个最高位为
1
、其余各位为
0
的整数
*/
printf("%d=",a);
for(i=1;i<=16;i++)
{
putchar(a&b?'1':'0'); /*
输出最高位的值(
1/0
)
*/
a<<=1; /*
将次高位移到最高位上
*/
if(i%4==0) putchar(','); /*
四位一组用逗号分开
*/
}
printf("/bB/n");
}