【C/C++】语言基础知识总复习

文章目录

  • [1. 指针](#1. 指针)
  • [2. 库函数及其模拟实现](#2. 库函数及其模拟实现)
  • [3. 自定义类型](#3. 自定义类型)
  • [4. 数据存储](#4. 数据存储)
  • [5. 编译链接过程](#5. 编译链接过程)
  • [6. C++入门基础](#6. C++入门基础)
    • [6.1 函数重载](#6.1 函数重载)
    • [6.2 引用和指针](#6.2 引用和指针)
    • [6.3 建议使用const、inline、enum去替代宏](#6.3 建议使用const、inline、enum去替代宏)
    • [6.4 nullptr的意义是什么?](#6.4 nullptr的意义是什么?)
  • [7. 类和对象](#7. 类和对象)
    • [7.1 面向对象和面向过程的区别?](#7.1 面向对象和面向过程的区别?)
    • [7.2 类大小的计算](#7.2 类大小的计算)
    • [7.3 class和struct区别](#7.3 class和struct区别)
    • [7.4 C++11智能指针](#7.4 C++11智能指针)
    • [7.5 this指针](#7.5 this指针)
    • [7.6 八个默认成员函数](#7.6 八个默认成员函数)
    • [7.7 运算符重载](#7.7 运算符重载)
    • [7.8 友元](#7.8 友元)
    • [7.9 static 成员](#7.9 static 成员)
  • [8. 内存管理](#8. 内存管理)

1. 指针

1.1 数组和指针

数组指针是指针,指向数组的第一个元素;

c 复制代码
#include <stdio.h>

int main() {
    int arr[3] = {1, 2, 3};
    int (*ptr)[3] = &arr;  // ptr 是一个指向包含3个整数的数组的指针

    // 通过指针访问数组元素
    for (int i = 0; i < 3; i++) {
        printf("%d ", (*ptr)[i]);
    }
    printf("\n");

    return 0;
}

指针数组是数组,数组的每个对象都是一个指针;

cpp 复制代码
#include <stdio.h>

int main() {
    int a = 10, b = 20, c = 30;
    int *ptr_arr[3];  // ptr_arr 是一个包含3个整数指针的数组

    ptr_arr[0] = &a;
    ptr_arr[1] = &b;
    ptr_arr[2] = &c;

    // 通过指针数组访问整数变量
    for (int i = 0; i < 3; i++) {
        printf("%d ", *ptr_arr[i]);
    }
    printf("\n");

    return 0;
}

1.2 函数指针

函数指针是一个指针,它指向一个函数的地址。函数指针允许我们通过指针允许我们通过指针来调用函数,这在实现回调函数调用时非常有用,虚函数表也就时一个函数指针数组。

cpp 复制代码
#include <stdio.h>

// 定义一个函数类型
typedef int (*FuncPtr)(int, int);

// 定义一个函数
int add(int a, int b) {
    return a + b;
}

// 另一个函数
int subtract(int a, int b) {
    return a - b;
}

// 使用函数指针的函数
void useFunctionPointer(FuncPtr fp, int x, int y) {
    int result = fp(x, y);
    printf("Result: %d\n", result);
}

int main() {
    FuncPtr fp;

    // 指向 add 函数
    fp = add;
    useFunctionPointer(fp, 5, 3);  // 输出: Result: 8

    // 指向 subtract 函数
    fp = subtract;
    useFunctionPointer(fp, 5, 3);  // 输出: Result: 2

    return 0;
}

指针函数是一个返回指针的函数,函数的返回类型是指针。

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>

// 函数返回一个指向整数的指针
int* createArray(int size) {
    int* array = (int*)malloc(size * sizeof(int)); // 动态分配内存
    if (array == NULL) {
        printf("Memory allocation failed\n");
        exit(1);
    }
    // 初始化数组
    for (int i = 0; i < size; i++) {
        array[i] = i + 1;
    }
    return array;
}

int main() {
    int size = 5;
    int* arr = createArray(size);

    // 打印数组内容
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    // 释放分配的内存
    free(arr);

    return 0;
}

1.3 const 和 指针、static、#define、typedef

  • const:定义变量不能修改,必须在定义时初始化;在 * 前是常量指针(不能通过该指针修改),在*后是指针常量(不能再指向其它地址)修饰函数的参数(函数体内不能修改这个值)
  • #define: C语言中定义语法,是预处理指令(简单的替换)、没有作用域
  • typedef:有类型检查功能,在定义很长类型的时候方便的多、有作用域
  • #defineconst都能定义常量,define可替换常量、表达式(代码段中:不分配内存空间);const常量在(数据段中)分配空间
cpp 复制代码
#include <stdio.h>
// 加法宏函数
#define ADD(x, y) ((x) + (y))
// 减法宏函数
#define SUBTRACT(x, y) ((x) - (y))
int main() {
    int a = 5;
    int b = 3;
    printf("Addition: %d + %d = %d\n", a, b, ADD(a, b));        // 输出: 5 + 3 = 8
    printf("Subtraction: %d - %d = %d\n", a, b, SUBTRACT(a, b)); // 输出: 5 - 3 = 2
    return 0;
}

1.4 指针和引用的异同

  • 相同:都是地址概念;
  • 区别 :指针是实体、引用是别名;指针++是内存地址自增、引用时值自增;引用无需解引用(*)、指针需要解引用、引用只能在定义的时候被初始化、引用不能为空。

1.5 sizeof与strlen

https://qhd666.blog.csdn.net/article/details/132915168

  • sizeof 用于计算数据类型或变量的大小(以字节为单位),它可以用于基本数据类型、数组、结构体、联合体以及其他类型。
  • strlen 计算以null终止字符的长度(不包括null终止符),它在 string.h 头文件中定义。
  • 数组所占空间 :sizeof(数组名); 数组大小:sizeof(数组名)/sizeof(数据类型);

2. 库函数及其模拟实现

https://qhd666.blog.csdn.net/article/details/133102559
memcpy 用于不重叠的内存区域快速复制数据,而 memmove 用于处理可能重叠的内存区域,确保数据正确移动。

字符串拷贝:strcpystrncpy

字符创连结:strcatstrncat

字符串比较:memcmpstrcmpstrncmp

字符串查找:strstr

计算长度:strlen

...

3. 自定义类型

内存对齐:自定义类型的内存对齐是确保数据在内存中按照特定字节边界排列,以提高访问效率和满足硬件要求。
https://qhd666.blog.csdn.net/article/details/134456752?spm=1001.2014.3001.5502

https://qhd666.blog.csdn.net/article/details/132009604?spm=1001.2014.3001.5502

  • 内存对齐的规则:
  1. 第一个成员在与结构体变量偏移量为0的位置
  2. 其他成员变量要对齐到对齐数的整数倍位置
  3. 对齐数 = min( 编译器默认的对齐数 , 该成员变量大小 ) , VS下默认对齐数为8
  4. 结构体总大小为每一个成员变量的最大对齐数的整数倍
  5. 修改默认对齐数的方法: #pragma pack(8) , 设置默认对齐数为8
  • 为什么要有内存对齐
  1. 为了平台的可移植:不是所有的硬件都能访问任意地址上的任意数据, 可能只能在4的倍数的地址处取数据。
  2. 为了性能:若内存不对齐, 原本只需要访问一次的数据现在可能要访问两次才能拿全
  • 整型的存储:
  • 原码:直接表示整数的符号和大小,最高位为符号位。
  • 反码:正数与原码相同,负数的表示是将原码的每一位取反。
  • 补码:正数与原码相同,负数的表示是将反码加1,主要用于简化计算和处理负数。

4. 数据存储

https://qhd666.blog.csdn.net/article/details/132009604

静态存储区(全局变量、静态变量)、栈区(局部变量、函数内参数)。

大端 :高地址存低字节、低地址存高字节
小端:高地址存高字节、低地址存低字节

5. 编译链接过程

编译 :将源代码翻译成目标代码(机器语言),生成一个或多个目标文件。
汇编 :将汇编代码转换成目标代码(如果需要)。
链接:将多个目标文件和库文件合并,解决符号引用,生成最终的可执行文件。

6. C++入门基础

6.1 函数重载

https://qhd666.blog.csdn.net/article/details/140560876

函数重载是指在同一作用域内,多个函数名相同但参数列表不同的特性。

6.2 引用和指针

https://qhd666.blog.csdn.net/article/details/140904531?spm=1001.2014.3001.5502

  • 指针和引用的异同:

相同 :都是地址概念;
区别:指针是实体、引用是别名、指针++是内存地址自增、引用时值自增、引用无需解引用(*)、指针需要解引用、引用只能在定义的时候被初始化一次、引用不能为空。

  • 引用价值:做参数和做返回值

引用可以作为参数传递给函数以避免复制开销,也可以作为返回值以允许函数返回对对象的直接引用。

例如:

cpp 复制代码
int& getElement(std::vector<int>& vec, size_t index) {
    return vec[index]; // 返回对 vec 中元素的引用
}
  • 引用也不是绝对安全的:

悬挂引用:如果引用的对象在引用被使用之前已经被销毁或超出作用域(例如局部变量),那么引用将变成悬挂引用,导致未定义行为。

cpp 复制代码
int* unsafeFunc() {
    int local = 42;
    return &local; // local 在函数返回后被销毁
}
// 访问 unsafeFunc() 返回的指针将是未定义行为

6.3 建议使用const、inline、enum去替代宏

  • 宏的缺点:
  1. 调试困难:宏展开后,调试时无法直接查看宏的原始代码。
  2. 类型安全差:宏不进行类型检查,容易导致类型错误。
  3. 作用域问题:宏没有作用域限制,可能影响其他代码。
  4. 代码重复:宏可能导致重复代码,增加维护难度。
  5. 可能导致错误:宏展开中的括号问题可能引发难以发现的错误。
  • inline要求:频繁调用短小函数合适(给编译器提建议)

6.4 nullptr的意义是什么?

在C++中 #define NULL 0

NULL定义存在缺陷

nullptr 是 C++11 引入的类型安全关键字,用于表示空指针,而 NULL 是一个宏定义,通常与 0等价,可能在类型安全和可移植性方面不如 nullptr

7. 类和对象

7.1 面向对象和面向过程的区别?

面向对象侧重于对象的抽象和封装,而面向过程则着重于步骤和函数的顺序执行。

7.2 类大小的计算

  • 内存对齐

  • 空类

7.3 class和struct区别

7.4 C++11智能指针

https://qhd666.blog.csdn.net/article/details/139183793
unique_ptr 禁止拷贝、shared_ptr使用引用计数:解决多次释放问题、每一个资源配一个引用计数

7.5 this指针

是每个对象的专属指针,访问自己的数据成员和方法。

  • this 指针存在哪里?
    this 指针在类的成员函数中,指向当前对象的内存地址。它通常存储在栈上或寄存器中。
  • this 指针可以为空吗?
    this 指针不会为空,因为它总是指向当前对象。

7.6 八个默认成员函数

  • 构造和析构

  • 拷贝构造和赋值

  • 移动构造和移动赋值

  • 初始化列表

  • 特性是什么?
    以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式。
  • 哪些成员必须在初始化列表初始化?
    引用成员变量
    const成员变量
    自定义类型成员(且该类没有默认构造函数时)
  • 初始化顺序是按声明顺序
  1. 什么情况下要自己写?
    一般构造都要自己写:
    深拷贝的类,一般都要自己写析构、拷贝、构造、赋值。
    深拷贝的类,也需要实现移动构造和移动赋值
  2. 默认生成的这些函数行为是什么?
  1. 默认构造函数:初始化对象的成员。
  2. 复制构造函数:逐个复制对象的成员。
  3. 赋值运算符:将右侧对象的成员赋值给左侧对象。
  4. 析构函数:释放对象占用的资源。
  5. 移动构造函数:移动资源,清空右侧对象。
  6. 移动赋值运算符:移动资源并清空右侧对象。

这些行为适用于所有类,除非你自定义了这些函数。

  1. 什么是默认构造?(不传参的都可以是默认构造)

我们不写,编译器默认生成的是默认构造。

全缺省的是默认构造 。

没有参数的是默认构造。

7.7 运算符重载

  1. 哪些运算符不能重载?
  2. 和函数重载的区别?
  3. 他的意义是什么?

7.8 友元

  1. 友元函数
  2. 友元类

7.9 static 成员

static成员就是全局成员不占类的大小,仅仅只是收到类域限制而已

8. 内存管理

-------------------------------------------未完待续----------------------------------------------------

相关推荐
Ajiang28247353041 小时前
对于C++中stack和queue的认识以及priority_queue的模拟实现
开发语言·c++
幽兰的天空1 小时前
Python 中的模式匹配:深入了解 match 语句
开发语言·python
Theodore_10224 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
网易独家音乐人Mike Zhou4 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
‘’林花谢了春红‘’6 小时前
C++ list (链表)容器
c++·链表·list
----云烟----6 小时前
QT中QString类的各种使用
开发语言·qt
lsx2024066 小时前
SQL SELECT 语句:基础与进阶应用
开发语言
开心工作室_kaic6 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
向宇it6 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
武子康7 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud