赞
踩
将一块内存空间映射到不同的进程空间中
1.define 是预处理指令,用于创建符号常量。const
是 C 和 C++ 的关键字,用于创建具有常量值的变量,本质是只读变量。
2.define
在预处理阶段执行。const
在编译阶段执行。
3.define
没有类型检查,仅进行文本替换。const
有类型检查,可以与变量类型关联。
1.数组内存连续,链表内存不连续。
2.数组访问速度比链表快
3.链表增加删除操作比数组快
1.指针:指针是一个变量,保存着内存地址。引用:引用是已存在变量的别名,没有自己的内存地址。
2.指针可以具有空值(NULL),引用不能为空,必须在初始化时指向一个有效的对象。
3.可以修改指针的指向,可以将指针重新赋值为另一个地址。一旦引用被初始化,它始终指向同一个对象,不可更改。
4.指针需要额外的内存空间来存储地址值。引用不需要额外的内存空间,因为它是对已存在变量的别名。
信号与槽是一种用于实现对象之间通信和事件处理的机制。
1.当IIC总线在空闲状态,SDA和SCL需要处于高电平状态。
2.开漏输出无法输出高电平,使用上拉电阻可以完成高低电平之间的转换。
1.假如使用推挽输出可能导致器件的烧毁
2.实现线与功能
1.创建客户端
2.指定IP地址和端口号
3.进行连接
4.发布主题或者订阅主题
5.数据传输
6.断开连接
1.互斥锁
2.信号量
3.条件变量
1.TCP:文件传输、电子邮件、网页浏览。
2.UDP:实时音视频传输、在线游戏、实时监控。
1.指向已被释放或无效的内存地址的指针是野指针。
1.内存释放后未置空指针
int *ptr = (int*)malloc(sizeof(int)); free(ptr); *ptr = 10; // 这里ptr成为了野指针
2.返回局部变量的指针
int* getIntPointer() {
int num = 5;
return # // 返回局部变量的指针
}
int *ptr = getIntPointer();
*ptr = 10; // getIntPointer返回一个野指针
3.未初始化指针
char* p;
互斥锁是一种用于线程同步的机制,用于确保同一时间只有一个线程访问共享资源。
数组是一块连续的内存空间,其大小在编译时确定,访问元素使用下标操作;而指针是一个变量,存储地址值,大小固定,可以指向不同类型的数据,通过解引用操作访问内存中的数据。
1.使用预处理指令
#ifndef HEADER_FILE_NAME_H
#define HEADER_FILE_NAME_H
// 头文件内容
#endif // HEADER_FILE_NAME_H
2.使用#pragma once
1.栈是后进先出的数据结构,而队列是先进先出的数据结构。
2.栈常用于表达式求值、函数调用的调用栈、括号匹配等需要后进先出的场景。队列常用于任务调度、缓冲区管理、消息传递等需要先进先出的场景。
中断是异步调用,无法知道什么时候会被调用,不能够像函数一样主动调用。
起始位,数据位,校验位,停止位。
中断是计算机系统中一种重要的处理机制,用于响应某种事件或条件的发生。它是一种异步的事件,可以打断当前正在执行的程序或任务,以处理紧急情况或外部设备的请求。
控制变量生命周期,控制作用域,控制文件可见性。
中断的执行过程包括中断请求、中断控制器响应、中断响应、中断向量确定、中断处理程序执行和中断处理程序结束。
多态是面向对象编程中的一种特性,它允许以一种统一的方式处理不同类型的对象,通过相同的接口可以表现出不同的行为。
1.静态内存分配。
3.堆上内存分配。
1.默认访问权限不同,struct的默认访问权限是public,class的默认访问权限是private。
2.继承方式不同,struct的默认继承方式是公有继承,class的继承访问是私有继承。
3.在一般情况下,struct被用于表示数据结构,而class则更多用于表示具有行为和数据的对象。
1.函数调用不会发生上下文切换,中断调用会发生上下文切换。
2.函数可以主动被调用,中断无法主动被调用。
3.函数调用是同步的,中断是异步的。
4.函数可以有返回值和参数,中断没有返回值和参数。
自旋锁是一种忙等待的方式,适用于临界区执行时间短暂、锁冲突概率低的情况;而信号量是一种阻塞机制,适用于临界区执行时间长、锁冲突概率高的情况,自旋锁不会进入休眠,信号量会进入休眠。
使用快慢指针。
思路:
char* mystrcpy(char* str, const char* str1)
{
char* temp = str;
while (*temp++ = *str1++);
return str;
}
char* mystrcat(char* str1, char* str2) { char* temp = str1; while (*temp != '\0') { temp++; } while (*str2 != '\0') { *temp = *str2; temp++; str2++; } *temp = '\0'; return str1; }
int mystrlen(char* str)
{
int i = 0;
while (*str++ != '\0')
{
i++;
}
return i;
}
1.new是C++中的关键字,malloc是标准库中的函数。
2.使用new创建对象会调用构造函数,使用malloc创建对象不会调用构造函数。
3.使用new不需要指定对象的大小,使用malloc需要指定对象的大小。
4.new返回的是一个对象的指针,malloc返回的是void*
预处理–编译–汇编–链接
1.UART概念:UART是一种异步串行通信协议,用于在两个设备之间实现简单的点对点通信。它使用两根传输线(TX和RX)进行数据传输,其中TX(发送线)负责发送数据,RX(接收线)负责接收数据。
2.SPI概念:SPI是一种同步串行通信协议,用于在一个主设备(主控器)和一个或多个从设备之间实现全双工的高速数据传输。
3.IIC概念:I2C是一种串行双线制通信协议,用于在多个设备之间进行数据传输。它使用两根传输线(SDA和SCL)进行数据传输,其中SDA(串行数据线)负责发送和接收数据,SCL(串行时钟线)用于数据同步。
区别:
UART是异步通信协议,用于点对点通信;SPI是同步通信协议,适用于高速数据传输;I2C是双线制通信协议,适用于连接多个低速外设的场景。
1.软件中断是由特殊指定触发,硬件中断是由外部设备或处理器内部产生的信号触发的。
2.软件中断可以是同步也可以是异步的,硬件中断是异步的。
3.软件中断响应时间较长,硬件中断响应时间非常短。
1.内联函数在编译时展开,而宏函数在预处理时展开。
2.内联函数会进行错误检查,宏函数是直接替换不会进行错误检查。
3.内联函数可以进行调试,宏函数无法进行调试。
4.内联函数有作用域规则,只能在定义它的源文件内使用,不能被其他源文件调用。而宏函数没有作用域限制,可以在整个程序中使用。
冒泡排序(Bubble Sort)是一种简单且直观的排序算法,属于比较排序算法的一种。它通过多次迭代比较和交换相邻的元素,将较大(或较小)的元素逐渐“浮”到数组的一端,从而实现排序。
void bubbleSort(int* array, int size) { for (int i = 0; i < size - 1; i++) { for (int j = 0; j < size - i - 1; j++) { // 比较相邻的两个元素,如果顺序错误就交换它们 if (array[j] > array[j + 1]) { int temp = array[j]; array[j] = array[j + 1]; array[j + 1] = temp; } } } }
选择排序(Selection Sort)是一种简单且直观的排序算法,属于比较排序算法的一种。它的基本思想是从未排序部分的数组中选择最小(或最大)的元素,然后将其放置在已排序部分的末尾,不断重复这个过程,直到整个数组排序完成。
void selectionSort(int* array, int size) { for (int i = 0; i < size - 1; i++) { int minIndex = i; for (int j = i + 1; j < size; j++) { // 寻找未排序部分的最小元素的索引 if (array[j] < array[minIndex]) { minIndex = j; } } // 将最小元素与当前位置交换 int temp = array[i]; array[i] = array[minIndex]; array[minIndex] = temp; } }
插入排序(Insertion Sort)是一种简单且直观的排序算法,属于比较排序算法的一种。它的基本思想是将数组分为已排序部分和未排序部分,初始时已排序部分包含第一个元素,然后逐步将未排序部分的元素插入到已排序部分的合适位置,直到整个数组排序完成。
void insertionSort(int array[], int size) { for (int i = 1; i < size; i++) { int key = array[i]; int j = i - 1; // 在已排序部分中找到合适的位置插入元素 while (j >= 0 && array[j] > key) { array[j + 1] = array[j]; j--; } array[j + 1] = key; } }
// 交换两个元素的值 void swap(int* a, int* b) { int temp = *a; *a = *b; *b = temp; } // 将数组划分为两个子区间,并返回枢轴的索引 int partition(int arr[], int low, int high) { int pivot = arr[high]; // 选择最后一个元素作为枢轴 int i = (low - 1); // 记录小于枢轴的元素的索引 for (int j = low; j <= high - 1; j++) { // 如果当前元素小于或等于枢轴,则交换位置 if (arr[j] <= pivot) { i++; swap(&arr[i], &arr[j]); } } // 把枢轴放到正确的位置上,并返回索引 swap(&arr[i + 1], &arr[high]); return (i + 1); } // 快速排序 void quickSort(int arr[], int low, int high) { if (low < high) { // 划分数组,获取枢轴索引 int pivotIndex = partition(arr, low, high); // 递归对枢轴左侧的子数组进行排序 quickSort(arr, low, pivotIndex - 1); // 递归对枢轴右侧的子数组进行排序 quickSort(arr, pivotIndex + 1, high); } }
1.C++中的struct可以支持继承,C语言中的struct不支持继承。
2.C++中的struct可以包含成员函数,C语言中的struct不可以包含成员函数。
1.线程是程序调度的基本单位,进程是资源分配的基本单位。
2.一个进程崩溃不会导致其他进程崩溃,一个线程崩溃可能会导致整个程序崩溃。
3.创建和销毁进程所消耗的资源比较多,创建和销毁线程所消耗的资源比较少。
4.每个进程都有独立的内存空间和系统资源,线程是在进程内部创建的,共享相同的内存空间和系统资源。
volatile的本质是仿真编译器对所修饰的变量进行优化。
作用:
1.访问硬件寄存器:当需要直接访问硬件寄存器或外设寄存器时,使用 volatile
可以确保编译器每次访问该寄存器时都从内存中读取或写入,而不是从寄存器的缓存中获取值。
2.处理并发访问和中断:在多线程或多进程环境中,多个线程或进程可能同时访问共享的变量。
大小端(Endian)指的是在计算机存储和处理多字节数据时,字节的存储顺序。
0x12345678
在内存中按照大端序排列为 12 34 56 78
。0x12345678
在内存中按照小端序排列为 78 56 34 12
。在C语言中,可以使用联合(union)的特性来判断系统的大小端(Big Endian 或 Little Endian)。
#include <stdio.h> union EndianCheck { int i; char c[sizeof(int)]; }; int main() { union EndianCheck ec; ec.i = 1; if (ec.c[0] == 1) { printf("Little Endian\n"); } else { printf("Big Endian\n"); } return 0; }
1.define
用于创建宏定义,在预处理时进行简单的文本替换。
2.typedef
用于创建类型别名,在编译时进行类型检查,并为已有类型创建新的名称。
3.define
是预处理指令,typedef
是关键字。
4.define
不会进行类型检查,而 typedef
会。
5.typedef
在定义新类型时更为灵活和安全。
1.使用fork创建的子进程和父进程有独立的地址空间。
2.vfork 创建的子进程与父进程共享地址空间,包括代码段、数据段和堆栈等。
3.使用fork时父子进程的执行顺序是不确定的,取决于系统调度。
4.vfork会暂停父进程的执行,直到子进程调用exec或_exit,在此期间,父进程一直等待子进程的结束。
1.作用域:
全局变量:全局变量在整个程序中都是可见和可访问的,被定义在全局作用域中。
局部变量:局部变量只在其被定义的特定函数、代码块或作用域内部可见和可访问。
2.生命周期
全局变量:全局变量的生命周期从程序开始运行到程序结束,它在内存中一直存在。
局部变量:局部变量的生命周期仅在其定义的特定作用域内部存在。
3.初始值
全局变量:全局变量可以在定义时显示地指定初始值,如果没有指定初始值,全局变量会被默认初始化为零值。
局部变量:局部变量在定义时不会被自动初始化,其初始值是未定义的(即不确定的),需要显式地给定一个初始值。
4.存储位置
全局变量:全局变量通常被存储在数据段(data segment)中,具有固定的存储位置,且在整个程序的执行期间都保持不变。
局部变量:局部变量通常被存储在栈(stack)中,它们的存储位置在函数调用过程中动态分配和释放,每次函数执行时都会创建一个新的副本。
交叉编译(Cross-compilation)是指在一台计算机上使用特定的编译工具链将代码编译成目标平台上可执行的程序或库。
1.可变性
1.用法和语法
define:#define是一个预处理指令,用于在代码中创建常量或宏定义。
typedef:typedef关键字用于为已存在的数据类型创建新的名称,可以通过typedef为存在的类型创建别名。
2.处理阶段
define:#define指令是在预处理阶段进行处理,即在编译之前进行文本替换。它将标识符替换为指定的文本,不进行任何类型检查。
typedef:typedef是在编译阶段进行处理,在编译器解析代码时处理类型信息。它为已存在的类型创建一个新的别名。会进行类型检查
3.作用范围
define:#define指令的作用范围是整个文件或者被它所定义的预处理区域,可以在文件的任何位置进行定义和使用。
typedef:typedef创建的别名具有更窄的作用域,仅在指定的代码块、函数、结构体或枚举内部有效。
构造函数不能被声明为虚函数。
析构函数可以被声明为虚函数。
1.创建方式不同
有名管道使用mkfifo函数创建,无名管道使用pipe函数创建。
2.生存周期
有名管道可以持久存在于文件系统中,无名管道的生命周期仅限于创建它的父子进程的生命周期。
3.通信限制
无名管道只能用于亲缘关系间的进程进行通信,有名管道可以进行非亲缘关系之间的进程进行通信。
1.创建状态(New):当一个进程刚刚被创建时,它处于新建状态。此时,操作系统为进程分配必要的资源,并对其进行初始化。
2.就绪状态(Ready):当一个进程已经被创建并具备运行所需的所有资源时,但尚未被调度执行,它处于就绪状态。在就绪状态下,进程等待操作系统的调度,以便在合适的时机执行。
3.运行状态(Running):当操作系统将 CPU 资源分配给处于就绪状态的进程时,进程进入运行状态。在运行状态下,进程正在执行其指令和操作。
4.阻塞状态(Blocked):当一个进程无法继续执行,因为它正在等待某种事件的发生,比如等待输入/输出、等待资源释放等,此时进程进入阻塞状态。在阻塞状态下,进程会释放 CPU 资源,让其他可运行的进程有机会执行。
5.终止状态(Terminated):当一个进程完成了其任务或由于某种原因被操作系统终止时,它进入终止状态。在终止状态下,进程释放它所占用的资源,并等待系统回收。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。