### IT常见笔试面试题目知识点详解
#### 一、字符串复制函数`strcpy`的实现
**题目背景**: 在不使用C/C++内置字符串处理库的情况下,手动实现字符串复制函数`strcpy`。
**知识点详解**:
1. **函数原型**: `char* strcpy(char* strDest, const char* strSrc);`
- `strDest`: 目标字符串,即复制的目的地。
- `strSrc`: 源字符串,即复制的来源。
2. **实现细节**:
- 首先检查输入参数是否为`NULL`,如果任一参数为`NULL`则返回`NULL`。
- 如果`strDest`和`strSrc`指向同一地址,则直接返回`strDest`。
- 使用临时指针`tempptr`记录`strDest`的原始位置,以便最后返回。
- 循环遍历`strSrc`,将每个字符复制到`strDest`对应的地址上,直到遇到字符串结束标志`\0`。
3. **代码实现**:
```c++
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;
}
```
#### 二、自定义字符串类`String`的实现
**题目背景**: 实现一个简单的字符串类`String`,包含构造函数、拷贝构造函数、赋值运算符以及析构函数。
**知识点详解**:
1. **类结构**:
- `String`: 字符串类。
- `m_data`: 类型为`char*`的私有成员变量,用于存储字符串数据。
2. **构造函数**:
- **普通构造函数**:
- 参数为`const char* str`,默认值为`NULL`。
- 如果`str`为`NULL`,分配一个长度为1的字符数组,并将其初始化为空字符串。
- 否则,计算`str`的长度并分配相应大小的内存,然后使用`strcpy`进行复制。
- **拷贝构造函数**:
- 参数为`const String& other`。
- 分配与`other`等长的内存,并使用`strcpy`复制字符串。
3. **赋值运算符**:
- 参数为`const String& other`。
- 首先检查`this`与`other`是否相同,如果相同则直接返回`*this`。
- 删除当前的`m_data`,重新分配内存并使用`strcpy`复制字符串。
4. **析构函数**:
- 负责释放`m_data`所指向的内存。
5. **代码实现**:
```c++
class String {
public:
String(const char* str = NULL);
String(const String& other);
~String();
String& operator=(const String& other);
private:
char* m_data;
};
String::String(const char* str) {
if (str == 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& other) {
m_data = new char[strlen(other.m_data) + 1];
strcpy(m_data, other.m_data);
}
String& String::operator=(const String& other) {
if (this == &other)
return *this;
delete[] m_data;
m_data = new char[strlen(other.m_data) + 1];
strcpy(m_data, other.m_data);
return *this;
}
String::~String() {
delete[] m_data;
}
```
#### 三、C/C++编程基础知识
1. **头文件中的`ifndef/define/endif`的作用**:
- 防止头文件被重复包含。当多个文件同时包含了同一个头文件时,`ifndef/define/endif`结构可以确保头文件中的内容只被编译一次。
2. **`#include <filename.h>`与`#include "filename.h"`的区别**:
- `#include <filename.h>`: 编译器从标准库路径开始搜索文件。
- `#include "filename.h"`: 编译器从用户的工作路径开始搜索文件。
3. **C++中调用C编译的函数为什么需要`extern "C"`**:
- C++支持函数重载,而C不支持。因此,C++编译器会对函数名称进行修改(名称修饰)。使用`extern "C"`告诉C++编译器按照C的方式处理函数名。
4. **构造函数的执行顺序**:
- 如果类中有基类或成员对象,则构造函数的执行顺序为:
1. 先执行基类的构造函数(若有虚基类,则先执行虚基类)。
2. 再执行成员对象的构造函数。
3. 最后执行自身类的构造函数。
5. **设计模式**:
- 设计模式是一种在特定情况下解决问题的标准方法。常见的设计模式包括工厂模式、单例模式、观察者模式等。
6. **聚合与组合的区别**:
- **聚合**: 表示“has-a”关系,意味着一个对象拥有另一个对象,但二者之间没有紧密绑定。例如,一本书有许多页(`Book has many Pages`)。
- **组合**: 表示“part-of”关系,意味着一个对象是另一个对象的一部分,二者之间有很强的依赖关系。例如,一本书放在书架上(`Book is part of Bookshelf`)。
7. **C#与C++的区别**:
- **垃圾回收机制**: C#具备自动垃圾回收机制,而C++需要手动管理内存。
- **指针**: C#不允许直接操作指针,除非在`unsafe`上下文中;而C++允许使用指针。
- **继承**: C#只支持单继承,而C++支持多重继承。
- **静态成员访问**: C#必须通过类名访问静态成员,而在C++中可以通过对象访问静态成员。
- **函数重写**: 在C#中,重写基类方法需要使用`override`关键字,在C++中则不需要显式使用关键字。
以上知识点涵盖了从基础的字符串操作到高级的面向对象设计模式等内容,对于准备IT笔试面试的同学来说是非常有价值的复习资料。