4、linux c 进程

【三】进程

1. 进程与程序的区别

  • 程序:存放在磁盘上的指令和数据的有序集合(文件),是静态的。

  • 进程:执行一个程序所分配的资源的总称,是动态的。

2. 进程的组成部分

  • BSS段(bss):存放程序中未初始化的全局变量。

  • 数据段(data):存放已初始化的全局变量。

  • 代码段(text):存放程序执行代码。

  • 堆(heap):通过malloc等函数分配内存,动态扩张或缩减。

  • 栈(stack):存放局部变量、函数参数和函数返回值,先进后出。

  • 进程控制块(PCB):包含进程ID(PID)、进程优先级、文件描述符表等。

3. 进程类型

  • 交互进程:用户通过终端与系统交互的进程。

  • 批处理进程:在后台运行,不需要用户交互。

  • 守护进程:在后台运行的特殊进程,通常用于系统服务。

4. 进程状态

  • 运行态:进程正在运行。

  • 等待态:进程等待某些资源(如I/O)。

  • 停止态:进程被暂停。

  • 死亡态:进程已结束,但父进程尚未读取其状态信息。

5. 堆与栈

  • 堆(heap):用于存放进程运行中被动态分配的内存段,当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)

  • 栈(stack):又称堆栈,是用户存放程序临时创建的局部变量,(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进后出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。


一、查看进程信息

1. ps命令

用于查看系统进程的快照。

1.1 常用参数

  • -e:显示所有进程。

  • -l:长格式显示更详细信息。

  • -f:全格式显示,通常与其他选项联用。

1.2 输出字段说明

字段含义
F进程标志,说明进程的权限。常见标志:1(不可执行)、4(超级用户权限)等。
S进程状态。常见状态:-D(不可唤醒的睡眠状态)、-R(运行)、-S(睡眠)、-T(停止)、-Z(僵尸进程)等。
UID运行此进程的用户ID。
PID进程的ID。
PPID父进程的ID。
C进程的CPU使用率(百分比)。
PRI进程的优先级,数值越小优先级越高。
NI进程的nice值,数值越小优先级越高。
ADDR进程在内存中的位置。
SZ进程占用的内存大小。
WCHAN进程是否运行,"-"表示正在运行。
TTY进程由哪个终端产生。
TIME进程占用CPU的时间。
CMD产生此进程的命令名。

1.3 示例

ps -elf

2. top命令

用于查看进程的动态信息。

2.1 常用操作

  • shift + >:后翻页。

  • shift + <:前翻页。

  • top -p PID:查看指定进程。

3. /proc目录

用于查看进程的详细信息。

每个进程在/proc目录下都有一个以PID命名的子目录,包含进程的各种信息文件,如statusmaps等。


二、改变进程优先级

1. nice命令

按用户指定的优先级运行进程。

1.1 命令格式

nice [-n NI值] 命令
  • NI值范围:-20~19。

    • 数值越大,优先级越低。

    • 普通用户可调整范围为0~19,只能调高优先级。

    • 只有root用户可以设置负值。

2. renice命令

改变正在运行进程的优先级。

2.1 命令格式

renice [优先级] PID

三、进程管理

1. 查看后台进程

1.1 命令

jobs

2. 将挂起的进程在后台运行

2.1 命令

bg

3. 将后台进程放到前台运行

3.1 命令

fg

4. 将前台进程转为后台并停止

4.1 操作

Ctrl + Z

5. 后台运行程序

5.1 示例

./test &

四、创建子进程

1. fork()函数

创建新的进程。

1.1 函数原型

#include <unistd.h>
pid_t fork(void);

1.2 返回值

  • 成功

    • 父进程返回子进程的PID。

    • 子进程返回0。

  • 失败:返回-1。

1.3 特点

  • 子进程只执行fork()之后的代码。

  • 父子进程的执行顺序由操作系统决定。

  • 子进程继承父进程的内容,但父子进程有独立的地址空间。

1.4 注意事项

  • 若父进程先结束:

    • 子进程成为孤儿进程,被init进程收养。

    • 子进程可能成为后台进程。

  • 若子进程先结束:

    • 父进程如果没有及时回收,子进程变成僵尸进程。

1.5 示例

#include <stdio.h>
#include <unistd.h>
​
int main() {pid_t pid = fork();if (pid == -1) {perror("fork failed");return 1;} else if (pid == 0) {printf("I am the child process, PID: %d\n", getpid());} else {printf("I am the parent process, PID: %d, Child PID: %d\n", getpid(), pid);}return 0;
}

五、进程的退出

1. exit()函数

结束当前进程。

1.1 函数原型

#include <stdlib.h>
void exit(int status);

1.2 特点

  • 会刷新流缓冲区。

  • 通常用于正常退出。

2. _exit()函数

结束当前进程。

2.1 函数原型

#include <unistd.h>
void _exit(int status);

2.2 特点

  • 不刷新流缓冲区。

  • 通常用于异常退出。

3. returnexit的区别

  • main函数结束时会隐式调用exit

  • 普通函数的return是返回上一级。


六、进程的回收

1. wait() 函数

回收子进程。

1.1 函数原型

#include <unistd.h>
pid_t wait(int *status);

1.2 返回值

  • 成功时返回回收的子进程的 PID。

  • 失败时返回 -1。

1.3 特点

  • 若子进程未结束,父进程会阻塞。

  • status 用于保存子进程的返回值和结束方式。

  • statusNULL,表示直接释放子进程的 PCB。

2. waitpid() 函数

更灵活的子进程回收。

2.1 函数原型

#include <unistd.h>
pid_t waitpid(pid_t pid, int *status, int options);

2.2 参数说明

  • pid

    • >0:只等待指定 PID 的子进程。

    • = -1:等待任意子进程。

    • = 0:等待同一进程组中的子进程。

    • < -1:等待指定进程组中的子进程。

  • options

    • WNOHANG:非阻塞,若子进程未结束,立即返回 0。

    • WUNTRACED:返回终止子进程信息和因信号停止的子进程信息。

2.3 示例代码

示例 1:wait() 示例
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
​
int main() {pid_t pid = fork();if (pid == -1) {perror("fork failed");return 1;}
​if (pid == 0) {// 子进程printf("Child process, PID: %d\n", getpid());sleep(2); // 模拟子进程运行printf("Child process finished\n");return 0; // 子进程退出} else {// 父进程printf("Parent process, PID: %d, waiting for child...\n", getpid());int status;wait(&status); // 等待子进程结束printf("Child process exited with status: %d\n", status);return 0;}
}
示例 2:waitpid() 示例
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
​
int main() {pid_t pid = fork();if (pid == -1) {perror("fork failed");return 1;}
​if (pid == 0) {// 子进程printf("Child process, PID: %d\n", getpid());sleep(3); // 模拟子进程运行printf("Child process finished\n");return 0; // 子进程退出} else {// 父进程printf("Parent process, PID: %d, waiting for child...\n", getpid());int status;pid_t ret = waitpid(pid, &status, WNOHANG); // 非阻塞等待子进程if (ret == 0) {printf("Child process is still running\n");} else if (ret == -1) {perror("waitpid failed");} else {printf("Child process exited with status: %d\n", status);}return 0;}
}

七、exec 函数族

1. 背景

fork 创建进程后,子进程会继承父进程的代码和数据,父子进程执行相同的代码。然而,在实际开发中,我们通常希望子进程执行与父进程不同的程序。exec 函数族的作用就是用来替换当前进程的代码和数据,从而执行指定的程序。

2. 作用

exec 函数族用于替换当前进程的代码和数据,执行指定的程序。这些函数不会创建新的进程,而是直接替换当前进程的内容。

3. 函数原型

#include <unistd.h>
​
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int system(const char *command);

4. 参数说明

4.1 execl

int execl(const char *path, const char *arg, ...);
  • path:指定要执行的程序的路径。

  • arg:传递给程序的参数列表,必须以 NULL 结尾。

  • 特点:参数列表是可变参数,每个参数都是字符串。

4.2 execlp

int execlp(const char *file, const char *arg, ...);
  • file:指定要执行的程序的文件名。execlp 会在环境变量 PATH 中查找该文件。

  • arg:传递给程序的参数列表,必须以 NULL 结尾。

  • 特点:不需要指定文件的全路径,execlp 会自动在 PATH 中查找。

4.3 execv

int execv(const char *path, char *const argv[]);
  • path:指定要执行的程序的路径。

  • argv:传递给程序的参数数组,必须以 NULL 结尾。

  • 特点:参数以数组形式传递,适合参数较多的情况。

4.4 execvp

int execvp(const char *file, char *const argv[]);
  • file:指定要执行的程序的文件名。execvp 会在环境变量 PATH 中查找该文件。

  • argv:传递给程序的参数数组,必须以 NULL 结尾。

  • 特点:不需要指定文件的全路径,execvp 会自动在 PATH 中查找。

4.5 system

int system(const char *command);
  • command:要执行的命令字符串。

  • 特点system 是一个高级函数,会调用 /bin/sh 来执行命令。它会创建一个子进程来运行命令,并等待命令执行完成。

5. 返回值

  • 成功:执行指定的程序,不会返回到调用 exec 的代码。

  • 失败:返回 -1,并设置 errno

6. 特点

  1. 进程替换exec 函数会替换当前进程的代码和数据,但进程号(PID)保持不变。

  2. 参数传递

    • 第一个参数(如 argargv[0])通常是程序的名称,虽然它在程序中没有实际用途。

    • 参数列表或数组必须以 NULL 结尾。

  3. 路径查找

    • execlexecv 需要指定程序的完整路径。

    • execlpexecvp 会在环境变量 PATH 中查找程序。

  4. 环境变量exec 函数不会改变当前进程的环境变量。

7. 示例代码

示例 1:execl 示例

#include <stdio.h>
#include <unistd.h>
​
int main() {printf("Before exec\n");execl("/bin/ls", "ls", "-l", NULL); // 替换当前进程为 ls 程序printf("After exec\n"); // 不会执行到这里return 0;
}

示例 2:execlp 示例

#include <stdio.h>
#include <unistd.h>
​
int main() {printf("Before exec\n");execlp("ls", "ls", "-l", NULL); // 替换当前进程为 ls 程序printf("After exec\n"); // 不会执行到这里return 0;
}

示例 3:execv 示例

#include <stdio.h>
#include <unistd.h>
​
int main() {printf("Before exec\n");char *args[] = {"/bin/ls", "-l", NULL};execv("/bin/ls", args); // 替换当前进程为 ls 程序printf("After exec\n"); // 不会执行到这里return 0;
}

示例 4:execvp 示例

#include <stdio.h>
#include <unistd.h>
​
int main() {printf("Before exec\n");char *args[] = {"ls", "-l", NULL};execvp("ls", args); // 替换当前进程为 ls 程序printf("After exec\n"); // 不会执行到这里return 0;
}

示例 5:system 示例

#include <stdio.h>
#include <stdlib.h>
​
int main() {printf("Before system\n");system("ls -l"); // 使用 shell 执行命令printf("After system\n"); // 会执行到这里return 0;
}

exec 函数族的使用注意事项

1. 参数传递

  • 参数列表或数组必须以 NULL 结尾,否则会导致未定义行为。

  • 第一个参数(如 argargv[0])通常是程序的名称,虽然它在程序中没有实际用途,但建议正确填写。

2. 环境变量

  • exec 函数不会改变当前进程的环境变量。如果需要修改环境变量,可以使用 putenvsetenv 函数。

3. 文件描述符

  • 在调用 exec 函数之前,应确保关闭不需要的文件描述符,以避免资源泄漏。

  • 如果需要保留某些文件描述符(如日志文件),应确保它们在调用 exec 之前已正确打开。

4. 错误处理

  • 如果 exec 函数失败,会返回 -1,并设置 errno。可以通过 perrorstrerror 获取错误信息。

  • 常见错误包括:

    • 文件路径错误或文件不存在。

    • 文件没有执行权限。

    • 环境变量 PATH 中未找到程序。

  1. fork 结合使用

  • exec 函数通常与 fork 结合使用,创建子进程并执行不同的程序。

  • 示例代码:

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
​
int main() {pid_t pid = fork();if (pid == -1) {perror("fork failed");return 1;}
​if (pid == 0) {// 子进程printf("Child process, PID: %d\n", getpid());execlp("ls", "ls", "-l", NULL); // 子进程执行 ls 程序perror("execlp failed"); // 如果 execlp 失败,会执行到这里return 1;} else {// 父进程printf("Parent process, PID: %d\n", getpid());wait(NULL); // 等待子进程结束printf("Child process finished\n");}return 0;
}

6. 使用 system 的注意事项

  • system 函数会调用 /bin/sh 来执行命令,因此可能会引入安全风险(如注入攻击)。

  • 如果需要执行简单的命令,可以使用 system,但建议优先使用 exec 函数族。

  • 示例:避免注入攻击

#include <stdio.h>
#include <stdlib.h>
​
int main() {char *filename = "test.txt";char command[256];snprintf(command, sizeof(command), "ls -l %s", filename); // 安全地构造命令system(command);return 0;
}

八、守护进程(Daemon Process)

1. 概念

守护进程(Daemon Process)是一种生存期较长的进程,通常独立于控制终端,并周期性地执行某种任务或等待处理某些事件。

2. 特点

  • 始终在后台运行,独立于任何终端。

  • 周期性地执行任务或等待处理特定事件。

  • 是一种特殊的孤儿进程,脱离终端,避免被终端信息打断。

3. 创建守护进程

3.1 简便方法

使用 nohup 命令:

nohup xxxx &

3.2 使用 setsid 函数

#include <unistd.h>
​
pid_t setsid(void);
  • 成功时返回调用进程的会话 ID。

  • 失败时返回 -1,并设置 errno

  • 调用 setsid 的进程成为新的会话组长和组长进程。

3.3 使用 getsid 函数

#include <unistd.h>
​
pid_t getsid(pid_t pid);
  • 成功时返回调用进程的会话 ID。

  • 失败时返回 -1,并设置 errno

  • 参数 pid 为 0 时,查看当前进程的会话 ID。

3.4 其他辅助函数

  • getpid:获取进程 ID。

    pid_t getpid(void);
  • getpgid:获取进程组 ID。

    pid_t getpgid(pid_t pid);

4. 创建守护进程的步骤

  1. 创建子进程,父进程退出

    if (fork() > 0) {exit(0); // 父进程退出
    }
  2. 子进程变成孤儿进程,被 init 进程收养

    • 子进程在后台运行。

  3. 子进程创建新会话

    if (setsid() < 0) {exit(-1); // 创建会话失败
    }
    • 子进程成为新的会话组长。

    • 子进程脱离原先的终端。

  4. 更改当前工作目录

    chdir("/"); // 或 chdir("/tmp");
    • 防止守护进程的工作目录被卸载。

  5. 重设文件权限掩码

    umask(0); // 文件权限掩码设置为 0
  6. 关闭打开的文件描述符

    for (int i = 0; i < 3; i++) {close(i); // 关闭标准输入、输出和错误
    }

4.1 示例代码

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
​
int main() {// 创建子进程,父进程退出if (fork() > 0) {exit(0); // 父进程退出}
​// 创建新会话if (setsid() < 0) {perror("setsid failed");exit(-1);}// 更改当前工作目录
if (chdir("/") < 0) {perror("chdir failed");exit(-1);
}
​
// 重设文件权限掩码
umask(0);
​
// 关闭打开的文件描述符
for (int i = 0; i < 3; i++) {close(i); // 关闭标准输入、输出和错误
}
​
// 执行守护进程的任务
while (1) {printf("Daemon process running...\n");sleep(10); // 模拟周期性任务
}
​
return 0;
}

九、守护进程的注意事项

1. 避免守护进程占用终端

守护进程不应与终端关联,否则可能会因终端关闭而退出。使用 setsid() 可以确保进程脱离终端。

2. 防止工作目录被卸载

守护进程的工作目录应设置为根目录(/)或 /tmp,避免因工作目录被卸载而导致守护进程无法运行。

3. 关闭不必要的文件描述符

守护进程不应继承父进程的文件描述符。关闭标准输入、输出和错误(stdinstdoutstderr),并根据需要重新打开日志文件。

4. 日志记录

守护进程通常需要记录日志以便调试和监控。可以将日志写入 /var/log 或其他日志文件中,而不是直接输出到终端。

5. 示例:守护进程与日志记录

示例代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
​
int main() {// 创建子进程,父进程退出if (fork() > 0) {exit(0); // 父进程退出}
​// 创建新会话if (setsid() < 0) {perror("setsid failed");exit(-1);}
​// 更改当前工作目录if (chdir("/") < 0) {perror("chdir failed");exit(-1);}
​// 重设文件权限掩码umask(0);
​// 关闭标准输入、输出和错误for (int i = 0; i < 3; i++) {close(i);}
​// 打开日志文件int log_fd = open("/var/log/mydaemon.log", O_WRONLY | O_CREAT | O_APPEND, 0644);if (log_fd < 0) {perror("open log file failed");exit(-1);}
​// 重定向标准输出和错误到日志文件dup2(log_fd, STDOUT_FILENO);dup2(log_fd, STDERR_FILENO);
​// 执行守护进程的任务while (1) {printf("Daemon process running...\n");sleep(10); // 模拟周期性任务}
​return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/34886.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【软考-架构】7、系统配置与性能评价

✨资料&文章更新✨ GitHub地址&#xff1a;https://github.com/tyronczt/system_architect 文章目录 性能指标&#x1f4af;考试真题第一题第二题 性能评价方法&#x1f4af;考试真题第一题第二题 阿姆达尔解决方法考试真题 性能指标 对计算机评价的主要性能指标有&#x…

STC89C52单片机学习——第20节: [8-2]串口向电脑发送数据电脑通过串口控制LED

写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难&#xff0c;但我还是想去做&#xff01; 本文写于&#xff1a;2025.03.15 51单片机学习——第20节: [8-2]串口向电脑发送数据&电脑通过串口控制LED 前言…

java简单基础学习

目录 简单5位验证码快捷键的使用 评委打分5个评委 去掉一个最高分和一个最低分 取平均分 抢红包出现数组越界java​编辑 双色球系统--之蒟蒻学习 简单5位验证码快捷键的使用 题目意思做个验证码 //生成一个5位数的验证码 //前四位是字母,大小字母都可以 //最后一位要是数字…

前端学习记录:解决路由缓存问题

问题描述&#xff1a;响应路由参数的变化&#xff0c;使用带有参数的路由时需要注意的是&#xff0c;当用户从 /users/johnoy 导航到 /users/jolyne 时&#xff0c;相同的组件实例将会被重复使用。因为两个路由都渲染同个组件&#xff0c;比起销毁再创建&#xff0c;复用则显得…

Leetcode-1278.Palindrome Partitioning III [C++][Java]

目录 一、题目描述 二、解题思路 【C】 【Java】 Leetcode-1278.Palindrome Partitioning IIIhttps://leetcode.com/problems/palindrome-partitioning-iii/description/1278. 分割回文串 III - 力扣&#xff08;LeetCode&#xff09;1278. 分割回文串 III - 给你一个由小写…

deepseek GRPO算法保姆级讲解(数学原理+源码解析+案例实战)

文章目录 什么是GRPO群组形成(Group Formation):让大模型创建多种解决方案偏好学习(Preference Learning)&#xff1a;让大模型理解何为好的解答组内相对优势 优化(optimization): 让大模型从经验中学习(learning from experience)目标函数 GRPO算法的伪码表示GRPO算法的局限与…

【Linux我做主】基础命令完全指南上篇

Linux基础命令完全指南【上篇】 Linux基础命令完全指南github地址前言命令行操作的引入Linux文件系统树形结构的根文件系统绝对路径和相对路径适用场景Linux目录下的隐藏文件 基本指令目录和文件相关1. ls2. cd和pwdcdpwd 3. touch4. mkdir5. cp6. mv移动目录时覆盖写入的两种特…

自然语言秒转SQL—— 免费体验 OB Cloud Text2SQL 数据查询

在数据驱动决策的今天&#xff0c;企业急需从庞大业务数据中提炼信息&#xff0c;获取深度洞察。然而&#xff0c;面对海量数据&#xff0c;业务人员往往因缺乏SQL专业技能而难以快速查询和分析所需信息&#xff0c;频繁求助于BI部门不仅抬高了企业的沟通与时间成本&#xff0c…

鸿蒙next 多行文字加图片后缀实现方案

需求 实现类似iOS的YYLabel之类的在文字后面加上图片作为后缀的样式&#xff0c;多行时文字使用…省略超出部分&#xff0c;但必须保证图片的展现。 系统方案 在当前鸿蒙next系统提供的文字排版方法基本没有合适使用的接口&#xff0c;包括imagespan和RichEditor,根据AI的回…

C语言基础知识04---指针

目录 1、指针 1.1 指针概念 1.2 指针的大小 1.3 指针的定义 1.4 多级指针 1.5 指针的初始化 1.6 指针的使用 1.7 类型转换 1.8 大小端 1.9 地址偏移 1.10 指针常量&&常量指针 1.11 指针数组&&数组指针 1、指针 1.1 指针概念 指针保存地址&#xff…

spring boot 发送邮件验证码

一、前置需求 1、准备邮箱 2、登录授权码 qq邮箱在–>设置–>账号POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务 开启服务 二、发送邮件 1、简单邮件 包含邮件标题、邮件正文 2、引入mail启动器 <dependency><groupId>org.springframework.boot</groupI…

Spring Cloud Config - 动态配置管理与高可用治理

引言&#xff1a;为什么需要配置中心&#xff1f; 在微服务架构中&#xff0c;配置管理面临分散化、多环境、动态更新三大挑战。传统基于application.yml等配置文件的硬编码方式&#xff0c;导致以下问题&#xff1a; • 环境差异&#xff1a;开发、测试、生产环境配置混杂&a…

[网络][tcp协议]:tcp报头

tcp(传输控制协议)是一种面向字节流的传输层协议,相较于udp协议,tcp能保证传输数据的可靠性与准确性,tcp也是目前最常见的传输层协议 本文主要介绍tcp报头各个字段的含义与用途 注:保留6位和6位标记位是目前最普遍的写法,在我查资料时,发现有一些拓展情况,会在后文细说 最简单的…

【sklearn 01】人工智能概述

一、人工智能&#xff0c;机器学习&#xff0c;深度学习 人工智能指由人类制造出的具有智能的机器。这是一个非常大的范围&#xff0c;长远目标是让机器实现人工智能&#xff0c;但目前我们仍处在非常初始的阶段&#xff0c;甚至不能称为智能 机器学习是指通过数据训练出能完成…

Excel ScriptLab学习笔记

注意 The Excel JavaScript API 没有“Cell”对象或类。 相反&#xff0c;Excel JavaScript API 将所有 Excel 单元格定义为 Range 对象。 Excel UI 中的单个单元格转换为 Excel JavaScript API 中包含一个单元格的 Range 对象。 单个 Range 对象也可以包含多个连续的单元格。…

【数据结构】线性表简介

0.本篇问题 线性表&#xff0c;顺序表&#xff0c;链表什么关系&#xff1f;它们是逻辑结构还是存储结构&#xff1f;线性表的基本操作有哪些&#xff1f; 线性表是具有相同数据元素的有限序列。 表中元素有先后次序&#xff0c;每个元素占有相同大小的存储空间。 一、线性…

设计模式(行为型)-备忘录模式

目录 定义 类图 角色 角色详解 &#xff08;一&#xff09;发起人角色&#xff08;Originator&#xff09;​ &#xff08;二&#xff09;备忘录角色&#xff08;Memento&#xff09;​ &#xff08;三&#xff09;备忘录管理员角色&#xff08;Caretaker&#xff09;​…

Navicat如何查看密码

近期遇到需要将大部分已存储的navicat数据库转发给其他人&#xff0c;于是乎进行导出文件 奈何对方不用navicat&#xff0c;无法进行文件的导入从而导入链接 搜罗navicat的密码查看&#xff0c;大部分都为php代码解析 以下转载GitHub上看到的一个python代码解析的脚本 这里是对…

Matlab 四分之一车体车辆半主动悬架鲁棒控制

1、内容简介 略 Matlab 173-四分之一车体车辆半主动悬架鲁棒控制 可以交流、咨询、答疑 2、内容说明 略 3、仿真分析 略 4、参考论文 略

Python学习第十九天

Django-分页 后端分页 Django提供了Paginator类来实现后端分页。Paginator类可以将一个查询集&#xff08;QuerySet&#xff09;分成多个页面&#xff0c;每个页面包含指定数量的对象。 from django.shortcuts import render, redirect, get_object_or_404 from .models impo…