1、
a)一个有10个指针的数组,该指针是指向一个整型数;
b)一个指向有10个整型数数组的指针;c)一个指向函数的指针,该函数有一个整型参数并返回一个整型数;
d)一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数
a)int *a [10];
b) int (*a)[10];
c)int (*a)(int)
d) int( *a[10])(int)
2、程序输出
void GetMemory(char *p)
{
p=(char *)malloc(100);
}
void main()
{
char *str=NULL;
GetMemory(str);
strcpy(str,"hello world");
printf(str);
cout<<endl;
}
char * GetMemory()
{
char *p=(char *)malloc(100);
return p;
}
void main()
{
char *str=NULL;
str=GetMemory();
strcpy(str,"hello world");
printf(str);
cout<<endl;
}
输出:hello world
char * GetMemory()
{
char p[]="hello world";
return p;
}
void main()
{
char *str=NULL;
str=GetMemory();
strcpy(str,"hello world");
printf(str);
cout<<endl;
}
输出:
void GetMemory(char **p,int num)
{
*p=(char *)malloc(num);
}
void main()
{
char *str=NULL;
GetMemory(&str,100);
strcpy(str,"hello world");
printf(str);
cout<<endl;
}
输出:hello world
void main()
{
char *str=(char *)malloc(100);
strcpy(str,"world");
free(str);
if(str!=NULL)
{
strcpy(str,"hello3456");
printf(str);
}
cout<<endl;
}
输出:str变成野指针,指向内容不确定
3、程序输出:
class A
{
public:
A(){
cout<<"A()"<<endl;
}
virtual ~A(){
printf("~A().\n");
}
virtual void fn()
{
cout<<"A::fn()"<<endl;
}
};
class B:public A
{
public:
B()
{
printf("B constructed.\n");
}
virtual ~B()
{
printf("B deconstructed.\n");
}
virtual void fn()
{
cout<<"B::fun()"<<endl;
}
};
class C:public B
{
public:
C()
{
printf("C constructed.\n");
}
virtual ~C()
{
printf("C deconstructed.\n");
}
virtual void fn()
{
printf("C fn called.\n");
}
};
void main(int argc ,char* argv[])
{
A *pA=new B;
cout<<"here"<<endl;
if(pA!=NULL)
pA->fn();
B *pB=static_cast<B*>(pA);
if(pB!=NULL)
pB->fn();
C * pC=static_cast<C*>(pA);
if(pC!=NULL)
pC->fn();
delete pA;
}
输出:
A()
B constructed.
here
B::fun()
B::fun()
B::fun()
B deconstructed.
~A().
4、指针和引用的区别:
A)指针和引用作为函数参数都可以改变实参
B)指针可以在定义后任意的改变指向,引用总是指向初始化时指定的对象,以后不能改变,但是对象的内容可变。
C)引用必须在创建的时候初始化,而指针则不需要
D)不能空引用,但是可以有空指针
5、C++多态性:运算符重载中的两种形式 . 运算符的重载形式有两种,重载为_____________和________________________
1、重载为类的成员函数:
当重载成为成员函数时,双目运算符仅有一个参数。对单目运算符,重载为成员函数时,总是隐含了一个 参数,该参数是 this 指针。 This 指针指向调用该成员函数对象的指针。
2、重载为友员函数:
当重载友员函数时,将没有隐含的参数 this 指针。这样,对双目运算符,友员函数有2个参数,对单目运算符,友员函数有一个参数。
6、main主函数执行完毕后,是否可能会再执行一段代码?
int fun()
{
cout<<"exit three"<<endl;
return 0;
}
int fun2()
{
cout<<"exit second"<<endl;
return 0;
}
void main(int argc ,char* argv[])
{
_onexit(fun); //oneexit以栈的方式注册函数,后注册的先执行
_onexit(fun2);
cout<<"exit first "<<endl;;
}输出:
exit first
exit second
exit three
7、C++中的空类,默认产生那些类成员函数?
默认构造函数
析构函数
拷贝构造函数
赋值运算符(operator=)
取址运算符(operator&)(一对,一个非const的,一个const的)
#include<iostream>
using namespace std;
class class1
{
public:
class1(){}//缺省构造函数
class1(const class1&){}//拷贝构造函数
~class1(){}//析构函数
class1&operator=(const class1&){}//赋值运算符
class1*operator&(){}//取址运算符
const class1*operator&()const{}//取址运算符 const
};
//空类class2会产生class1一样的成员函数
class class2
{
};
void main()
{
class2 obj1;//缺省构造函数
class2 obj2;
obj1=obj2;//赋值运算符
&obj2;//取址运算符
class2 obj3(obj1);//拷贝构造函数
class2 const obj4;
&obj4;//取址运算符 const
}
8、静态链接库和动态链接库:
静态链接库是.lib格式的文件,一般在工程的设置界面加入工程中,程序编译时会把lib文件的代码加入你的程序中因此会增加代码大小,你的程序一运行lib代码强制被装入你程序的运行空间,不能手动移除lib代码。动态链接库是程序运行时动态装入内存的模块,格式*.dll,在程序运行时可以随意加载和移除,节省内存空间。 也就是说静态链接库不适合程序的运行,它是要么不做,要么全做的库。 在大型的软件项目中一般要实现很多功能,如果把所有单独的功能写成一个个lib文件的话,程序运行的时候要占用很大的内存空间,导致运行缓慢;但是如果将功能写成dll文件,
就可以在用到该功能的时候调用功能对应的dll文件,不用这个功能时将dll文件移除内存,这样可以节省内存空间
这种情况称为运行时链接
如果我们再把动态库的名字加上去呢?
[cpp] view plaincopyprint?
1. >>gcc main.c -ldl ./libA.so ./libB.so
@crazybaby
2. >>./a.out
@crazybaby
3. libA common!
4. libA common!
[cpp] view plaincopyprint?
1. >>gcc main.c -ldl ./libB.so ./libA.so
@crazybaby
2. >>./a.out
@crazybaby
3. libB common!
4. libB common!
同样可以得出结论,动态链接库如果不加库连选项 ,函数调用是正确的 加库路径,会以库的路径顺序为主! 左边覆盖右边. 而且当只链接其中一个时 也生效.
如果是两个静态库中有相同的函数,会造成同名冲突。但是动态库不会造成同名冲突。 也就是说动态库不会造成同名冲突。只有静态链接库才会造成同名冲突。
9、简述STL库的功能
1.标准模板库(STL)使得C++编程语言在有了强大的类库的同时,保有了更大的可扩展性。该库包含了诸多在计算机科学领域里所常用的基本数据结构和基本算法。
2.为广大C++程序员们提供了一个可扩展的应用框架,高度体现了软件的可复用性。
3.从逻辑层次来看,在STL中体现了泛型化程序设计的思想(generic programming)
10、什么是内存的垃圾回收集算法,其作用是什么?据你所知,有那些开发语言中提供了垃圾收集机制?
一种自动内存管理的策略,就是自动垃圾回收机制。既然是自动垃圾回收,那么平台肯定得采取一种方式发现垃圾,然后清除。这就是垃圾收集算法所关注的问题。
垃圾收集算法的任务就是将活动的对象和已经死掉的对象分别出来,然后将死掉的对象的内存回收,而且为了更好的利用内存,有的算法还会对内存碎片进行压缩。
下面会对常用的垃圾收集算法进行介绍:
引用计数(Reference Counting) 引用计数,顾名思义,就是每个对象上有个计数器,当添加了一个对它的引用时它的计数器就会加1,当不再使用这个引用时它的计数器就会递减1。当计数器为0的时候则认为该对象是垃圾,可以被回收了,如果该对象被回收则该对象所引用的所有对象的计数器会跟着递减。这样有可能会有很多对象的引用都减为0
跟踪(trace)跟踪有以下几种方式。
标记清扫(Mark-Sweep) 使用跟1.标记(Mark Phase) 2.清扫(Sweep Phase) 首先垃圾收集器会确定一些根(root):比如线程当前正在执行的方法的局部变量,方法参数,以及所在类的实例变量及所有静态变量。
然后垃圾收集器会从这些根对象出发查找他们所有的引用,然后在被引用的对象上作标记(mark),当垃圾收集器遇上一个已经被标记的对象后就不再往前走了(避免循环标记,造成死循环)。当标记阶段结束后,所有被标记的对象就称为可达对象(Reachable Object)或活对象(Live Object),而所有没有被标记的对象则被认为是垃圾,可以被回收。踪对象的关系图,然后进行收集。
使用跟踪方式的垃圾收集算法主要有以下几种
标记压缩(Mark-Compact) 标记压缩算法的标记阶段和标记清扫算法的标记阶段是一致的,就不再重复。使用标记压缩算法时,标记完可达对象之后,我们不再遍历所有对象清扫垃圾了,我们只需要将所有存活对象向“左”靠齐,让不连续的空间变成连续的,这样就没有内存碎片了。不仅如此,因为不再连续的空间变成连续的,内存分配也更快速了。
标记拷贝(Mark-Copy,也有叫节点复制) 这种算法的一大特点就是将堆空间分为两部分:From,To。开始的时候我们只在From里分配,当From分配满的时候出发垃圾收集,这个时候会找出From空间里所有的存活对象,然后将这些存活的对象拷贝
到To空间里。这样From空间里剩下的就都全是垃圾 JAVA,C# c#提供了GC(grabage collection)专门用于自动回 收垃圾,的垃圾机制,垃圾回收一般被放在 Finalize、Dispose、close方法中
11、现在非常多的用户都在谈SOA,根据Gartner的预测,2008年,企业80%应用都将通过使用SOA来实现,你理解SOA是什么?SOA的关键特点有哪些?SOA带来什么?
面向服务的体系结构 面向服务的体系结构(Service-Oriented Architecture,SOA)是一个组件模型,它将应用程序的不同功能单元(称为服务)通过这些服务之间定义良好的接口和契约联系起来。接口是采用中立的方式进行定义的,它应该独立于实现服务的硬件平台、操作系统和编程语言。这使得构建在各种这样的系统中的服务可以一种统一和通用的方式进行交互。
12、随着互联网的普及,很多新兴的、传统的软件厂商都在探讨SAAS的前景,甚至很多行业观点认为SAAS是软件行业的未来趋势。你是怎么理解SAAS
的,你怎么看待这种趋势?SAAs和更早之前的ASP感念有什么异同?
SaaS(Software-as-a-service)的意思是软件即服务,
SaaS的中文名称为软营或软件运营。SaaS是基于互联网提供软件服务的软件应用模式。作为一种在21世纪开始兴起的创新的软件应用模式,SaaS是软件科技发展的最新趋势 SaaS提供商为企业搭建信息化所需要的所有网络基础设施及软件、硬件运作平台,并负责所有前期的实施、后期的维护等一系列服务,企业无需购买软硬件、建设机房、招聘IT人员,即可通过互联网使用信息系统。就像打开自来水龙头就能用水一样,企业根据实际需要,从SaaS提供商租赁软件服务。
13、指针和引用的相同点和不同点:
★相同点:
●都是地址的概念;
指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名。
★不同点:
●指针是一个实体,而引用仅是个别名;
●引用只能在定义时被初始化一次,之后不可变;指针可变;引用“从一而终”,指针可以“见异思迁”;
●引用没有const,指针有const,const的指针不可变;
●引用不能为空,指针可以为空;
●“sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身的大小;
●指针和引用的自增(++)运算意义不一样;
●引用是类型安全的,而指针不是 (引用比指针多了类型检查
14 、多线程问题
为什么多线程会比单线程更耗时呢?其原因就在于,线程启停以及线程上下文切换都会引起额外的开销,所以消耗的时间比单线程多。
为什么加锁后的三线程比两线程还慢呢?其原因也很简单,那把读写锁就是罪魁祸首。实际情况并不是并行执行,反而成了串行执行,
在采用多线程方法设计程序时,如果产生的额外开销大于线程的工作任务,就没有并行的必要。线程并不是越多越好,软件线程的数量尽量能与硬件线程的数量相匹配。最好根据实际的需要,通过不断的调优,来确定线程数量的最佳值。
采用多核多线程并行设计方案,能有效提高性能,但如果考虑不全面,如忽略带宽、数据竞争及数据同步不当等因素,效率反而降低,程序执行越来越慢。
CPU 亲和力可分为两大类:软亲和力和硬亲和力。
Linux 内核进程调度器天生就具有被称为 CPU 软亲和力(affinity) 的特性,这意味着进程通常不会在处理器之间频繁迁移。这种状态正是我们希望的,因为进程迁移的频率小就意味着产生的负载小。但不代表不会进行小范围的迁移。
CPU 硬亲和力是指进程固定在某个处理器上运行,而不是在不同的处理器之间进行频繁的迁移。这样不仅改善了程序的性能,还提高了程序的可靠性。
从以上不难看出,在某种程度上硬亲和力比软亲和力具有一定的优势。
通过设置 CPU 亲和力来利用多核特性,为提高应用程序性能提供了捷径。同时也是一把双刃剑,如果忽略负载均衡、数据竞争等因素,效率将大打折扣,甚至带来事倍功半的结果。
在进行具体的设计过程中,需要设计良好的数据结构和算法,使其适合于应用的数据移动和处理器的性能特性
15、什么是虚拟存储器?虚拟存储器的特点是什么?
虚拟存储器:在具有层次结构存储器的计算机系统中,自动实现部分装入和部分替换功能,能从逻辑上为用户提供一个比物理贮存容量大得多,可寻址的“主存储器”。
虚拟存储区的容量与物理主存大小无关,而受限于计算机的地址结构和可用磁盘容量。
特点:多次性、对换性、虚拟性。
多次性是指一个作业被分成多次调入内存运行,亦即在作业运行时没有必要将其全部装入,只需将当前要运行的那部分程序和数据装入内存即可;以后每当要运行到尚未调入的那部分程序时,再将它调入。
对换性是指允许在作业的运行过程中进行换进、换出,亦即,在进程运行期间,允许将那些暂不使用的程序和数据,从内存调至外村的对换区(换出),待以后需要时再将它们从外存调至内存(换进)。
虚拟性是指能够从逻辑上扩充内存容量,使用户所看到的内存容量远大于实际内存容量。
16、什么是this指针?其主要功能是什么?
this指针是类的一个自动生成、自动隐藏的私有成员,它存在于类的非静态成员函数中,指向被调用函数所在的对象的地址。
全局仅有一个this指针,当一个对象被创建时,this指针就指向对象数据的首地址。
一种情况就是,在类的非静态成员函数中返回类对象本身的时候,直接使用
return *this;
另外一种情况是当参数与成员变量名相同时使用this指针,如this->n = n (不能写成n= n)
17、C++常见的内存错误:
1. 内存泄露
内存泄露是指应用程序未释放动态申请的且不再使用的内存,原因可能是程序员疏忽或者错误造成程序异常。
在C/C++中,动态申请的内存是在堆上的。如果发送此类的内存泄露,函数每执行一次就丢失一块内存。长时间运行改程序可能引起系统"内存耗尽"。
2. 野指针
未初始化的指针称为野指针。
通常的避免方法就是在指针定义的时候就初始化,初始为NULL或者一个有意义的内存地址。对于动态申请的内存地址,在该内存释放之后,对应指针最好立即赋值为NULL。并在具体使用指针的时候判断指针的值是否为NULL。
3. 内存越界访问
内存越界访问通常发生在数组、字符串或者连续内存的访问。有两种情况:
读越界,即读了非有效的数据。如果所读的内存地址是无效的,程序会立即崩溃。如果所读内存地址是有效的,读入的时候不会有错误,但是读入的数据是随机的,可能会产生不可控制的后果。举个简单的例子,字符串的输出,如果没有结束符,会输出一堆乱码也可能输出正常,也就是说结果是不可控的。
写越界,亦称为缓冲区溢出,通常写越界会发生错误。内存写越界造成的后果是非常严重的。例如访问数组越界可能会修改访问数组的循环变量,造成死循环。
4. 返回指向临时变量的指针
char * getString(){char b[] = "Hello, Tocy!"; return b;}
栈里面的变量都是临时的,函数执行完成之后,相关的临时变量和参数都会被清除。程序不允许返回指向这些临时变量的指针。
通常此类错误编译器会给出警告。不要返回函数的局部变量的任何指针。
5. 试图修改常量
在普通变量前面加上const修饰符,只是给编译器做类型检查用的。编译器禁止修改这样的变量。可以用强制类型转换来处理,一般不会出错。
6. 内存未分配成功,但已经使用
通常是由于程序员认为动态内存分配不会失败。在使用动态申请的内存时,首先检测指针是否为NULL。
7. 内存分配成功,但没有初始化

被折叠的 条评论
为什么被折叠?



