乐闻世界logo
搜索文章和话题

面试题手册

C++ 指针与引用的区别是什么

C++ 指针与引用的区别C++ 中指针和引用是两个重要的概念,它们在语法和使用上有很多相似之处,但在底层实现和特性上存在显著差异。主要区别1. 内存占用指针:占用 4 字节(32 位系统)或 8 字节(64 位系统)的内存空间引用:不占用额外内存空间,只是变量的别名2. 初始化要求指针:可以不初始化,声明时可以不指向任何有效地址引用:必须在声明时初始化,且一旦绑定就不能改变3. 空值处理指针:可以设置为 nullptr 或 NULL,表示不指向任何对象引用:不能为空,必须始终引用一个有效的对象4. 重新赋值指针:可以重新赋值,指向不同的对象引用:一旦初始化后,不能改变引用的对象5. 运算符指针:使用 * 和 -> 运算符访问指向的对象引用:直接使用变量名访问,无需额外运算符6. 多级引用指针:支持多级指针(如 int**)引用:不支持多级引用使用场景指针适用于:需要动态内存分配需要重新赋值指向不同对象需要表示"无对象"的状态实现数据结构(链表、树等)引用适用于:函数参数传递,避免拷贝开销函数返回值,支持链式调用运算符重载确保参数不为空的情况代码示例// 指针示例int* ptr = nullptr;int a = 10;ptr = &a;*ptr = 20; // a 的值变为 20// 引用示例int b = 10;int& ref = b;ref = 30; // b 的值变为 30// 函数参数示例void swap(int* x, int* y) { int temp = *x; *x = *y; *y = temp;}void swap(int& x, int& y) { int temp = x; x = y; y = temp;}注意事项在现代 C++ 中,优先使用引用和智能指针,避免使用裸指针引用在函数参数中使用时,可以提供更好的代码可读性指针需要手动管理内存,容易导致内存泄漏,建议使用智能指针(std::uniqueptr, std::sharedptr)
阅读 0·2月18日 17:33

C++ 多态的实现机制有哪些

C++ 多态的实现机制多态是面向对象编程的核心特性之一,C++ 通过虚函数和继承机制实现了编译时多态和运行时多态。多态的类型1. 编译时多态(静态多态)函数重载运算符重载模板(泛型编程)2. 运行时多态(动态多态)虚函数纯虚函数抽象类虚函数实现多态基本示例:class Animal {public: virtual void makeSound() { std::cout << "Animal makes a sound" << std::endl; } virtual ~Animal() {}};class Dog : public Animal {public: void makeSound() override { std::cout << "Dog barks" << std::endl; }};class Cat : public Animal {public: void makeSound() override { std::cout << "Cat meows" << std::endl; }};// 使用多态void animalSound(Animal* animal) { animal->makeSound(); // 动态绑定}int main() { Dog dog; Cat cat; animalSound(&dog); // 输出: Dog barks animalSound(&cat); // 输出: Cat meows return 0;}纯虚函数与抽象类纯虚函数:class Shape {public: virtual double area() = 0; // 纯虚函数 virtual double perimeter() = 0; virtual ~Shape() {} // 虚析构函数};class Rectangle : public Shape {private: double width; double height;public: Rectangle(double w, double h) : width(w), height(h) {} double area() override { return width * height; } double perimeter() override { return 2 * (width + height); }};class Circle : public Shape {private: double radius;public: Circle(double r) : radius(r) {} double area() override { return 3.14159 * radius * radius; } double perimeter() override { return 2 * 3.14159 * radius; }};// 使用void printShapeInfo(Shape* shape) { std::cout << "Area: " << shape->area() << std::endl; std::cout << "Perimeter: " << shape->perimeter() << std::endl;}int main() { Rectangle rect(5, 3); Circle circle(2); printShapeInfo(&rect); // Rectangle 的实现 printShapeInfo(&circle); // Circle 的实现 return 0;}虚析构函数为什么需要虚析构函数:class Base {public: virtual ~Base() { std::cout << "Base destructor" << std::endl; }};class Derived : public Base {private: int* data;public: Derived() : data(new int[100]) {} ~Derived() { delete[] data; std::cout << "Derived destructor" << std::endl; }};// 正确使用Base* ptr = new Derived();delete ptr; // 正确调用 Derived 和 Base 的析构函数// 如果 Base 的析构函数不是虚函数class BaseNoVirtual {public: ~BaseNoVirtual() { // 非虚析构函数 std::cout << "BaseNoVirtual destructor" << std::endl; }};class DerivedNoVirtual : public BaseNoVirtual {private: int* data;public: DerivedNoVirtual() : data(new int[100]) {} ~DerivedNoVirtual() { delete[] data; std::cout << "DerivedNoVirtual destructor" << std::endl; }};// 错误使用BaseNoVirtual* ptr2 = new DerivedNoVirtual();delete ptr2; // 只调用 BaseNoVirtual 的析构函数,内存泄漏!override 关键字使用 override 确保正确重写:class Base {public: virtual void func1() {} virtual void func2(int x) {}};class Derived : public Base {public: void func1() override { // 正确重写 std::cout << "Derived func1" << std::endl; } // void func2() override; // 编译错误:参数不匹配 // void func3() override; // 编译错误:基类没有 func3};final 关键字阻止进一步重写或继承:class Base {public: virtual void func() final { // 不能被重写 std::cout << "Base func" << std::endl; }};class Derived1 : public Base {public: // void func() override; // 编译错误:func 是 final};class FinalClass final { // 不能被继承public: void method() {}};// class Derived2 : public FinalClass {}; // 编译错误:FinalClass 是 final运行时类型识别(RTTI)dynamic_cast:class Animal {public: virtual ~Animal() {}};class Dog : public Animal {public: void bark() { std::cout << "Woof!" << std::endl; }};class Cat : public Animal {public: void meow() { std::cout << "Meow!" << std::endl; }};void processAnimal(Animal* animal) { if (Dog* dog = dynamic_cast<Dog*>(animal)) { dog->bark(); } else if (Cat* cat = dynamic_cast<Cat*>(animal)) { cat->meow(); }}// 使用Dog dog;Cat cat;processAnimal(&dog); // 输出: Woof!processAnimal(&cat); // 输出: Meow!typeid:#include <typeinfo>class Base {public: virtual ~Base() {}};class Derived : public Base {};int main() { Base* base = new Derived(); std::cout << "Type name: " << typeid(*base).name() << std::endl; std::cout << "Is Derived: " << (typeid(*base) == typeid(Derived)) << std::endl; delete base; return 0;}多态的实际应用策略模式:class SortStrategy {public: virtual void sort(std::vector<int>& data) = 0; virtual ~SortStrategy() {}};class BubbleSort : public SortStrategy {public: void sort(std::vector<int>& data) override { std::cout << "Using Bubble Sort" << std::endl; // 冒泡排序实现 }};class QuickSort : public SortStrategy {public: void sort(std::vector<int>& data) override { std::cout << "Using Quick Sort" << std::endl; // 快速排序实现 }};class Sorter {private: SortStrategy* strategy;public: void setStrategy(SortStrategy* s) { strategy = s; } void sort(std::vector<int>& data) { strategy->sort(data); }};// 使用Sorter sorter;BubbleSort bubbleSort;QuickSort quickSort;std::vector<int> data = {5, 2, 8, 1, 9};sorter.setStrategy(&bubbleSort);sorter.sort(data); // 使用冒泡排序sorter.setStrategy(&quickSort);sorter.sort(data); // 使用快速排序观察者模式:class Observer {public: virtual void update(const std::string& message) = 0; virtual ~Observer() {}};class Subject {private: std::vector<Observer*> observers;public: void attach(Observer* observer) { observers.push_back(observer); } void detach(Observer* observer) { observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end()); } void notify(const std::string& message) { for (auto observer : observers) { observer->update(message); } }};class EmailObserver : public Observer {public: void update(const std::string& message) override { std::cout << "Email: " << message << std::endl; }};class SMSObserver : public Observer {public: void update(const std::string& message) override { std::cout << "SMS: " << message << std::endl; }};// 使用Subject subject;EmailObserver emailObserver;SMSObserver smsObserver;subject.attach(&emailObserver);subject.attach(&smsObserver);subject.notify("Hello World!");// 输出:// Email: Hello World!// SMS: Hello World!编译时多态函数重载:class Printer {public: void print(int value) { std::cout << "Int: " << value << std::endl; } void print(double value) { std::cout << "Double: " << value << std::endl; } void print(const std::string& value) { std::cout << "String: " << value << std::endl; }};// 使用Printer printer;printer.print(42); // 调用 print(int)printer.print(3.14); // 调用 print(double)printer.print("Hello"); // 调用 print(string)运算符重载:class Complex {private: double real; double imag;public: Complex(double r = 0, double i = 0) : real(r), imag(i) {} Complex operator+(const Complex& other) const { return Complex(real + other.real, imag + other.imag); } Complex operator*(const Complex& other) const { return Complex(real * other.real - imag * other.imag, real * other.imag + imag * other.real); } friend std::ostream& operator<<(std::ostream& os, const Complex& c) { os << c.real << " + " << c.imag << "i"; return os; }};// 使用Complex c1(1, 2);Complex c2(3, 4);Complex sum = c1 + c2;Complex product = c1 * c2;std::cout << sum << std::endl; // 4 + 6istd::cout << product << std::endl; // -5 + 10i模板(静态多态):template <typename T>T add(T a, T b) { return a + b;}// 使用int intResult = add(10, 20); // T = intdouble doubleResult = add(3.14, 2.71); // T = double// CRTP(奇异递归模板模式)template <typename Derived>class Base {public: void interface() { static_cast<Derived*>(this)->implementation(); }};class Derived : public Base<Derived> {public: void implementation() { std::cout << "Derived implementation" << std::endl; }};// 使用Derived d;d.interface(); // 输出: Derived implementation最佳实践1. 始终为多态基类声明虚析构函数class Base {public: virtual ~Base() = default; // 虚析构函数};2. 使用 override 关键字确保正确重写class Derived : public Base {public: void func() override { // 明确表示重写 // 实现 }};3. 优先使用组合而非继承// 推荐:组合class Engine {public: void start() { std::cout << "Engine started" << std::endl; }};class Car {private: Engine engine;public: void start() { engine.start(); }};// 不推荐:过度继承class Vehicle {public: virtual void start() = 0;};class Car : public Vehicle {public: void start() override { std::cout << "Car started" << std::endl; }};4. 避免过度使用 dynamic_cast// 不推荐if (Dog* dog = dynamic_cast<Dog*>(animal)) { dog->bark();} else if (Cat* cat = dynamic_cast<Cat*>(animal)) { cat->meow();}// 推荐:使用虚函数class Animal {public: virtual void makeSound() = 0;};class Dog : public Animal {public: void makeSound() override { bark(); } void bark() { std::cout << "Woof!" << std::endl; }};注意事项虚函数调用有性能开销,避免在性能关键路径过度使用构造函数和析构函数中调用虚函数不会发生动态绑定不要在构造函数中调用纯虚函数虚函数不能是静态成员函数避免在基类构造函数中调用虚函数考虑使用 final 关键字阻止不必要的重写谨慎使用 RTTI,它可能影响性能和可维护性
阅读 0·2月18日 17:33

C++ 虚函数的实现原理是什么

C++ 虚函数的实现原理虚函数是 C++ 实现多态性的核心机制,理解其实现原理对于深入掌握 C++ 至关重要。虚函数表(vtable)虚函数通过虚函数表(Virtual Function Table,简称 vtable)来实现。每个包含虚函数的类都有一个对应的虚函数表。vtable 的特点:vtable 是一个静态数组,存储着该类所有虚函数的函数指针每个对象在内存中都有一个指向 vtable 的指针(vptr),通常位于对象内存布局的起始位置vtable 在编译时生成,存储在程序的只读数据段内存布局包含虚函数的对象内存布局:+------------------+| vptr (虚表指针) | 指向该类的 vtable+------------------+| 成员变量 1 |+------------------+| 成员变量 2 |+------------------+| ... |+------------------+vtable 的结构:+------------------+| type_info 指针 | 用于 RTTI(运行时类型识别)+------------------+| 虚函数 1 指针 |+------------------+| 虚函数 2 指针 |+------------------+| ... |+------------------+虚函数调用过程当调用虚函数时,编译器会生成类似以下的代码:// 假设调用:obj->virtualFunction()// 编译器生成的伪代码:(*(obj->vptr)[index])(obj)调用步骤:通过对象的 vptr 找到对应的 vtable根据虚函数在 vtable 中的索引找到函数指针通过函数指针调用实际的函数继承中的 vtable单继承:派生类会继承基类的 vtable派生类重写的虚函数会替换 vtable 中对应的函数指针派生类新增的虚函数会追加到 vtable 的末尾多重继承:派生类会有多个 vtable,每个基类对应一个对象中会有多个 vptr,分别指向不同的 vtable调用虚函数时需要根据基类类型选择正确的 vtable纯虚函数和抽象类纯虚函数:class Shape {public: virtual void draw() = 0; // 纯虚函数 virtual double area() = 0;};特点:纯虚函数在 vtable 中对应的函数指针为 nullptr包含纯虚函数的类称为抽象类,不能实例化派生类必须实现所有纯虚函数才能实例化虚析构函数为什么需要虚析构函数:class Base {public: virtual ~Base() { // 虚析构函数 cout << "Base destructor" << endl; }};class Derived : public Base {public: ~Derived() { cout << "Derived destructor" << endl; }};Base* ptr = new Derived();delete ptr; // 正确调用 Derived 和 Base 的析构函数如果不声明为虚析构函数:只会调用基类的析构函数,导致派生类资源泄漏性能考虑虚函数调用的开销:需要通过 vptr 间接访问 vtable需要通过函数指针间接调用函数破坏了内联优化的可能性优化建议:在性能关键的代码中,避免过度使用虚函数考虑使用 final 关键字阻止进一步重写,可能帮助编译器优化使用 CRTP(奇异递归模板模式)实现静态多态代码示例#include <iostream>using namespace std;class Animal {public: virtual void makeSound() { cout << "Animal makes a sound" << endl; } virtual ~Animal() { cout << "Animal destructor" << endl; }};class Dog : public Animal {public: void makeSound() override { cout << "Dog barks" << endl; } ~Dog() override { cout << "Dog destructor" << endl; }};class Cat : public Animal {public: void makeSound() override { cout << "Cat meows" << endl; } ~Cat() override { cout << "Cat destructor" << endl; }};int main() { Animal* animals[2]; animals[0] = new Dog(); animals[1] = new Cat(); for (int i = 0; i < 2; i++) { animals[i]->makeSound(); // 动态绑定 } for (int i = 0; i < 2; i++) { delete animals[i]; // 正确调用派生类析构函数 } return 0;}注意事项虚函数不能是静态函数(static)构造函数不能是虚函数析构函数应该是虚函数,除非确定不会被多态使用在构造函数和析构函数中调用虚函数,不会发生动态绑定
阅读 0·2月18日 17:32

C++ 智能指针的使用场景和区别有哪些

C++ 智能指针的使用场景和区别C++11 引入了智能指针,用于自动管理动态分配的内存,避免内存泄漏和悬空指针问题。智能指针是 RAII(资源获取即初始化)模式的典型应用。三种主要智能指针1. std::unique_ptr独占所有权的智能指针同一时刻只能有一个 unique_ptr 指向对象不可复制,只能移动轻量级,几乎没有额外开销2. std::shared_ptr共享所有权的智能指针多个 shared_ptr 可以指向同一个对象使用引用计数管理对象生命周期可以复制和移动3. std::weak_ptr不控制对象生命周期的智能指针必须与 shared_ptr 配合使用用于解决 shared_ptr 的循环引用问题不增加引用计数使用场景std::unique_ptr 适用场景:对象的所有权明确,不需要共享作为函数返回值返回动态分配的对象容器中存储动态分配的对象Pimpl(Pointer to Implementation)模式std::shared_ptr 适用场景:多个对象需要共享同一个资源对象的生命周期不确定,需要延迟释放异步编程中传递对象缓存系统中共享资源std::weak_ptr 适用场景:观察者模式中避免循环引用缓存系统中避免强引用导致资源无法释放打破 shared_ptr 的循环引用代码示例std::unique_ptr 示例:#include <memory>#include <iostream>class Widget {public: Widget() { std::cout << "Widget constructed\n"; } ~Widget() { std::cout << "Widget destroyed\n"; } void doSomething() { std::cout << "Widget doing something\n"; }};// 创建 unique_ptrstd::unique_ptr<Widget> ptr1 = std::make_unique<Widget>();// 移动语义std::unique_ptr<Widget> ptr2 = std::move(ptr1);// ptr1 现在为 nullptr// 自定义删除器auto deleter = [](Widget* w) { std::cout << "Custom deleter\n"; delete w;};std::unique_ptr<Widget, decltype(deleter)> ptr3(new Widget(), deleter);// 作为函数参数void processWidget(std::unique_ptr<Widget> ptr) { ptr->doSomething();}processWidget(std::move(ptr2));std::shared_ptr 示例:#include <memory>#include <iostream>class Resource {public: Resource() { std::cout << "Resource created\n"; } ~Resource() { std::cout << "Resource destroyed\n"; }};// 创建 shared_ptrstd::shared_ptr<Resource> ptr1 = std::make_shared<Resource>();std::cout << "Use count: " << ptr1.use_count() << "\n"; // 1// 复制std::shared_ptr<Resource> ptr2 = ptr1;std::cout << "Use count: " << ptr1.use_count() << "\n"; // 2// 移动std::shared_ptr<Resource> ptr3 = std::move(ptr1);std::cout << "Use count: " << ptr2.use_count() << "\n"; // 2std::cout << "ptr1 is " << (ptr1 ? "not null" : "null") << "\n"; // null// 自定义删除器auto deleter = [](Resource* r) { std::cout << "Custom deleter for Resource\n"; delete r;};std::shared_ptr<Resource> ptr4(new Resource(), deleter);std::weak_ptr 示例:#include <memory>#include <iostream>class Node {public: std::shared_ptr<Node> next; std::weak_ptr<Node> prev; // 使用 weak_ptr 避免循环引用 Node() { std::cout << "Node created\n"; } ~Node() { std::cout << "Node destroyed\n"; }};void createCycle() { auto node1 = std::make_shared<Node>(); auto node2 = std::make_shared<Node>(); node1->next = node2; node2->prev = node1; // weak_ptr 不会增加引用计数 // node1 和 node2 可以正常释放}// 使用 weak_ptr 检查对象是否存在std::weak_ptr<int> weakPtr;{ auto sharedPtr = std::make_shared<int>(42); weakPtr = sharedPtr; if (auto locked = weakPtr.lock()) { std::cout << "Value: " << *locked << "\n"; // 42 } else { std::cout << "Object has been destroyed\n"; }}// sharedPtr 离开作用域,对象被销毁if (auto locked = weakPtr.lock()) { std::cout << "Value: " << *locked << "\n";} else { std::cout << "Object has been destroyed\n"; // 执行这里}性能比较内存开销:unique_ptr:几乎无额外开销,只包含一个原始指针shared_ptr:包含两个指针(控制块 + 对象指针),约 16 字节weakptr:与 sharedptr 类似,包含控制块指针操作开销:unique_ptr:所有操作都是 O(1),无额外开销shared_ptr:复制和销毁需要原子操作修改引用计数weak_ptr:lock() 操作需要原子操作循环引用问题问题示例:class A {public: std::shared_ptr<B> b_ptr;};class B {public: std::shared_ptr<A> a_ptr; // 导致循环引用};auto a = std::make_shared<A>();auto b = std::make_shared<B>();a->b_ptr = b;b->a_ptr = a;// a 和 b 的引用计数永远不会变为 0,内存泄漏解决方案:class B {public: std::weak_ptr<A> a_ptr; // 使用 weak_ptr 打破循环};最佳实践1. 优先使用 std::makeunique 和 std::makeshared// 推荐auto ptr = std::make_unique<Widget>();auto ptr = std::make_shared<Resource>();// 不推荐auto ptr = std::unique_ptr<Widget>(new Widget());auto ptr = std::shared_ptr<Resource>(new Resource());2. 使用 std::move 转移 unique_ptr 所有权std::unique_ptr<Widget> createWidget() { return std::make_unique<Widget>();}auto ptr = createWidget(); // 移动构造3. 避免从裸指针创建 shared_ptrint* raw = new int(42);std::shared_ptr<int> ptr1(raw);std::shared_ptr<int> ptr2(raw); // 错误!会导致双重释放4. 使用 std::enablesharedfrom_thisclass MyClass : public std::enable_shared_from_this<MyClass> {public: std::shared_ptr<MyClass> getShared() { return shared_from_this(); }};auto obj = std::make_shared<MyClass>();auto shared = obj->getShared();注意事项不要混用裸指针和智能指针管理同一个对象在多线程环境中使用 shared_ptr 时要注意线程安全weakptr::lock() 返回的 sharedptr 可能为空避免在循环中频繁创建和销毁 shared_ptr考虑使用 std::observer_ptr(C++26)作为非拥有指针的替代方案
阅读 0·2月18日 17:32

C语言中枚举类型的定义和使用技巧有哪些?

C语言中枚举类型的定义和使用技巧有哪些?枚举类型基础:基本定义 enum Color { RED, GREEN, BLUE }; enum Color c = RED;指定值 enum Status { SUCCESS = 0, ERROR = -1, PENDING = 1, COMPLETED = 2 };匿名枚举 enum { MAX_SIZE = 100, BUFFER_SIZE = 1024 };高级用法:枚举作为位标志 enum FileFlags { READ = 0x01, // 0001 WRITE = 0x02, // 0010 EXECUTE = 0x04, // 0100 APPEND = 0x08 // 1000 }; unsigned int flags = READ | WRITE; if (flags & READ) { printf("Read permission\n"); }枚举与switch配合 enum Day { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }; void print_day(enum Day day) { switch (day) { case MONDAY: printf("Monday\n"); break; case TUESDAY: printf("Tuesday\n"); break; default: printf("Other day\n"); } }枚举类型转换 enum Color { RED, GREEN, BLUE }; // 枚举到整数 int value = RED; // value = 0 // 整数到枚举 enum Color c = (enum Color)1; // GREEN // 枚举大小 printf("Size of enum: %zu\n", sizeof(enum Color));最佳实践:命名约定 // 使用大写和下划线 enum ErrorCode { ERROR_NONE, ERROR_INVALID_PARAM, ERROR_OUT_OF_MEMORY, ERROR_FILE_NOT_FOUND }; // 或使用前缀 enum SocketType { SOCK_TYPE_STREAM, SOCK_TYPE_DGRAM };枚举作为数组索引 enum Month { JAN = 1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC }; const char* month_names[] = { "", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; printf("%s\n", month_names[JAN]);枚举与typedef结合 typedef enum { STATE_IDLE, STATE_RUNNING, STATE_PAUSED, STATE_STOPPED } State; State current_state = STATE_IDLE;注意事项:枚举值的连续性 enum Example { A = 1, B = 2, C = 5, // 不连续 D = 6 }; // 不能假设枚举值是连续的枚举的范围 enum Small { MIN = 0, MAX = 255 }; // 编译器可能选择更大的类型 // 不能保证只占用1字节枚举的前向声明 // C11 支持 enum Color; void process_color(enum Color c); enum Color { RED, GREEN, BLUE };实际应用示例:状态机实现 typedef enum { STATE_INIT, STATE_CONNECTING, STATE_CONNECTED, STATE_DISCONNECTING, STATE_ERROR } ConnectionState; ConnectionState handle_state(ConnectionState state) { switch (state) { case STATE_INIT: return STATE_CONNECTING; case STATE_CONNECTING: return STATE_CONNECTED; case STATE_CONNECTED: return STATE_DISCONNECTING; default: return STATE_ERROR; } }配置选项 enum ConfigOption { OPT_DEBUG = 0x01, OPT_VERBOSE = 0x02, OPT_LOG_FILE = 0x04, OPT_DAEMON = 0x08 }; void configure(unsigned int options) { if (options & OPT_DEBUG) { enable_debug(); } if (options & OPT_DAEMON) { run_as_daemon(); } }错误码定义 enum LibraryError { LIB_OK = 0, LIB_ERR_INVALID_ARG = -1, LIB_ERR_OUT_OF_MEMORY = -2, LIB_ERR_IO = -3, LIB_ERR_TIMEOUT = -4 }; enum LibraryError library_init() { if (!allocate_memory()) { return LIB_ERR_OUT_OF_MEMORY; } return LIB_OK; }
阅读 0·2月18日 17:22

C语言中结构体和类的区别及使用场景是什么?

C语言中结构体和类的区别及使用场景是什么?结构体基本概念:结构体定义 struct Point { int x; int y; }; struct Point p1 = {10, 20}; struct Point p2 = {.x = 30, .y = 40};结构体指针 struct Point *ptr = &p1; ptr->x = 50; ptr->y = 60;与类的对比:数据封装 // C语言结构体 struct Rectangle { int width; int height; }; // C++类 class Rectangle { private: int width; int height; public: Rectangle(int w, int h) : width(w), height(h) {} int area() { return width * height; } };方法定义 // C语言:使用函数指针 struct Shape { int (*area)(struct Shape*); int (*perimeter)(struct Shape*); }; int rectangle_area(struct Shape *s) { struct Rectangle *r = (struct Rectangle*)s; return r->width * r->height; } // C++:成员函数 class Shape { public: virtual int area() = 0; virtual int perimeter() = 0; };构造和析构 // C语言:手动初始化 struct Point create_point(int x, int y) { struct Point p = {x, y}; return p; } void destroy_point(struct Point *p) { // 手动清理资源 } // C++:自动构造和析构 class Point { public: Point(int x, int y) : x(x), y(y) {} ~Point() {} private: int x, y; };使用场景:数据结构 struct Node { int data; struct Node *next; }; struct LinkedList { struct Node *head; int size; };配置管理 struct Config { char server[256]; int port; int timeout; int max_connections; }; struct Config load_config(const char *filename);网络协议 struct PacketHeader { unsigned int version : 4; unsigned int type : 4; unsigned int length : 16; unsigned int checksum : 8; };高级特性:结构体嵌套 struct Address { char street[100]; char city[50]; char country[50]; }; struct Person { char name[50]; int age; struct Address address; }; struct Person person = { .name = "John Doe", .age = 30, .address = { .street = "123 Main St", .city = "New York", .country = "USA" } };结构体数组 struct Student { int id; char name[50]; float score; }; struct Student students[100]; students[0].id = 1; strcpy(students[0].name, "Alice"); students[0].score = 95.5;灵活数组成员 struct String { size_t length; char data[]; // 灵活数组成员 }; struct String *create_string(const char *str) { size_t len = strlen(str); struct String *s = malloc(sizeof(struct String) + len + 1); s->length = len; strcpy(s->data, str); return s; }最佳实践:命名约定 struct Point { int x; int y; }; typedef struct Point Point; Point p1 = {10, 20};初始化函数 struct Point point_create(int x, int y) { struct Point p = {x, y}; return p; } struct Point p = point_create(10, 20);内存管理 struct Point *point_alloc(int x, int y) { struct Point *p = malloc(sizeof(struct Point)); if (p) { p->x = x; p->y = y; } return p; } void point_free(struct Point *p) { free(p); }注意事项:内存对齐 struct Example { char c; // 1字节 + 3字节填充 int i; // 4字节 }; // 总大小: 8字节结构体赋值 struct Point p1 = {10, 20}; struct Point p2 = p1; // 浅拷贝结构体比较 struct Point p1 = {10, 20}; struct Point p2 = {10, 20}; // 错误:不能直接比较结构体 // if (p1 == p2) { } // 正确:逐个成员比较 if (p1.x == p2.x && p1.y == p2.y) { printf("Equal\n"); }
阅读 0·2月18日 17:22

C语言中动态内存管理的完整指南和常见问题是什么?

C语言中动态内存管理的完整指南和常见问题是什么?动态内存分配函数:malloc - 分配内存 void *malloc(size_t size); // 分配指定字节数的内存 int *arr = (int*)malloc(10 * sizeof(int)); if (arr == NULL) { fprintf(stderr, "Memory allocation failed\n"); exit(1); } // 使用内存 for (int i = 0; i < 10; i++) { arr[i] = i * i; } // 释放内存 free(arr);calloc - 分配并初始化 void *calloc(size_t num, size_t size); // 分配并初始化为零 int *arr = (int*)calloc(10, sizeof(int)); // 所有元素自动初始化为0 free(arr);realloc - 重新分配 void *realloc(void *ptr, size_t size); int *arr = (int*)malloc(5 * sizeof(int)); // 扩展内存 int *new_arr = (int*)realloc(arr, 10 * sizeof(int)); if (new_arr == NULL) { free(arr); // 原内存仍然有效 exit(1); } arr = new_arr; free(arr);free - 释放内存 void free(void *ptr); int *ptr = (int*)malloc(sizeof(int)); free(ptr); ptr = NULL; // 避免悬空指针内存管理最佳实践:检查分配结果 void *ptr = malloc(size); if (ptr == NULL) { // 处理内存分配失败 return NULL; }避免内存泄漏 void function_with_leak() { int *ptr = malloc(sizeof(int)); // 忘记 free(ptr) - 内存泄漏 } void correct_function() { int *ptr = malloc(sizeof(int)); if (ptr) { // 使用内存 free(ptr); } }防止悬空指针 int *ptr = malloc(sizeof(int)); free(ptr); ptr = NULL; // 避免使用已释放的内存 // 错误示例 *ptr = 10; // 未定义行为双重释放防护 int *ptr = malloc(sizeof(int)); free(ptr); ptr = NULL; // 设置为NULL free(ptr); // free(NULL) 是安全的常见问题和解决方案:内存碎片 // 问题:频繁分配和释放不同大小的内存 for (int i = 0; i < 1000; i++) { void *ptr = malloc(rand() % 1000); free(ptr); } // 解决:使用内存池或固定大小分配缓冲区溢出 // 危险 int *arr = malloc(10 * sizeof(int)); arr[10] = 100; // 越界访问 // 安全 int *arr = malloc(10 * sizeof(int)); if (index < 10) { arr[index] = value; }野指针 int *ptr; // 未初始化 *ptr = 10; // 未定义行为 // 正确做法 int *ptr = NULL; ptr = malloc(sizeof(int)); if (ptr) { *ptr = 10; free(ptr); ptr = NULL; }高级技巧:自定义内存分配器 void* my_malloc(size_t size) { void *ptr = malloc(size); if (ptr) { memset(ptr, 0, size); // 清零 } return ptr; }内存调试 #ifdef DEBUG void *debug_malloc(size_t size, const char *file, int line) { void *ptr = malloc(size); printf("Allocated %zu bytes at %p (%s:%d)\n", size, ptr, file, line); return ptr; } #define MALLOC(size) debug_malloc(size, __FILE__, __LINE__) #else #define MALLOC(size) malloc(size) #endif
阅读 0·2月18日 17:21

C语言中typedef和#define的区别及使用场景是什么?

C语言中typedef和#define的区别及使用场景是什么?核心区别:处理阶段#define: 预处理器阶段,文本替换typedef: 编译器阶段,类型别名作用域#define: 全局作用域,从定义点到文件末尾typedef: 遵循正常作用域规则类型检查#define: 无类型检查,纯文本替换typedef: 有类型检查,编译器验证调试支持#define: 调试时显示原始代码typedef: 调试时显示别名类型使用场景对比:类型别名 // typedef - 推荐 typedef unsigned int uint32_t; uint32_t value = 100; // #define - 不推荐 #define uint32_t unsigned int uint32_t value = 100;函数指针 // typedef - 清晰易读 typedef int (*CompareFunc)(const void*, const void*); CompareFunc compare = my_compare; // #define - 难以理解 #define CompareFunc int (*)(const void*, const void*) CompareFunc compare = my_compare;结构体 // typedef - 简洁 typedef struct { int x; int y; } Point; Point p1 = {10, 20}; // #define - 不适用数组类型 // typedef - 类型安全 typedef int Array10[10]; Array10 arr1, arr2; // #define - 可能导致意外行为 #define Array10 int[10] Array10 arr1, arr2; // 只有arr2是数组#define 的优势场景:常量定义 #define MAX_SIZE 100 #define PI 3.14159 #define VERSION "1.0.0"条件编译 #ifdef DEBUG #define LOG(x) printf x #else #define LOG(x) #endif宏函数 #define SQUARE(x) ((x) * (x)) #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))typedef 的优势场景:提高代码可读性 typedef unsigned long long ull; typedef struct Node* NodePtr;跨平台兼容性 #ifdef _WIN64 typedef __int64 intptr_t; #else typedef long intptr_t; #endif回调函数类型 typedef void (*Callback)(int result); void register_callback(Callback cb);常见陷阱:宏的副作用 #define SQUARE(x) ((x) * (x)) int i = 2; int result = SQUARE(i++); // 未定义行为宏的括号问题 #define MUL(a, b) a * b int result = MUL(2 + 3, 4); // 结果是14,不是20typedef 不能用于数组初始化 typedef int IntArray[10]; IntArray arr = {1, 2, 3}; // 错误 int arr[10] = {1, 2, 3}; // 正确
阅读 0·2月18日 17:21