面试宝典之C++面试知识分享Word下载.docx
- 文档编号:7782854
- 上传时间:2023-05-09
- 格式:DOCX
- 页数:65
- 大小:42.57KB
面试宝典之C++面试知识分享Word下载.docx
《面试宝典之C++面试知识分享Word下载.docx》由会员分享,可在线阅读,更多相关《面试宝典之C++面试知识分享Word下载.docx(65页珍藏版)》请在冰点文库上搜索。
0)
*pDst=(char)val;
pDst=pDst+1;
size--;
returnstart;
void*my_memset(void*pDst,intval,size_tsize)//库函数写法
void*start=pDst;
*(char*)pDst=(char)val;
pDst=(char*)pDst+1;
memcpy是不考虑内存重叠的。
void*my_memcpy(void*pDst,constvoid*pSrc,size_tsize)
void*ret=pDst;
*(char*)pDst=*(char*)pSrc;
pSrc=(char*)pSrc+1;
returnret;
void*my_memmove(void*pDst,constvoid*pSrc,size_tsize)
if((char*)pDst<
=(char*)pSrc||(char*)pSrc+size>
=pDst)
//内存没有重叠时与memcpy一样
while(size>
{
*(char*)pDst=*(char*)pSrc;
pDst=(char*)pDst+1;
pSrc=(char*)pSrc+1;
size--;
}
else//OverLappingbuffers内存重叠
pDst=(char*)pDst+size-1;
pSrc=(char*)pSrc+size-1;
pDst=(char*)pDst-1;
pSrc=(char*)pSrc-1;
2.赋值语句
inti=1;
intmain()
inti=i;
//undefinedvalue.里面定义了i之后就屏蔽了全局变量
return0;
3.求一个数转换成二进制的数中的1的个数的求法:
intCount1forBinary(intx)
intcount=0;
while(x)
count++;
x=x&
(x-1);
//每次消去最后一个1
returncount;
补充:
判断一个数是不是2的N次方的方法:
!
(x&
(x-1))
4.C语言中printf和C++中cout计算参数时是从右到左压栈的。
printf("
%d,%d"
*ptr,*(++ptr));
//输出的结果应该是一样的
cout<
<
*ptr<
"
\n"
*(++ptr)<
endl;
5.优先级:
++--优先于*&
(取值取址)优先于sizeof()优先于*/%优先于<
>
6.求平均值:
intf(intx,inty)
return(x&
y)+((x^y)>
1);
7.不用判断语句求两个数中间比较大的数
max=(a+b)+abs(a-b)/2;
8.不用中间变量,交换a、b的值
方法一:
a=a+b;
b=a-b;
a=a-b;
//a+b可能会越界
方法二:
a=a^b;
b=a^b;
a=a^b;
2012.07.21
1.C++的类中的数据成员加上mutable后,修饰为const的成员函数,就可以修改它了。
intfun()const
/****/只能调用const的变量,不能改变
setw(tmp)<
setfill(‘‘)<
tmp<
//setw()为设置宽度,setfill()为设置填充字符
2.sizeof的用法
charss3[100]="
0123456789"
;
cout<
sizeof(ss3):
sizeof(ss3)<
//100,预分配的大小
strlen(ss3):
strlen(ss3)<
//10,内部实现是用一个循环计算字符串的长度,直到“\0”为止。
intss4[100];
sizeof(ss4):
sizeof(ss4)<
//400
strlen(ss4):
strlen(ss4)<
//错误,因为strlen的参数只能是char*,且必须是以”\0”结束。
char*str1=(char*)malloc(100);
sizeof(str1):
sizeof(str1)<
//4,指针的大小
sizeof(*str1):
sizeof(*str1)<
//1,第一个字符
sizeof(struct)时,struct要考虑对齐,一般都是取结构体中最长的来对齐,结构体默认对齐长度为8。
sizeof()计算栈中分配的大小,因此静态变量等全局数据区内的数的大小是不会计算在内的。
sizeof()按字节大小计算。
内存对齐的规则:
1、
对于结构的各个成员,第一个成员位于偏移为0的位置,以后每个数据成员的偏移量必须是min(#pragmapack()指定的数,这个数据成员的自身长度)
的倍数。
2、
在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragmapack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。
默认的#pragmapack
指定的值为8,如果最大数据结构成员长度为int,则结果本身按照4字节对齐,结构总大小必须为4的倍数。
内存对齐的主要作用是:
平台原因(移植原因):
不是所有的硬件平台都能访问任意地址上的任意数据的;
某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
性能原因:
经过内存对齐后,CPU的内存访问速度大大提升。
CPU把内存当成是一块一块的,块的大小可以是2,4,8,16字节大小,因此CPU在读取内存时是一块一块进行读取的。
块大小称为memoryaccessgranularity(粒度)
本人把它翻译为“内存读取粒度”。
原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;
而对齐的内存访问仅需要一次访问。
与strlen()的区别,具体实现
①sizeof是运算符,strlen是函数;
②sizeof操作符的结果类型是size_t;
③sizeof可以用类型做参数,还可以用函数做参数,而strlen只能用char*的变量做参数,且必须是以’\0’结尾的;
④大部分编译器在编译时就计算sizeof的值,是类型或者变量的长度,而strlen在运行时计算,计算字符串的长度,而不是内存的大小;
⑤sizeof后如果是变量名可以不加括号。
intmy_strlen(constchar*str)
assert(str!
=NULL);
intlen=0;
while((*str++)!
)//先执行*,再执行++
len++;
returnlen;
intmy_strlen2(constchar*str)//库函数
constchar*eos=str;
while(*eos++);
return(eos-str-1);
3.程序中常规的的变量,都是从大地址向小地址放的(存放在一个堆栈中,堆栈以大地址为底)。
4.数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址,如fun(char[8])、fun(char[])都等价于fun(char*),编译器是不知道数组的大小的。
5.类虚继承后,会添加虚表。
虚继承是为了解决多重继承中的重定义而产生的。
classB:
publicvirtualA{}
虚基类:
在虚继承体系中的通过virtual继承而来的基类,如A。
6.inline内联函数,在调用的地方不是跳转,而是把代码直接写到那里。
与宏函数相比,内联函数要做类型检查。
(const与宏的差别也是const有类型设置,会检查类型。
)对于短小的代码,inline减少了普通函数调用时的资源消耗,可以带来效率的提升,而它会增加空间的消耗。
2012.07.23
1.指针和引用的区别
引用不能为空,内容不能改变,使用前不会测试它的合法性;
而指针正好相反。
定义引用时必须初始化(const变量一样)。
2.地址值相减,转换成int之后要/sizeof(int)。
P68
int*m=(int*)2000;
int*n=(int*)1000;
printf("
%d\n"
m-n);
//-250
3.const指针:
constint*a;
可以执行a++,但是不能执行(*a)++
指向const的指针:
int*const;
可以执行(*a)++,但不能执行a++
4.数组名本身就是指针,加个&
就变成了双指针,即二位数组。
inta[]={1,2,3,4,5};
int*ptr=(int*)(&
a+1);
ptr-a<
//5,ptr指向下一行
5.malloc与free是C++/C的标准库函数,而new/delete是C++的运算符。
对于非内部数据结构的对象而言,只用malloc/free无法满足动态对象的要求。
malloc和free是库函数而不是运算符,不在编译器控制权限之内,不能够执行构造函数和析构函数。
6.智能指针auto_ptr是安全指针,包含在空间std中,用它构造的对象,析构函数总在退栈过程中被调用。
auto_ptr<
Object>
pObj(newObject);
auto_ptr<
source(){returnnewObject;
7.vector<
CDemo>
*a1=newvector<
();
a1->
push_back(d1);
//浅拷贝
deletea1;
//释放vector对象,vector包含的元素也同时释放了
8.静态模板类:
template<
classT>
template用法
STL
9.一个空类默认产生的成员函数:
默认构造函数、析构函数、拷贝构造函数、赋值函数。
拷贝构造函数:
CExample(const
CExample&
C)就是我们自定义的拷贝构造函数。
可见,拷贝构造函数是一种特殊的构造函数,函数的名称必须和类名称一致,它的唯一的一个参数是本类型的一个引用变量,该参数是const类型,不可变的。
例如:
类X的拷贝构造函数的形式为X(X&
x)。
当用一个已初始化过了的自定义类类型对象去初始化另一个新构造的对象的时候,拷贝构造函数就会被自动调用。
也就是说,当类的对象需要拷贝时,拷贝构造函数将会被调用。
以下情况都会调用拷贝构造函数:
一个对象以值传递的方式传入函数体
一个对象以值传递的方式从函数返回
一个对象需要通过另外一个对象进行初始化。
深拷贝和浅拷贝可以简单理解为:
如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝。
CA(constCA&
C)
a=C.a;
str=newchar[a];
//深拷贝
if(str!
=0)
strcpy(str,C.str);
10.class和struct的区别:
class中变量默认是private,struct中变量默认是public。
C++中存在struct是为了兼容以前的C项目。
11.类中,初始化列表的初始化顺序是根据成员变量的声明顺序来执行的。
常量必须在构造函数的初始化列表里初始化或者将其设置成static。
classA
A(){constintSize=0;
};
或者
staticconstintSize=0;
12.MFC中Cobject的析构函数是虚拟的。
原因:
多态的情况,CBase*p=newCChild();
析构时,如果不是virtual则会调用父类的析构函数,而实际new的子类的空间可能不会完全释放;
而如果是virtual的析构函数,则会调用虚拟指针执行的子类的析构函数来释放空间。
13.strcpy,strncpy,strlcpy
strcpy是依据/0作为结束判断的,如果to的空间不够,则会引起bufferoverflow。
strcpy(char*to,constchar*from)
char*save=to;
for(;
(*to=*from)!
/0'
++from,++to);
return(save);
strncpy(path,src,sizeof(path)-1);
//要赋值的长度
path[sizeof(path)-1]='
len=strlen(path);
strlcpy(char*dst,constchar*src,size_tsize);
而使用strlcpy,就不需要我们去手动负责/0了,仅需要把sizeof(dst)告之strlcpy即可:
strlcpy(path,src,sizeof(path));
if(len>
=sizeof(path))
srcistruncated."
并且strlcpy传回的是strlen(str),因此我们也很方便的可以判断数据是否被截断。
2012.07.24
1.String类P112
classString
public:
String(constchar*str=NULL);
//普通构造函数
String(constString&
copy);
//拷贝构造函数
~String();
String&
operator=(constString&
other);
//赋值函数
private:
char*m_data;
String:
:
String(constchar*str/*=NULL*/)
if(NULL==str)
m_data=newchar[1];
m_data='
else
intlength=strlen(str);
m_data=newchar[length+1];
strcpy(m_data,str);
~String()
delete[]m_data;
String(constString&
copy)
intlength=strlen(copy.m_data);
m_data=newchar[length+1];
strcpy(m_data,copy.m_data);
String&
String:
other)
if(this==&
return*this;
m_data=newchar[strlen(other.m_data)+1];
strcpy(m_data,other.m_data);
return*this;
调用:
Strings1("
hello"
Strings2=s1;
或者Strings2(s1);
//拷贝构造函数
Strings3;
s3=s2;
2.重载在编译期间就确定了,是静态的,重载和多态无关。
真正与多态相关的是覆盖(虚函数)。
当定义了父类的虚函数后,父类指针根据赋给它的不同的子类的指针,动态地调用属于子类的该函数,这样的函数调用在编译期间是无法确定的,调用子类的虚函数的地址无法给出。
封装可以隐藏细节,使得代码模块化,继承可以扩展存在的代码模块,它们都是为了代码重用。
而多态是为了接口重用。
override—覆盖(派生类函数覆盖基类virtual函数),
overload—重载(语义、功能相似的几个函数用同一个名字表示,但参数或返回值不同),
overwrite—重写(派生类的函数屏蔽了与其同名的基类函数)。
重写:
(1)如果派生类的函数与基类的函数同名,但是参数不同。
此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。
(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。
此时,基类的函数被隐藏(注意别与覆盖混淆)。
classParent
voidF()
cout<
ParentF().\n"
virtualvoidG()
ParentG().\n"
intAdd(intx,inty)
returnx+y;
floatAdd(floatx,floaty)//overload
classChild:
publicParent
voidF()//overwrite
ChildF().\n"
virtualvoidG()//override
ChildG().\n"
Child*child;
Parent*p=(Parent*)child;
(或者Parent*p1=newChild;
p1->
G();
p->
F();
//ParentF().
//ChildG().
3.voidfunction()const;
//常成员函数,它不改变对象的成员变量.也不能调用类中任何非const成员函数。
4.析构函数可以是private的。
classTest1
Test1()
Constructor."
};
voidDeleteTest1()
Deletetest1."
deletethis;
~Test1()
Destructor."
Test1*t1=newTest1();
//deletet1;
编译的时候会报错,因为析构函数时private的,delete调用不到它
t1->
DeleteTest1();
5.构造函数不能是virtual的。
构造函数可以是private的,但是该类不能被实例化,因为不能执行初始化。
private的构造函数不会生成默认的拷贝构造函数。
6.构造函数是从最初始的基类开始构造,各个类的同名变量没有形成覆盖,都是单独的变量。
接口的调用是就近的,优先调用离自己最近的接口(从当前层往上向父辈、祖父辈)。
7.A*pa=newA();
B*pb=(B*)pa;
//始终是A类空间
deletepa,pb;
//删除所指向的地址,但pa、pb指针并没有删除,也就是悬浮指针
pa=newB();
//B类的空间
pb=(B*)pa;
8.子类继承父类时,不管什么继承方式,子类都会继承父类的任何数据成员和方法,不管数据成员和方法是什么类型,只是因为继承方式或类型的原因而
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 面试 宝典 C+ 知识 分享