int *p1 = new int[10];
int *p2 = new int[10]();
对于内置类型而言,new仅仅是分配内存,除非后面显示加(),相当于调用它的构造函数,对于自定义类型而言,只要一调用new,
那么编译器不仅仅给它分配内存,还调用它的默认构造函数初始化,即使后面没有加()
下面的程序可以从0....n-1中随机等概率的输出m个不重复的数。这里我们假设n远大于m
knuth(int n, int m)
{
srand((unsigned int)time(0));
for (int i = 0; i < n; i++) {
if ( ) {
cout << i << endl;
( );
}
}
}
rand()%(n-i)<m m--
void prim(int m, int n)
{
if (m >= n)
{
while ( ) n++;
( );
prim(m, n);
cout << n << endl;
}
}
m%n m/=n
enum string{
x1,
x2,
x3=10,
x4,
x5,
} x;
函数外部问x等于什么?0
unsigned char *p1;
unsigned long *p2;
p1=(unsigned char *)0x801000;
p2=(unsigned long *)0x810000;
请问p1+5= 什么?
p2+5= 什么?
1代表的是一个单位量
p1+5=p1+5*1=p1+5*sizeof(unsigned char)=p1+5*1=0x801000+ox5=0x801005
p2+5=p2+5*1=p2+5*sizeof(unsigned long)=p1+5*4=0x810000+20=0x810000+0x14=0x810014
最后要转换成16进制
在32位机器中,如下代码:
void example(char acWelcome[]){
printf("%d",sizeof(acWelcome));
return;
}
void main(){
char acWelcome[]="Welcome to Huawei Test";
example(acWelcome);
return;
}
的输出是?4 数组作为函数的参数是会退化为函数指针的
函数func的定义如下:
void func(const int& v1, cont int& v2)
{
std::cout << v1 << ' ';
std::cout << v2 << ' ';
}
在Visual Studio开发环境下, 以下代码输出结果为____。
int main (int argc, char* argv[])
{
int i=0;
func(++i,i++);
return 0;
}
C语言函数参数入栈顺序为由右向左,func(++i, i++)可以分解为
参数 i 先入栈 输出0
然后执行i++ 此时i为1
接着参数 i 先执行++i i 此时为2 后入栈进行输出 2
假设寄存器为8位,用补码形式存储机器数,包括一位符号位,那么十进制数-25在寄存器表示为:
十进制数-25的原码为10011001,反码为11100110,补码是反码加1,即为11100111,转化为十六进制即为E7
#include<stdio.h>
int main()
{
unsigned char i=7;
int j=0;
for(;i>0;i-=3)
{
++j;
}
printf("%d\n",j);
return 0;
}
请问该程序的输出是多少?
unsigned char 8位数据位,范围0-255,
所以-2(11111110)时,溢出变成254;
同理-1(11111111)时,溢出变成255;
最后减到0时,不满足循环条件,for停止。
刚好173次。
7 4 1 -2 ==> 共4次
254 251 ... 5 2 -1 ==> 共85次
255 252 ... 6 3 ==> 共85-1=84次(因为3-3=0,不能进入循环了)
所以总共173次。(相减相除)
构造函数是不能被继承的,但是可以被调用,如果父类重新定义了构造函数,也就是没有了默认的构造函数,子类创建自己的构造函数的时候必须显式的调用父类的构造函数。
C++赋值运算符重载函数不能被继承
浅拷贝就比如像引用类型,而深拷贝就比如值类型。
浅拷贝是指源对象与拷贝对象共用一份实体,仅仅是引用的变量不同(名称不同)。对其中任何一个对象的改动都会影响另外一个对象。举个例子,一个人一开始叫张三,后来改名叫李四了,可是还是同一个人,不管是张三缺胳膊少腿还是李四缺胳膊少腿,都是这个人倒霉。
深拷贝是指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。举个例子,一个人名叫张三,后来用他克隆(假设法律允许)了另外一个人,叫李四,不管是张三缺胳膊少腿还是李四缺胳膊少腿都不会影响另外一个人。比较典型的就是Value(值)对象,如预定义类型Int32,Double,以及结构(struct),枚举(Enum)等。
浅拷贝是创建了一个对象用一个现成的对象初始化它的时候只是复制了成员(简单赋值)而没有拷贝分配给成员的资源(如给其指针变量成员分配了动态内存); 深拷贝是当一个对象创建时,如果分配了资源,就需要定义自己的拷贝构造函数,使之不但拷贝成员也拷贝分配给它的资源。
专用多态是指( A )
A.重载多态和强制多态
B.强制多态和包含多态
C.包含多态和参数多态
D.参数多态和重载多态
通用多态是指( C )
A.重载多态和强制多态
B.强制多态和包含多态
C.包含多态和参数多态
D.参数多态和重载多态
下列各项不属于类型兼容规则的是( A )
A.基类的对象可以赋值给派生类对象
B.派生类的对象可以赋值给基类的对象
C.派生类的对象可以初始化基类的引用
D.派生类对象的地址可以赋值给指向基类的指针
在创建派生类对象时,构造函数的执行顺序是( D )
A.对象成员构造函数、基类构造函数、派生类本身的构造函数
B.派生类本身的构造函数、基类构造函数、对象成员构造函数
C.基类构造函数、派生类本身的构造函数、对象成员构造函数
D.基类构造函数、对象成员构造函数、派生类本身的构造函数
如果把基类的析构函数声明为虚函数,则( A )
A.各派生类的析构函数均自动为虚函数;
B.派生类的析构函数与基类析构函数不同名,故不是虚函数;
C.每个派生类的析构函数都必须声明为虚函数;
D.只有基类的析构函数是虚函数。
求解:将一个3×3的矩阵转置,用一函数实现。
void reset(int a[][3])
{
int i,j,temp;
for(i=0;i<3;i++)
for(j=i;j<3;j++)
{
temp=a[i][j];
a[i][j]=a[j][i];
a[j][i]=temp;
}
}
void move(int *pointer)
{
int i,j,t;
for(i=0;i<3;i++)
for(j=1;j<3;j++)
{
t=*(pointer+3*i+j);
*(pointer+3*i+j)=*(pointer+3*j+i);
*(pointer+3*j+i)=t;
}
}
C++:memset ,memcpy 和strcpy 的根本区别?
#include “memory.h”memset用来对一段内存空间全部设置为某个字符,一般用在对定义的字符串进行初始化为‘ ‘或‘\0′;例:char a[100];memset(a, ‘\0′, sizeof(a));
memcpy用来做内存拷贝,你可以拿它拷贝任何数据类型的对象,可以指定拷贝的数据长度;例:char a[100],b[50]; memcpy(b, a, sizeof(b));注意如用sizeof(a),会造成b的内存地址溢出。
strcpy就只能拷贝字符串了,它遇到’\0′就结束拷贝;例:char a[100],b[50];strcpy(a,b);如用strcpy(b,a),要注意a中的字符串长度(第一个‘\0′之前)是否超过50位,如超过,则会造成b的内存地址溢出。
strcpy
原型:extern char *strcpy(char *dest,char *src);
用法:#include
功能:把src所指由NULL结束的字符串复制到dest所指的数组中。
说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
返回指向dest的指针。
memcpy
原型:extern void *memcpy(void *dest, void *src, unsigned int count);
用法:#include
功能:由src所指内存区域复制count个字节到dest所指内存区域。
说明:src和dest所指内存区域不能重叠,函数返回指向dest的指针。
Memset
原型:extern void *memset(void *buffer, char c, int count);
用法:#include
功能:把buffer所指内存区域的前count个字节设置成字符c。
说明:返回指向buffer的指针。
void swap_int(int *a,int *b){
*a=*a+*b;
*b=*a-*b;
*a=*a-*b;
}
结果正确,即使会溢出
关于“深拷贝”,下列说法正确的是:
会拷贝动态分配的成员对象 (正确答案)会拷贝成员数据的值会拷贝静态分配的成员对象
#include < stdio. h >
int
a = l, b=
2
;
void
funl(
int
a,
int
b )
{
printf(
"%d %d "
,a, b );
}
void
fun2()
{
a=
3
; b =
4
;
}
main()
{
funl(
5
,
6
) ;
fun2();
printf(
"%d %d\n"
,a,b );
}
|
程序运行后的输出结果是?
5 6 3 4
funl函数中的a、b为局部变量,fun2函数中的a、b为全局变量。执行funl函数后输出5,6 执行完ftin2 后a变为3,b变为4,所以结果为3,4。
switch(c)语句中,c不可以是什么类型()D
int long char float switch语句后的控制表达式只能是short、char、int、long整数类型和枚举类型,不能是float,double和boolean类型
Tip: 只有当函数只有 10 行甚至更少时才将其定义为内联函数.
定义: 当函数被声明为内联函数之后, 编译器会将其内联展开, 而不是按通常的函数调用机制进行调用.
优点: 当函数体比较小的时候, 内联该函数可以令目标代码更加高效. 对于存取函数以及其它函数体比较短, 性能关键的函数, 鼓励使用内联.
缺点: 滥用内联将导致程序变慢. 内联可能使目标代码量或增或减, 这取决于内联函数的大小. 内联非常短小的存取函数通常会减少代码大小, 但内联一个相当大的函数将戏剧性的增加代码大小. 现代处理器由于更好的利用了指令缓存, 小巧的代码往往执行更快。
结论: 一个较为合理的经验准则是, 不要内联超过 10 行的函数. 谨慎对待析构函数, 析构函数往往比其表面看起来要更长, 因为有隐含的成员和基类析构函数被调用!
另一个实用的经验准则: 内联那些包含循环或 switch 语句的函数常常是得不偿失 (除非在大多数情况下, 这些循环或 switch 语句从不被执行).
有些函数即使声明为内联的也不一定会被编译器内联, 这点很重要; 比如虚函数和递归函数就不会被正常内联. 通常, 递归函数不应该声明成内联函数.(递归调用堆栈的展开并不像循环那么简单, 比如递归层数在编译时可能是未知的, 大多数编译器都不支持内联递归函数). 虚函数内联的主要原因则是想把它的函数体放在类定义内, 为了图个方便, 抑或是当作文档描述其行为, 比如精短的存取函数.
-inl.h文件:
Tip: 复杂的内联函数的定义, 应放在后缀名为 -inl.h 的头文件中.
内联函数的定义必须放在头文件中, 编译器才能在调用点内联展开定义. 然而, 实现代码理论上应该放在 .cc 文件中, 我们不希望 .h 文件中有太多实现代码, 除非在可读性和性能上有明显优势.
使用inline关键字的函数会被编译器在调用处展开(错)如果只声明含有inline关键字,就没有内联的效果。 内联函数的定义必须放在头文件中, 编译器才能在调用点内联展开定义. 有些函数即使声明为内联的也不一定会被编译器内联, 这点很重要; 比如虚函数和递归函数就不会被正常内联. 通常, 递归函数不应该声明成内联函数. 使用 inline 关键字的函数只是用户希望它成为内联函数,但编译器有权忽略这个请求,比如:若此函数体太大,则不会把它作为内联函数展开的。
#inc#include <stdio.h>
#define N 2
#define M N+ 1
#define NUM ( M+1 )*M/2
int main()
{
printf( "%d\n" ,NUM );
}
本题考查宏定义,宏定义只是做个简单的替换,执行NUM=(N+1+1)*N+1/2=8
[ ]是面向对象程序设计语言中的一种机制。这种机制实现了方法的定义与具体的对象无关,而对方法的调用则可以关联于具体的对象。
动态绑定
已知ii,j都是整型变量,下列表达式中,与下标引用X[ii][j]不等效的是()。
*(X[ii]+j) *(*(X+ii)+j) 正确*(X+ii)[j] 由于[]的优先级高于*,正确的应该是(*(x+ii))[jj],*(X+ii+j) 错
char *p="hello"; return p == "hello";
#define NUMA 10000000
#define NUMB 1000
int a[NUMA], b[NUMB];
void pa()
{
int i, j;
for(i = 0; i < NUMB; ++i)
for(j = 0; j < NUMA; ++j)
++a[j];
}
void pb()
{
int i, j;
for(i = 0; i < NUMA; ++i)
for(j = 0; j < NUMB; ++j)
++b[j];
}
pb比pa快,数组a比数组b大很多,可能跨更多的页,缺页率高或者缓存命中更低,所以pb快
以下代码执行后,val的值是_B__:
1
2
3
4
|
unsigned
long
val = 0;
char
a = 0x48;
char
b = 0x52;
val = b << 8 | a;
|
-
20992
-
21064
-
72
-
0
int a=248, b=4;
int const c=21;
const int *d=&a;
int *const e=&b;
int const * const f =&a;
请问下列表达式哪些会被编译器禁止?
*c=32
*d=43
e=&a
f=0x321f
d=&b
*e=34
正确答案: A B C D
1) malloc 函数: void *malloc(unsigned int size)
在内存的动态分配区域中分配一个长度为size的连续空间,如果分配成功,则返回所分配内存空间的首地址,否则返回NULL,申请的内存不会进行初始化。
2)calloc 函数: void *calloc(unsigned int num, unsigned int size)按照所给的数据个数和数据类型所占字节数,分配一个 num * size 连续的空间。
3)realloc 函数: void *realloc(void *ptr, unsigned int size)
动态分配一个长度为size的内存空间,并把内存空间的首地址赋值给ptr,把ptr内存空间调整为size。
4)new是动态分配内存的运算符,自动计算需要分配的空间,在分配类类型的内存空间时,同时调用类的构造函数,对内存空间进行初始化,即完成类的初始化工作。动态分配内置类型是否自动初始化取决于变量定义的位置,在函数体外定义的变量都初始化为0,在函数体内定义的内置类型变量都不进行初始化。
1 静态链接库的优点
(1) 代码装载速度快,执行速度略比动态链接库快;
(2) 只需保证在开发者的计算机中有正确的.LIB文件,在以二进制形式发布程序时不需考虑在用户的计算机上.LIB文件是否存在及版本问题,可避免DLL地狱等问题。
2 动态链接库的优点
(1) 更加节省内存并减少页面交换;
(2) DLL文件与EXE文件独立,只要输出接口不变(即名称、参数、返回值类型和调用约定不变),更换DLL文件不会对EXE文件造成任何影响,因而极大地提高了可维护性和可扩展性;
(3) 不同编程语言编写的程序只要按照函数调用约定就可以调用同一个DLL函数;
(4)适用于大规模的软件开发,使开发过程独立、耦合度小,便于不同开发者和开发组织之间进行开发和测试。
3 不足之处
(1) 使用静态链接生成的可执行文件体积较大,包含相同的公共代码,造成浪费;
(2) 使用动态链接库的应用程序不是自完备的,它依赖的DLL模块也要存在,如果使用载入时动态链接,程序启动时发现DLL不存在,系统将终止程序并给出错误信息。而使用运行时动态链接,系统不会终止,但由于DLL中的导出函数不可用,程序会加载失败;速度比静态链接慢。当某个模块更新后,如果新模块与旧的模块不兼容,那么那些需要该模块才能运行的软件,统统撕掉。这在早期Windows中很常见。
下列代码的输出结果是D
1
2
3
4
5
6
7
8
9
10
11
|
int
i = -
1
;
unsigned j =
1
;
if
(j > i)
printf(
" (j>i)成立\n"
);
else
printf(
" (j>i)不成立\n"
);
if
(i < j)
printf(
" (i<j)成立\n"
);
else
printf(
" (i<j)不成立\n"
);
|
-
(j>i)成立,(i<j)成立
-
(j>i)不成立,(i<j)成立
-
(j>i)成立,(i<j)不成立
-
(j>i)不成立,(i<j)不成立
在C++ 程序中调用被 C编译器编译后的函数,为什么要加 extern "C"?
C++语言支持函数重载,C语言不支持函数重载。函数被C++编译后在库中的名字与C语言的不同。假设某个函数的原型为: void foo(int x, int y);该函数被C编译器编译后在库中的名字为_foo,而C++编译器则会产生像_foo_int_int之类的名字。C++提供了C连接交换指定符号extern"C"来解决名字匹配问题。
写一个“标准”宏,这个宏返回一个数组最高维的下标(如数组a[2][4][6],执行宏之后结果是2)
#define firstdem(array) sizeof(array)/sizeof(array[0])
.public static const int A=1;这段代码有错误么?是什么?
答:const不能用static修饰。
-
一个浮点数由三部分组成:符号位S、指数部分E(阶码)以及尾数部分M。
-
单精度浮点数(float)总共用32位来表示浮点数,其中尾数用23位存储,加上小数点前有一位隐藏的1(IEEE754规约数表示法),2^(23+1) = 16777216。因为 10^7 < 16777216 < 10^8,所以说单精度浮点数的有效位数是7位。考虑到第7位可能的四舍五入问题,所以单精度最少有6位有效数字(最小尺寸)。
-
同样地:双精度浮点数(double)总共用64位来表示浮点数,其中尾数用52位存储, 2^(52+1) = 9007199254740992,10^16 < 9007199254740992 < 10^17,所以双精度的有效位数是16位。同样四舍五入,最少15位。
1
2
3
4
5
6
7
|
char
ccString1[]=
"Is Page Fault??"
;
char
ccString2[]=
"No Page Fault??"
;
strcpy
(ccString1,
"No"
);
if
(
strcmp
(ccString1,ccString2)==0)
cout<<ccString2;
else
cout<<ccString1;
|
在析构函数中也不要调用虚函数。在析构的时候会首先调用子类的析构函数,析构掉对象中的子类部分,然后在调用基类的析构函数析构基类部分,如果在基类的析构函数里面调用虚函数,会导致其调用已经析构了的子类对象里面的函数,这是非常危险的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class A{
public:
A(){p();}
virtual void p(){print(
"A"
)}
virtual ~A(){p();}
};
class B:public A{
public:
B(){p();}
void p(){print(
"B"
)}
~B(){p();}
};
int main(int, char**){
A* a=
new
B();
delete
a;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
|
#include
"stdio.h"
int
func(
int
x,
int
y)
{
return
(x + y);
}
int
main()
{
int
a =
1
, b =
2
, c =
3
, d =
4
, e =
5
;
printf(
" % d\n"
, func((a + b, b + c, c + a), (d, e)));
return
0
;
}
|
-
对0x0这个地址取值是非法的
-
空指针可以确保不指向任何对象或函数; 而未初始化指针则可能指向任何地方。
-
空指针与任何对象或函数的指针值都不相等
-
mallc在其内存分配失败时返回的是一个未初始化的指针
1.需要初始化的数据成员是对象(继承时调用基类构造函数)
2.需要初始化const修饰的类成员
3.需要初始化引用成员数据
1
2
|
1.
char
* string_a=(
char
*)
malloc
(100*
sizeof
(
char
));
2.
char
string_b[100];
|
-
8 100
-
100 8
-
100 100
-
8 8
-
9++
-
(x+y)++
-
c+++c+++c++
-
++(a-b--)