笔试题总结0000

港控/mmm° 2022-06-13 11:09 325阅读 0赞

1.选一个正确的(A)(此题答案不知道是不是正确的,希望各位指正)

A静态链接库不能有同名全局函数
B动态链接库不能有同名全局函数
C两个静态链接库的同名全局函数不能同时加载

D两个动态链接库的同名全局函数不能同时加载

分析:若两个有A.lib,B.lib,两个静态lib文件,并且全部链接,且A有全局函数fun1,fun2,B有fun2,fun3,如果在代码中调用了属于A的函数也调用属于B的函数(可以不是同名的,比如fun1和fun3),那么连接时会发生冲突(fun2);但是如果只调用了其中一个静态库中的函数,就不会发生冲突,链接器会自动丢掉那个没有被调用过的lib,而且冲突是在编译时不是在运行时。

2.(1) 请说明以下局部变量、全局变量和静态变量的区别?
(2) 局部变量是否可以和全局变量同名?

(1) :

从作用域看:
全局变量
具有全局作用域,全局变量只需在一个源文件中定义,就可以作用于所有的源文件,当然,在不包含该全局变量定义的源文件需要使用extern关键字再次声明这个全局变量;
静态局部变量
具有局部作用域,它只被初始化一次,自从第一次被初始化直到程序运行结束都一直存在,它和全局变量的区别在于全局变量对所有函数可见,而静态句柄变量只对定义它的函数体始终可见;
局部变量
也是局部作用域,它是自动对象(auto),它在程序运行期间不是一直存在的,而是只在函数执行期间存在,函数的一次调用执行结束后,局部变量被撤销,其所占用的内存也被回收;
静态全局变量
具有全局作用域,它和全局变量的区别在于如果程序包含多个文件的话,它仅作用于定义它的文件中,即被static关键字修饰过的全局变量具有文件作用域。这样即使两个不同的源文件都定义了相同名字的静态全局变量,它们也是不同的变量,且不会冲突。
从分配内存空间看:

全局变量、静态局部变量、静态全局变量都是在静态存储区中分配空间的;而局部变量是在栈里分配空间的。

(2)局部变量和全局变量可以同名,在函数内引用这个变量时,会优先使用局部变量,而不是全局变量,要明确调用全局变量时,可以在这个变量名前加全局作用符:”::”。

3.请简述链表和数组的区别和优缺点。

1)数组是顺序存储的,元素在内存空间中一般是连续的;而链表元素间则是一种随机的状态,不一定是顺序连续的;

2)数组一旦显式声明后,其大小是固定的,不能动态扩充;而链表可以动态添加节点元素;

3)链表的插入删除操作简单,不需要移动元素的位置,但它不支持索引操作,要访问某个元素需要遍历链表进行查找;数组支持索引操作,可直接定位到第几个元素位置处,但数组的插入和删除操作时间和空间耗费大,一般需要移动元素的位置。

4.请找出下面程序的错误(转载)

#include

struct String

{

  1. char\* buffer;
  2. unsigned long size;

};

void resize(String* str, int size)

{

  1. char \*tempbuffer = new char\[size\];
  2. if(str->buffer != 0)
  3. \{
  4. if(size > str->size)
  5. \{
  6. size = str->size;
  7. \}
  8. for(int i=0; i<size; ++i)
  9. \{
  10. tempbuffer\[i\] = str->buffer\[i\];
  11. \}
  12. \}
  13. str->buffer = tempbuffer;
  14. str->size = size;

}

void copy(String* a, String* b)

{

  1. resize(a, b->size);
  2. for(int i=0; i<b->size; ++i)
  3. \{
  4. a->buffer\[i\] = b->buffer\[i\];
  5. \}

}

int main(int argc, char* argv[])

{

  1. String a;
  2. resize(&a, 3);
  3. a.buffer\[0\] = 'a';
  4. a.buffer\[1\] = 'b';
  5. a.buffer\[2\] = 'c';
  6. String b;
  7. copy(&b, &a);
  8. printf("%s %s", a.buffer, b.buffer);

}

解答:正确的代码如下:

#include

#include //加头文件:#include

struct String

{

  1. char\* buffer;
  2. unsigned long size;

};

void resize(String* str, int size)

{

  1. assert(str != NULL); //加一句断言是否为空
  2. char \*tempbuffer = new char\[size+1\]; //将数组大小再加1,用于存放结束标志’/0’
  3. if(str->buffer != NULL) //改为标准指针判断非空:!=NULL
  4. \{
  5. if(size > str->size)
  6. \{
  7. str->size = size; //顺序相反了
  8. \}
  9. int i; //独立到外面来
  10. for(i=0; i<size; ++i)
  11. \{
  12. tempbuffer\[i\] = str->buffer\[i\];
  13. \}
  14. tempbuffer\[i\] = '/0'; //加个字符数组结束符
  15. \}
  16. str->buffer = tempbuffer;
  17. str->size = size;

}

void copy(String* a, String* b)

{

  1. resize(a, b->size);
  2. for(int i=0; i<b->size; ++i)
  3. \{
  4. a->buffer\[i\] = b->buffer\[i\];
  5. \}

}

int main(int argc, char* argv[])

{

  1. String a;
  2. a.buffer = new char\[1\]; //需分配一个空间,后面再调整大小
  3. resize(&a, 3);
  4. a.buffer\[0\] = 'a';
  5. a.buffer\[1\] = 'b';
  6. a.buffer\[2\] = 'c';
  7. String b;
  8. b.buffer = new char\[1\]; //需分配一个空间,后面再调整大小
  9. copy(&b, &a);
  10. printf("%s %s", a.buffer, b.buffer);
  11. return 0; //加个返回值

}

5.makefile文件的作用是什么?

makefile文件保存了编译器和链接器的参数选项,还表述了所有源文件之间的关系(源代码文件需要的特定的包含文件、可执行文件要求包含的目标文件模块及库等)。创建程序make首先读取makefile文件,然后激活编译器、链接器、资源编译器和链接器以便产生最后的输出,最后输出并生成的通常是可执行文件。创建程序make利用内置的推理规则来激活编译器,以便通过对特定cpp文件的编译来产生特定的obj文件。

6.一般析构函数都要写成虚函数,请问为什么要这样做,编程给出实例说明这样做的作用?

先看实例代码:

#include

class ASCEBase

{

public:

  1. ASCEBase()\{\};
  2. virtual ~ASCEBase()\{std::cout<<"ASCEBase destructor!"<<std::endl;\};
  3. virtual void Broadcast()
  4. \{
  5. std::cout<<"See you in another life ASCEBase!"<<std::endl;
  6. \}

};

class ASCEDerive : public ASCEBase

{

public:

  1. ASCEDerive()\{\};
  2. ~ASCEDerive()\{std::cout<<"ASCEDerive destructor!"<<std::endl;\}
  3. void Broadcast()
  4. \{
  5. std::cout<<"See you in another life ASCEDerive!"<<std::endl;
  6. \}

};

int main()

{

  1. ASCEBase \*pAsce = new ASCEDerive;
  2. pAsce->Broadcast();
  3. delete pAsce;
  4. system("pause");
  5. return 0;

}

程序运行后输出是:

See you in another life ASCEDerive!

ASCEDerive destructor!

ASCEBase destructor!

这样的程序是正确的,但是,如果将基类ASCEBase析构函数前的virtual去掉,则输出结果是:

See you in another life ASCEDerive!

ASCEBase destructor!

即,派生类ASCEDerive的析构函数并没有被调用!一般情况下类的析构函数中是释放内存资源的代码,这样一来,就很可能造成内存泄漏。

因此,一般将析构函数写出虚函数,是为了当这个类用作基类时,用这个基类指针删除它的派生类的对象时,派生类的析构函数能够被调用到。当然,当一个类不打算作为基类使用时,我们一般不将其声明为虚函数,因为当类里面存在虚函数时,编译器会自动给这个类添加一个虚函数表,里面存放指向虚函数的指针,这无疑会增大类的存储空间。

发表评论

表情:
评论列表 (有 0 条评论,325人围观)

还没有评论,来说两句吧...

相关阅读

    相关 试题总结0001

    1)输出当前源文件的文件名以及源文件的当前行号? 解答: ANSI C标准预定义宏: 1)\_\_LINE\_\_:在源文件中插入当前源代码行号; 2)\_\_FILE

    相关 试题总结0000

    1.选一个正确的(A)(此题答案不知道是不是正确的,希望各位指正) > A静态链接库不能有同名全局函数 > B动态链接库不能有同名全局函数 > C两个静态链

    相关 Java基础常见试题总结

    以下是自己总结的一些Java常见的基础知识题,答案仅供参考,如有异议请指出。一直保持更新状态。 1.什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”?

    相关 试题总结0003

    1.哪些运算符不能重载? 重载操作符的限制:   8.1 并不是所有的操作符都能被重载。除了. ,.\ ,:: ,? : ,sizeof,typeid这几个运算符不能被

    相关 试题总结6.14

    1.序列找数 题目描述:从非负整数序列0,1,2,….,n中给出包含其中n个数的子序列,请找出未出现在该子序列中的那个数。 输入描述:输入为n+1个非负整数,用空格分开。