建立网站的基本流程,无需备案的域名,标志空间 网站,百度手机网页版11. 已知strcpy的函数原型#xff1a;char *strcpy(char *strDest, const char *strSrc)其中strDest 是目的字符串#xff0c;strSrc 是源字符串。不调用C/C 的字符串库函数#xff0c;请编写函数 strcpy。 答案#xff1a;
char *strcpy(char *strDest, const char *strS…11. 已知strcpy的函数原型char *strcpy(char *strDest, const char *strSrc)其中strDest 是目的字符串strSrc 是源字符串。不调用C/C 的字符串库函数请编写函数 strcpy。 答案
char *strcpy(char *strDest, const char *strSrc)
{
if ( strDest NULL || strSrc NULL)
return NULL ;
if ( strDest strSrc)
return strDest ;
char *tempptr strDest ;
while( (*strDest *strSrc) ! ‘\0’)
;
return tempptr ;
}
12. 已知String类定义如下
class String
{
public:
String(const char *str NULL); // 通用构造函数
String(const String another); // 拷贝构造函数
~ String(); // 析构函数
String operater (const String rhs); // 赋值函数
private:
char *m_data; // 用于保存字符串
};
尝试写出类的成员函数实现。
答案
String::String(const char *str)
{
if ( str NULL ) //strlen在参数为NULL时会抛异常才会有这步判断
{
m_data new char[1] ;
m_data[0] \0 ;
}
else
{
m_data new char[strlen(str) 1];
strcpy(m_data,str);
}
}
String::String(const String another)
{
m_data new char[strlen(another.m_data) 1];
strcpy(m_data,other.m_data);
} String String::operator (const String rhs)
{
if ( this rhs)
return *this ;
delete []m_data; //删除原来的数据新开一块内存
m_data new char[strlen(rhs.m_data) 1];
strcpy(m_data,rhs.m_data);
return *this ;
} String::~String()
{
delete []m_data ;
}
13. .h头文件中的ifndef/define/endif 的作用
答防止该头文件被重复引用。
14. i ncludefile.h 与 i nclude file.h的区别
答前者是从Standard Library的路径寻找和引用file.h而后者是从当前工作路径搜寻并引用file.h。
15.在C 程序中调用被C 编译器编译后的函数为什么要加extern “C”
首先作为extern是C/C语言中表明函数和全局变量作用范围可见性的关键字该关键字告诉编译器其声明的函数和变量可以在本模块或其它模块中使用。
通常在模块的头文件中对本模块提供给其它模块引用的函数和全局变量以关键字extern声明。例如如果模块B欲引用该模块A中定义的全局变量和函数时只需包含模块A的头文件即可。这样模块B中调用模块A中的函数时在编译阶段模块B虽然找不到该函数但是并不会报错它会在连接阶段中从模块A编译生成的目标代码中找到此函数
extern C是连接申明(linkage declaration),被extern C修饰的变量和函数是按照C语言方式编译和连接的,来看看C中对类似C的函数是怎样编译的
作为一种面向对象的语言C支持函数重载而过程式语言C则不支持。函数被C编译后在符号库中的名字与C语言的不同。例如假设某个函数的原型为
void foo( int x, int y ); 该函数被C编译器编译后在符号库中的名字为_foo而C编译器则会产生像_foo_int_int之类的名字不同的编译器可能生成的名字不同但是都采用了相同的机制生成的新名字称为“mangled name”。
_foo_int_int 这样的名字包含了函数名、函数参数数量及类型信息C就是靠这种机制来实现函数重载的。例如在C中函数void foo( int x, int y )与void foo( int x, float y )编译生成的符号是不相同的后者为_foo_int_float。
同样地C中的变量除支持局部变量外还支持类成员变量和全局变量。用户所编写程序的类成员变量可能与全局变量同名我们以.来区分。而本质上编译器在进行编译时与函数的处理相似也为类中的变量取了一个独一无二的名字这个名字与用户程序中同名的全局变量名字不同。
未加extern C声明时的连接方式
假设在C中模块A的头文件如下
// 模块A头文件 moduleA.h
#ifndef MODULE_A_H
#define MODULE_A_H
int foo( int x, int y );
#endif
在模块B中引用该函数
// 模块B实现文件 moduleB.cpp
i nclude moduleA.h
foo(2,3); 实际上在连接阶段连接器会从模块A生成的目标文件moduleA.obj中寻找_foo_int_int这样的符号
加extern C声明后的编译和连接方式
加extern C声明后模块A的头文件变为
// 模块A头文件 moduleA.h
#ifndef MODULE_A_H
#define MODULE_A_H
extern C int foo( int x, int y );
#endif
在模块B的实现文件中仍然调用foo( 2,3 )其结果是
1模块A编译生成foo的目标代码时没有对其名字进行特殊处理采用了C语言的方式
2连接器在为模块B的目标代码寻找foo(2,3)调用时寻找的是未经修改的符号名_foo。
如果在模块A中函数声明了foo为extern C类型而模块B中包含的是extern int foo( int x, int y ) 则模块B找不到模块A中的函数反之亦然。
所以可以用一句话概括extern “C”这个声明的真实目的任何语言中的任何语法特性的诞生都不是随意而为的来源于真实世界的需求驱动。我们在思考问题时不能只停留在这个语言是怎么做的还要问一问它为什么要这么做动机是什么这样我们可以更深入地理解许多问题实现C与C及其它语言的混合编程。
明白了C中extern C的设立动机我们下面来具体分析extern C通常的使用技巧
extern C的惯用法
1在C中引用C语言中的函数和变量在包含C语言头文件假设为cExample.h时需进行下列处理
extern C
{
i nclude cExample.h
}
而在C语言的头文件中对其外部函数只能指定为extern类型C语言中不支持extern C声明在.c文件中包含了extern C时会出现编译语法错误。
C引用C函数例子工程中包含的三个文件的源代码如下
/* c语言头文件cExample.h */
#ifndef C_EXAMPLE_H
#define C_EXAMPLE_H
extern int add(int x,int y);
#endif /* c语言实现文件cExample.c */
i nclude cExample.h
int add( int x, int y )
{
return x y;
} // c实现文件调用addcppFile.cpp
extern C
{
i nclude cExample.h
}
int main(int argc, char* argv[])
{
add(2,3);
return 0;
}
如果C调用一个C语言编写的.DLL时当包括.DLL的头文件或声明接口函数时应加extern C { }。
2在C中引用C语言中的函数和变量时C的头文件需添加extern C但是在C语言中不能直接引用声明了extern C的该头文件应该仅将C文件中将C中定义的extern C函数声明为extern类型。
C引用C函数例子工程中包含的三个文件的源代码如下
//C头文件 cppExample.h
#ifndef CPP_EXAMPLE_H
#define CPP_EXAMPLE_H
extern C int add( int x, int y );
#endif //C实现文件 cppExample.cpp
i nclude cppExample.h
int add( int x, int y )
{
return x y;
} /* C实现文件 cFile.c
/* 这样会编译出错i nclude cExample.h */
extern int add( int x, int y );
int main( int argc, char* argv[] )
{
add( 2, 3 );
return 0;
}
15题目的解答请参考《C中extern “C”含义深层探索》注解
16. 关联、聚合(Aggregation)以及组合(Composition)的区别
涉及到UML中的一些概念关联是表示两个类的一般性联系比如“学生”和“老师”就是一种关联关系聚合表示has-a的关系是一种相对松散的关系聚合类不需要对被聚合类负责如下图所示用空的菱形表示聚合关系
从实现的角度讲聚合可以表示为:
class A {...} class B { A* a; .....}
而组合表示contains-a的关系关联性强于聚合组合类与被组合类有相同的生命周期组合类要对被组合类负责采用实心的菱形表示组合关系
实现的形式是:
class A{...} class B{ A a; ...}
参考文章http://blog.csdn.net/wfwd/archive/2006/05/30/763753.aspx
http://blog.csdn.net/wfwd/archive/2006/05/30/763760.aspx
17.面向对象的三个基本特征并简单叙述之
1. 封装将客观事物抽象成类每个类对自身的数据和方法实行protection(private, protected,public)
2. 继承广义的继承有三种实现形式实现继承指使用基类的属性和方法而无需额外编码的能力、可视继承子窗体使用父窗体的外观和实现代码、接口继承仅使用属性和方法实现滞后到子类实现。前两种类继承和后一种对象组合接口继承以及纯虚函数构成了功能复用的两种方式。
3. 多态是将父对象设置成为和一个或更多的他的子对象相等的技术赋值之后父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说就是一句话允许将子类类型的指针赋值给父类类型的指针。
18. 重载overload)和重写(overried有的书也叫做“覆盖”的区别
常考的题目。从定义上来说
重载是指允许存在多个同名函数而这些函数的参数表不同或许参数个数不同或许参数类型不同或许两者都不同。
重写是指子类重新定义复类虚函数的方法。
从实现原理上来说
重载编译器根据函数不同的参数表对同名函数的名称做修饰然后这些同名函数就成了不同的函数至少对于编译器来说是这样的。如有两个同名函数function func(p:integer):integer;和function func(p:string):integer;。那么编译器做过修饰后的函数名称可能是这样的int_func、str_func。对于这两个函数的调用在编译器间就已经确定了是静态的。也就是说它们的地址在编译期就绑定了早绑定因此重载和多态无关
重写和多态真正相关。当子类重新定义了父类的虚函数后父类指针根据赋给它的不同的子类指针动态的调用属于子类的该函数这样的函数调用在编译期间是无法确定的调用的子类的虚函数的地址无法给出。因此这样的函数地址是在运行期绑定的晚绑定。
19. 多态的作用
主要是两个1. 隐藏实现细节使得代码能够模块化扩展代码模块实现代码重用2. 接口重用为了类在继承和派生的时候保证使用家族中任一类的实例的某一属性时的正确调用。
20. Ado与Ado.net的相同与不同
除了“能够让应用程序处理存储于DBMS 中的数据“这一基本相似点外两者没有太多共同之处。但是Ado使用OLE DB 接口并基于微软的COM 技术而ADO.NET 拥有自己的ADO.NET 接口并且基于微软的.NET 体系架构。众所周知.NET 体系不同于COM 体系ADO.NET 接口也就完全不同于ADO和OLE DB 接口这也就是说ADO.NET 和ADO是两种数据访问方式。ADO.net 提供对XML 的支持。
21. New delete 与malloc free 的联系与区别?
答案都是在堆(heap)上进行动态的内存操作。用malloc函数需要指定内存分配的字节数并且不能初始化对象new 会自动调用对象的构造函数。delete 会调用对象的destructor而free 不会调用对象的destructor.
22. #define DOUBLE(x) xx i 5*DOUBLE(5) i 是多少
答案i 为30。
23. 有哪几种情况只能用intialization list 而不能用assignment?
答案当类中含有const、reference 成员变量基类的构造函数都需要初始化表。
24. C是不是类型安全的
答案不是。两个不同类型的指针之间可以强制转换用reinterpret cast)。C#是类型安全的。
25. main 函数执行以前还会执行什么代码
答案全局对象的构造函数会在main 函数之前执行。