面试题-----strcpy

题目:

  已知strcpy函数的原型是:
  char * strcpy(char * strDest,const char * strSrc);
  1.不调用库函数,实现strcpy函数。
  2.解释为什么要返回char *。

解说:

  1.strcpy的实现代码
  char * strcpy(char * strDest,const char * strSrc)
  {
  char * strDestCopy=strDest; //[3]
  if ((strDest==NULL)||(strSrc==NULL)) //[1]
  throw "Invalid argument(s)"; //[2]
  while ((*strDest++=*strSrc++)!='\0'); //[4]
  return strDestCopy;
  }
  错误的做法:
  [1]
  (A)不检查指针的有效性,说明答题者不注重代码的健壮性。
  (B)检查指针的有效性时使用((!strDest)||(!strSrc))或(!(strDest&&strSrc)),说明答题者对C语言中类型的隐式转换没有深刻认识。在本例中char *转换为bool即是类型隐式转换,这种功能虽然灵活,但更多的是导致出错概率增大和维护成本升高。所以C++专门增加了bool、true、false三个关键字以提供更安全的条件表达式。
  (C)检查指针的有效性时使用((strDest==0)||(strSrc==0)),说明答题者不知道使用常量的好处。直接使用字面常量(如本例中的0)会减少程序的可维护性。0虽然简单,但程序中可能出现很多处对指针的检查,万一出现笔误, 编译器不能发现,生成的程序内含逻辑错误,很难排除。而使用NULL代替0,如果出现拼写错误,编译器就会检查出来。
  [2]
  (A)return new string("Invalid argument(s)");,说明答题者根本不知道返回值的用途,并且他对内存泄漏也没有警惕心。从函数中返回函数体内分配的内存是十分危险的做法,他把释放内存的义务抛给不知情的调用者,绝大多数情况下,调用者不会释放内存,这导致内存泄漏。
  (B)return 0;,说明答题者没有掌握异常机制。调用者有可能忘记检查返回值,调用者还可能无法检查返回值(见后面的链式表达式)。妄想让返回值肩负返回正确值和异常值的双重功能,其结果往往是两种功能都失效。应该以抛出异常来代替返回值,这样可以减轻调用者的负担、使错误不会被忽略、增强程序的可维护性。
  [3]
  (A)忘记保存原始的strDest值,说明答题者逻辑思维不严密。
  [4]
  (A)循环写成while (*strDest++=*strSrc++);,同[1](B)。
  (B)循环写成while (*strSrc!='\0') *strDest++=*strSrc++;,说明答题者对边界条件的检查不力。循环体结束后,strDest字符串的末尾没有正确地加上'\0'。
  2.返回strDest的原始值使函数能够支持链式表达式,增加了函数的“附加值”。同样功能的函数,如果能合理地提高的可用性,自然就更加理想。
<think>嗯,用户想要找C++相关的笔试和面试题,特别是第2到25题。不过根据提供的参考引用,里面只提到了第一个问题关于C++和C的区别,后面的题目可能没显示出来。首先,我需要确认用户的需求是不是需要我根据现有的资料生成更多题目,或者是否有其他来源的信息可用。 不过用户可能没有意识到参考内容有限,所以需要我根据常见的C++面试题来补充2到25题。接下来,我需要回忆常见的C++面试问题,涵盖基础概念、面向对象、内存管理、STL、新特性等方面,确保覆盖全面且难度适中。 然后,我要按照用户的要求,使用中文回答,结构清晰,分步骤解释每个问题,并提供详细的解析。同时,注意数学公式的格式是否正确,比如使用$...$和$$...$$。虽然大部分C++问题可能不涉及数学公式,但如果有相关的内容,比如算法复杂度,就需要正确应用格式。 另外,用户提到要生成相关问题,可能需要我在回答完问题后,再提出一些扩展问题,帮助用户深入理解。不过根据示例,用户可能希望在每个问题解析后添加相关问题,或者最后统一添加。需要根据示例结构来处理。 最后,检查所有回答是否符合LaTeX语法,确保没有格式错误,同时引用标记正确。可能需要在每个引用的地方添加[^1],但根据参考内容,只有引用[1]可用,所以需要确认是否需要其他引用来源,或者仅使用现有的。</think>以下是整理的C++笔试/面试题第2到25题及详细解析,涵盖常见核心知识点: --- ### **2. 指针和引用的区别是什么?** - **指针**是变量,存储内存地址,可重新指向其他对象,允许空值(`nullptr`),需要解引用操作符`*`访问值。 - **引用**是别名,必须在初始化时绑定对象,不能重新绑定,不能为空,直接通过名称访问对象。 ```cpp int a = 10; int *p = &a; // 指针 int &r = a; // 引用 ``` --- ### **3. `const`和`constexpr`的区别** - `const`表示“只读”,运行时确定值(如`const int x = func();`)。 - `constexpr`表示编译期常量,要求表达式可在编译时求值(如`constexpr int y = 42;`)。 --- ### **4. 虚函数如何实现多态?** 通过虚函数表(vtable)和虚函数指针(vptr)实现。每个包含虚函数的类有一个vtable,存储函数指针;对象通过vptr访问vtable,实现动态绑定。 --- ### **5. 堆和栈的内存分配区别** | **特征** | **堆** | **栈** | |----------------|---------------------------|---------------------| | 分配方式 | 手动分配(`new/malloc`) | 自动分配(编译器) | | 内存大小 | 较大,动态扩展 | 较小,固定 | | 访问速度 | 较慢 | 较快 | | 生命周期 | 手动释放 | 作用域结束自动释放 | --- ### **6. 什么是深拷贝和浅拷贝?** - **浅拷贝**:仅复制指针,新旧对象指向同一内存。 - **深拷贝**:复制指针指向的内容,新旧对象独立。 ```cpp class String { public: char* data; // 深拷贝构造函数 String(const String& other) { data = new char[strlen(other.data) + 1]; strcpy(data, other.data); } }; ``` --- ### **7. `new`和`malloc`的区别** | **特征** | `new` | `malloc` | |----------------|---------------------------|-----------------------| | 类型安全 | 是 | 否 | | 调用构造函数 | 是 | 否 | | 返回类型 | 具体类型指针 | `void*` | | 内存大小计算 | 自动 | 手动指定 | | 失败处理 | 抛出异常 | 返回`NULL` | --- ### **8. 什么是RAII?** RAII(资源获取即初始化)通过对象的生命周期管理资源(如内存、文件句柄)。资源在构造函数中获取,在析构函数中释放,避免泄漏。 ```cpp class FileHandle { public: FileHandle(const char* filename) { file = fopen(filename, "r"); } ~FileHandle() { if (file) fclose(file); } private: FILE* file; }; ``` --- ### **9. `std::vector`的底层实现** `std::vector`使用动态数组,元素连续存储。当容量不足时,重新分配更大的内存(通常2倍扩容),并拷贝原有元素。 --- ### **10. 智能指针类型及用途** - `unique_ptr`:独占所有权,不可拷贝,可移动。 - `shared_ptr`:共享所有权,引用计数。 - `weak_ptr`:解决`shared_ptr`循环引用问题,不增加计数。 --- ### **11. 什么是右值引用?** 右值引用(`T&&`)用于标识临时对象,支持移动语义(转移资源而非拷贝),提升性能。 ```cpp std::string s1 = "Hello"; std::string s2 = std::move(s1); // s1资源转移到s2 ``` --- ### **12. 虚析构函数的作用** 若基类指针指向派生类对象,基类析构函数非虚时,删除指针会导致派生类析构函数未调用,引发内存泄漏。虚析构函数确保正确调用所有析构函数。 --- ### **13. `override`和`final`关键字** - `override`:显式标记重写虚函数,增强代码可读性。 - `final`:禁止类被继承或虚函数被重写。 ```cpp class Base { public: virtual void func() {} }; class Derived : public Base { public: void func() override final {} // 正确重写且禁止进一步重写 }; ``` --- ### **14. 模板元编程的应用场景** - 编译期计算(如斐波那契数列)。 - 类型检查与转换(`std::is_integral`)。 - 优化代码(避免运行时开销)。 --- ### **15. `volatile`关键字的作用** 告诉编译器变量可能被外部修改(如硬件寄存器),禁止优化相关代码,确保每次访问都从内存读取。 --- ### **16. 什么是SFINAE?** “替换失败不是错误”原则,用于模板元编程中通过条件启用/禁用特定重载。 ```cpp template<typename T> auto foo(T t) -> decltype(t.size(), void()) { // 仅当T有size()方法时启用 } ``` --- ### **17. Lambda表达式的组成部分** ```cpp [capture](params) mutable -> ret_type { body } ``` - **捕获列表**:`[=]`(值捕获)、`[&]`(引用捕获)。 - **参数列表**:与普通函数参数类似。 - **可变规范**:`mutable`允许修改值捕获的变量。 - **返回类型**:可自动推导或显式指定。 --- ### **18. `std::unordered_map`的冲突解决** 使用开链法(每个桶存储链表),当哈希冲突时,元素添加到同一桶的链表中。 --- ### **19. 什么是移动构造函数?** 移动构造函数通过“窃取”资源(如动态内存)初始化新对象,避免深拷贝,参数为右值引用。 ```cpp class Vector { public: Vector(Vector&& other) : data(other.data), size(other.size) { other.data = nullptr; // 置空原对象指针 } }; ``` --- ### **20. `noexcept`关键字的用途** 标记函数不会抛出异常,帮助编译器优化代码。若标记为`noexcept`的函数抛出异常,程序终止。 --- ### **21. 类型推导规则(`auto`和`decltype`)** - `auto`:推导变量类型,忽略顶层`const`和引用。 - `decltype`:保留表达式类型(包括引用和`const`)。 ```cpp int a = 10; const int& b = a; auto c = b; // c类型为int decltype(b) d = a; // d类型为const int& ``` --- ### **22. 什么是CRTP?** 奇异递归模板模式(Curiously Recurring Template Pattern),通过基类模板派生类实现静态多态。 ```cpp template<typename T> class Base { public: void interface() { static_cast<T*>(this)->impl(); } }; class Derived : public Base<Derived> { public: void impl() { /* ... */ } }; ``` --- ### **23. `std::async`的启动策略** - `std::launch::async`:异步执行任务。 - `std::launch::deferred`:延迟执行(调用`get()`时执行)。 - 默认策略为两者组合,由系统决定。 --- ### **24. 什么是内存对齐?** 数据在内存中的地址需为特定值的倍数(如4字节对齐),以提升CPU访问效率。可通过`alignas`指定对齐方式。 ```cpp struct alignas(16) AlignedStruct { float data[4]; }; ``` --- ### **25. C++17新特性举例** - 结构化绑定:`auto [x, y] = std::make_pair(1, 2);` - `if constexpr`:编译期条件判断。 - 内联变量:允许头文件中定义`inline`变量。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值