BIG MERGE!!!
BIG ADD: - docker - archlinux FIX: - vim - c_cpp - string hash - linux /dev/random - thread - STL - linux - command - last OTHERS: - add antenna.md - mirrors - makefile.md
This commit is contained in:
parent
7539960a7d
commit
93cecd7544
10
electronic/parameter.md
Normal file
10
electronic/parameter.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# 电子硬件参数
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
- [电阻](#电阻)
|
||||||
|
- [电容](#电容)
|
||||||
|
- [电感](#电感)
|
||||||
|
- [微控制器](#微控制器)
|
||||||
|
- [逻辑器件](#逻辑器件)
|
||||||
|
- [晶体管](#晶体管)
|
||||||
|
|
0
miscellaneous/README.md
Normal file
0
miscellaneous/README.md
Normal file
19
os/linux/arch/command.md
Normal file
19
os/linux/arch/command.md
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# arch常用命令
|
||||||
|
|
||||||
|
- [pacman](#pacman)
|
||||||
|
|
||||||
|
|
||||||
|
## pacman
|
||||||
|
|
||||||
|
+ `-S` 同步
|
||||||
|
+ `-y` 更新软件包数据库
|
||||||
|
+ `-u` 升级已有安装包
|
||||||
|
+ `-R` 卸载
|
||||||
|
+ `-Q` 查看已安装
|
||||||
|
> 示例
|
||||||
|
+ `pacman -Sy` 同步数据库
|
||||||
|
+ `pacman -S <package_name>` 安装软件包
|
||||||
|
+ `pacman -Syu` 更新系统
|
||||||
|
+ `pacman -Rs <package_name>` 卸载同时删除无用的依赖
|
||||||
|
+ `pacman -Ss <keyword>` 搜索软件包
|
||||||
|
+ `sudo pacman -Sc` 清除缓存
|
125
os/linux/arch/install.md
Normal file
125
os/linux/arch/install.md
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
# archlinux安装
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
- [基础安装](#基础安装)
|
||||||
|
- [修改控制台字体](#修改控制台字体)
|
||||||
|
- [验证引导](#验证引导)
|
||||||
|
- [验证网络和更改系统时间](#验证网络和更改系统时间)
|
||||||
|
- [硬盘分区](#硬盘分区)
|
||||||
|
- [安装基础软件包](#安装基础软件包)
|
||||||
|
- [生成fstab](#生成fstab)
|
||||||
|
- [chroot配置](#chroot)
|
||||||
|
- [新系统](#新系统)
|
||||||
|
- [换源](#换源)
|
||||||
|
- [普通用户](#普通用户)
|
||||||
|
- [KDE](#kde)
|
||||||
|
|
||||||
|
## 基础安装
|
||||||
|
|
||||||
|
### 修改控制台字体
|
||||||
|
|
||||||
|
`/usr/share/kbd/consolefonts/` 存放字体的位置
|
||||||
|
`# setfont ter-132b`
|
||||||
|
|
||||||
|
### 验证引导
|
||||||
|
|
||||||
|
`# cat /sys/firmware/efi/fw_platform_size`
|
||||||
|
|
||||||
|
### 验证网络和更改系统时间
|
||||||
|
|
||||||
|
`ip addr`
|
||||||
|
`timedatectl`
|
||||||
|
|
||||||
|
### 硬盘分区
|
||||||
|
|
||||||
|
```bash
|
||||||
|
parted /dev/sdX # 进入parted交互界面
|
||||||
|
> mklabel gpt # 创建分区表格式
|
||||||
|
|
||||||
|
gdisk /dev/sdX # 分区
|
||||||
|
ef00 -> 1G
|
||||||
|
ef02 -> 2M
|
||||||
|
8300 -> /
|
||||||
|
|
||||||
|
**先用最小系统启动**
|
||||||
|
|
||||||
|
mkfs.fat -F 32 /dev/sdX1 # 分区格式化
|
||||||
|
mkfs.ext4 /dev/sdX3
|
||||||
|
|
||||||
|
mount /dev/sdX3 /mnt
|
||||||
|
mount --mkdir /dev/sdX1 /mnt/boot
|
||||||
|
```
|
||||||
|
|
||||||
|
### 安装基础软件包
|
||||||
|
|
||||||
|
`pacstrap -K /mnt xxx`
|
||||||
|
+ base linux linux-firmware
|
||||||
|
+ vim base-devel networkmanager archlinuxcn-keyring
|
||||||
|
---
|
||||||
|
以下是可以等系统启动后安装的
|
||||||
|
+ sof-firmware
|
||||||
|
+ yay
|
||||||
|
`pacman -S git base-devel && git clone https://aur.archlinux.org/yay.git && cd yay && makepkg -si`
|
||||||
|
+ man
|
||||||
|
+ fcitx5-im fcitx5-rime # 输入法
|
||||||
|
+ alsa-utils # 声卡驱动
|
||||||
|
+ 其他固件
|
||||||
|
|
||||||
|
### 生成fstab
|
||||||
|
|
||||||
|
`genfstab -U /mnt > /mnt/etc/fstab`
|
||||||
|
|
||||||
|
### chroot
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime # 配置时间
|
||||||
|
hwclock --systohc
|
||||||
|
|
||||||
|
vim /etc/locale.gen
|
||||||
|
> 去掉 en_GB.UTF-8 以及 zh_CN.
|
||||||
|
locale-gen
|
||||||
|
vim /etc/locale.conf
|
||||||
|
> LANG=en_US.UTF-8
|
||||||
|
|
||||||
|
vim /etc/hostname
|
||||||
|
> [hostname]
|
||||||
|
|
||||||
|
passwd
|
||||||
|
|
||||||
|
**安装引导**
|
||||||
|
pacman -S grub
|
||||||
|
grub-install --target=i386-pc /dev/sdX
|
||||||
|
grub-mkconfig -o /boot/grub/grub.cfg
|
||||||
|
|
||||||
|
umount -R /mnt
|
||||||
|
|
||||||
|
reboot
|
||||||
|
```
|
||||||
|
|
||||||
|
## 新系统
|
||||||
|
|
||||||
|
### 换源
|
||||||
|
- `/etc/pacman.d/mirrorlist`
|
||||||
|
```
|
||||||
|
Server = https://mirrors.tuna.tsinghua.edu.cn/archlinux/$repo/os/$arch
|
||||||
|
Server = http://mirrors.aliyun.com/archlinux/$repo/os/$arch
|
||||||
|
Server = https://mirrors.ustc.edu.cn/archlinux/$repo/os/$arch
|
||||||
|
```
|
||||||
|
|
||||||
|
### 普通用户
|
||||||
|
|
||||||
|
`useradd -m -G wheel username`
|
||||||
|
`vim /etc/sudoers`
|
||||||
|
|
||||||
|
### kde
|
||||||
|
|
||||||
|
```
|
||||||
|
pacman -S noto-fonts noto-fonts-cjk noto-fonts-emoji # 安装字体
|
||||||
|
pacman -S plasma
|
||||||
|
systemctl enable sddm
|
||||||
|
|
||||||
|
cd ~/.local/share/fcitx5/rime # 配置输入法
|
||||||
|
git clone https://github.com/iDvel/rime-ice.git
|
||||||
|
cp -r ./rime-ice/* .
|
||||||
|
|
||||||
|
sudo usermod -a -G uucp $USER # 允许用户使用串口
|
1029
os/linux/command.md
1029
os/linux/command.md
File diff suppressed because it is too large
Load Diff
@ -1,117 +0,0 @@
|
|||||||
# ~/.bashrc: executed by bash(1) for non-login shells.
|
|
||||||
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
|
|
||||||
# for examples
|
|
||||||
|
|
||||||
# If not running interactively, don't do anything
|
|
||||||
case $- in
|
|
||||||
*i*) ;;
|
|
||||||
*) return;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# don't put duplicate lines or lines starting with space in the history.
|
|
||||||
# See bash(1) for more options
|
|
||||||
HISTCONTROL=ignoreboth
|
|
||||||
|
|
||||||
# append to the history file, don't overwrite it
|
|
||||||
shopt -s histappend
|
|
||||||
|
|
||||||
# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
|
|
||||||
HISTSIZE=500
|
|
||||||
HISTFILESIZE=500
|
|
||||||
|
|
||||||
# check the window size after each command and, if necessary,
|
|
||||||
# update the values of LINES and COLUMNS.
|
|
||||||
shopt -s checkwinsize
|
|
||||||
|
|
||||||
# If set, the pattern "**" used in a pathname expansion context will
|
|
||||||
# match all files and zero or more directories and subdirectories.
|
|
||||||
#shopt -s globstar
|
|
||||||
|
|
||||||
# make less more friendly for non-text input files, see lesspipe(1)
|
|
||||||
[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"
|
|
||||||
|
|
||||||
# set variable identifying the chroot you work in (used in the prompt below)
|
|
||||||
if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
|
|
||||||
debian_chroot=$(cat /etc/debian_chroot)
|
|
||||||
fi
|
|
||||||
|
|
||||||
# set a fancy prompt (non-color, unless we know we "want" color)
|
|
||||||
case "$TERM" in
|
|
||||||
xterm-color|*-256color) color_prompt=yes;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# uncomment for a colored prompt, if the terminal has the capability; turned
|
|
||||||
# off by default to not distract the user: the focus in a terminal window
|
|
||||||
# should be on the output of commands, not on the prompt
|
|
||||||
#force_color_prompt=yes
|
|
||||||
|
|
||||||
if [ -n "$force_color_prompt" ]; then
|
|
||||||
if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
|
|
||||||
# We have color support; assume it's compliant with Ecma-48
|
|
||||||
# (ISO/IEC-6429). (Lack of such support is extremely rare, and such
|
|
||||||
# a case would tend to support setf rather than setaf.)
|
|
||||||
color_prompt=yes
|
|
||||||
else
|
|
||||||
color_prompt=
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$color_prompt" = yes ]; then
|
|
||||||
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h@\t\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
|
|
||||||
else
|
|
||||||
PS1='${debian_chroot:+($debian_chroot)}\u@\h@\t:\w\$ '
|
|
||||||
fi
|
|
||||||
unset color_prompt force_color_prompt
|
|
||||||
|
|
||||||
# If this is an xterm set the title to user@host:dir
|
|
||||||
case "$TERM" in
|
|
||||||
xterm*|rxvt*)
|
|
||||||
PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h@\t: \w\a\]$PS1"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# enable color support of ls and also add handy aliases
|
|
||||||
if [ -x /usr/bin/dircolors ]; then
|
|
||||||
test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
|
|
||||||
alias ls='ls --color=auto'
|
|
||||||
#alias dir='dir --color=auto'
|
|
||||||
#alias vdir='vdir --color=auto'
|
|
||||||
|
|
||||||
alias grep='grep --color=auto'
|
|
||||||
alias fgrep='fgrep --color=auto'
|
|
||||||
alias egrep='egrep --color=auto'
|
|
||||||
fi
|
|
||||||
|
|
||||||
# colored GCC warnings and errors
|
|
||||||
#export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'
|
|
||||||
|
|
||||||
# some more ls aliases
|
|
||||||
alias ll='ls -ahlF'
|
|
||||||
alias l='ls -lF'
|
|
||||||
# Add an "alert" alias for long running commands. Use like so:
|
|
||||||
# sleep 10; alert
|
|
||||||
alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'
|
|
||||||
|
|
||||||
# Alias definitions.
|
|
||||||
# You may want to put all your additions into a separate file like
|
|
||||||
# ~/.bash_aliases, instead of adding them here directly.
|
|
||||||
# See /usr/share/doc/bash-doc/examples in the bash-doc package.
|
|
||||||
|
|
||||||
if [ -f ~/.bash_aliases ]; then
|
|
||||||
. ~/.bash_aliases
|
|
||||||
fi
|
|
||||||
|
|
||||||
# enable programmable completion features (you don't need to enable
|
|
||||||
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
|
|
||||||
# sources /etc/bash.bashrc).
|
|
||||||
if ! shopt -oq posix; then
|
|
||||||
if [ -f /usr/share/bash-completion/bash_completion ]; then
|
|
||||||
. /usr/share/bash-completion/bash_completion
|
|
||||||
elif [ -f /etc/bash_completion ]; then
|
|
||||||
. /etc/bash_completion
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
alias powerele="upower -i /org/freedesktop/UPower/devices/battery_BAT0"
|
|
||||||
export LANG=en_US.UTF-8
|
|
@ -1,27 +0,0 @@
|
|||||||
# ~/.profile: executed by the command interpreter for login shells.
|
|
||||||
# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
|
|
||||||
# exists.
|
|
||||||
# see /usr/share/doc/bash/examples/startup-files for examples.
|
|
||||||
# the files are located in the bash-doc package.
|
|
||||||
|
|
||||||
# the default umask is set in /etc/profile; for setting the umask
|
|
||||||
# for ssh logins, install and configure the libpam-umask package.
|
|
||||||
#umask 022
|
|
||||||
|
|
||||||
# if running bash
|
|
||||||
if [ -n "$BASH_VERSION" ]; then
|
|
||||||
# include .bashrc if it exists
|
|
||||||
if [ -f "$HOME/.bashrc" ]; then
|
|
||||||
. "$HOME/.bashrc"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# set PATH so it includes user's private bin if it exists
|
|
||||||
if [ -d "$HOME/bin" ] ; then
|
|
||||||
PATH="$HOME/bin:$PATH"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# set PATH so it includes user's private bin if it exists
|
|
||||||
if [ -d "$HOME/.local/bin" ] ; then
|
|
||||||
PATH="$HOME/.local/bin:$PATH"
|
|
||||||
fi
|
|
252
program/c_cpp/STL/algorithms.md
Normal file
252
program/c_cpp/STL/algorithms.md
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
# STL算法
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
- [非修改性算法](#)
|
||||||
|
- [find](#)
|
||||||
|
- [conut](#)
|
||||||
|
- [二分查找](#binary-search)
|
||||||
|
- [修改性算法](#)
|
||||||
|
- [copy](#)
|
||||||
|
- [replace](#):将指定范围内等于给定值的元素替换为新值
|
||||||
|
- [reverse](#):翻转序列
|
||||||
|
- [排序算法](#)
|
||||||
|
- [sort](#)
|
||||||
|
- [稳定排序](#stable-sort)
|
||||||
|
- [第n大数](#nth-element)
|
||||||
|
- [数值算法](#)
|
||||||
|
- [accumulate](#):计算指定范围内元素的累积和
|
||||||
|
- [计算两个序列的内积](#inner-product)
|
||||||
|
- [集合算法](#)
|
||||||
|
- [两个有序序列的差集](#set-difference)
|
||||||
|
- [将两个有序序列合并为一个有序序列](#merge)
|
||||||
|
- [其他算法](#)
|
||||||
|
- [去除相邻重复元素](#unique)
|
||||||
|
- [随机打乱序列](#shuffle)
|
||||||
|
|
||||||
|
## 非修改性算法
|
||||||
|
### find
|
||||||
|
```
|
||||||
|
template <class InputIterator, class T>
|
||||||
|
InputIterator find(InputIterator first, InputIterator last, const T& value);
|
||||||
|
```
|
||||||
|
+ InputIterator:输入迭代器类型,表示要搜索的范围的起始和结束位置。
|
||||||
|
+ first:指向范围的起始位置的迭代器。
|
||||||
|
+ last:指向范围的结束位置的迭代器(不包含)。
|
||||||
|
+ value:要查找的目标值。
|
||||||
|
+ 返回值:如果找到目标值,返回指向该元素的迭代器;如果没有找到,则返回 last
|
||||||
|
|
||||||
|
__注意事项__
|
||||||
|
1. 返回值的判断
|
||||||
|
如果未找到目标值,返回值是 last,通常需要通过比较返回值是否等于 last 来判断是否找到目标
|
||||||
|
|
||||||
|
2. 自定义对象的比较
|
||||||
|
如果要在自定义对象中使用 `std::find`,需要重载 `operator==`,以便算法能够比较对象是否相等
|
||||||
|
|
||||||
|
3. 性能
|
||||||
|
是线性查找算法,时间复杂度为 O(n),其中 n 是范围内的元素数量
|
||||||
|
|
||||||
|
4. 范围的正确性
|
||||||
|
确保 first 和 last 指向的范围是有效的,并且 first 不大于 last
|
||||||
|
|
||||||
|
### conut
|
||||||
|
```
|
||||||
|
template <class InputIterator, class T>
|
||||||
|
typename iterator_traits<InputIterator>::difference_type count(
|
||||||
|
InputIterator first,
|
||||||
|
InputIterator last,
|
||||||
|
const T& value
|
||||||
|
);
|
||||||
|
```
|
||||||
|
+ InputIterator:输入迭代器类型,表示要搜索的范围的起始和结束位置。
|
||||||
|
+ first:指向范围的起始位置的迭代器。
|
||||||
|
+ last:指向范围的结束位置的迭代器(不包含)。
|
||||||
|
+ value:要统计的目标值。
|
||||||
|
+ 返回值:返回等于目标值的元素个数,类型为 `iterator_traits<InputIterator>::difference_type`
|
||||||
|
|
||||||
|
__注意事项__
|
||||||
|
1. 返回值的判断
|
||||||
|
返回值类型是 `iterator_traits<InputIterator>::difference_type`,通常是与容器相关的整数类型 `int` `size_t`
|
||||||
|
|
||||||
|
2. 自定义对象的比较
|
||||||
|
需要重载 `operator==`,以便算法能够比较对象是否相等
|
||||||
|
|
||||||
|
3. 性能
|
||||||
|
是线性查找算法,时间复杂度为 O(n),其中 n 是范围内的元素数量
|
||||||
|
|
||||||
|
4. 范围的正确性
|
||||||
|
确保 first 和 last 指向的范围是有效的,并且 first 不大于 last
|
||||||
|
|
||||||
|
### binary-search
|
||||||
|
用于在*有序序列*中查找是否存在某个值,基于二分查找的思想,时间复杂度为 O(log n)
|
||||||
|
|
||||||
|
只返回布尔值,表示是否找到目标值,如果需要找到目标值的位置,可以结合 `std::lower_bound` 或 `std::upper_bound` 使用
|
||||||
|
```
|
||||||
|
template <class ForwardIterator, class T>
|
||||||
|
bool binary_search(ForwardIterator first, ForwardIterator last, const T& value);
|
||||||
|
```
|
||||||
|
+ ForwardIterator:正向迭代器类型,表示要搜索的范围的起始和结束位置。
|
||||||
|
+ first:指向范围的起始位置的迭代器。
|
||||||
|
+ last:指向范围的结束位置的迭代器(不包含)。
|
||||||
|
+ value:要查找的目标值。
|
||||||
|
+ 返回值:如果找到目标值,返回 true;否则返回 false。
|
||||||
|
|
||||||
|
__还支持自定义比较函数__
|
||||||
|
```
|
||||||
|
template <class ForwardIterator, class T, class Compare>
|
||||||
|
bool binary_search(ForwardIterator first, ForwardIterator last, const T& value, Compare comp);
|
||||||
|
```
|
||||||
|
+ Compare:比较函数,用于定义元素之间的大小关系。如果未提供,会使用默认的 < 比较运算符
|
||||||
|
|
||||||
|
## 修改性算法
|
||||||
|
### copy
|
||||||
|
用于将一个范围内的元素复制到另一个范围中,是一个线性算法,时间复杂度为 O(n)
|
||||||
|
|
||||||
|
```
|
||||||
|
template <class InputIterator, class OutputIterator>
|
||||||
|
OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result);
|
||||||
|
```
|
||||||
|
+ InputIterator:输入迭代器类型,表示要复制的源范围的起始和结束位置。
|
||||||
|
+ first:指向源范围的起始位置的迭代器。
|
||||||
|
+ last:指向源范围的结束位置的迭代器(不包含)。
|
||||||
|
+ OutputIterator:输出迭代器类型,表示目标范围的起始位置。
|
||||||
|
+ result:指向目标范围的起始位置的迭代器。
|
||||||
|
+ 返回值:返回指向目标范围结束位置的迭代器(即 result + (last - first))
|
||||||
|
|
||||||
|
### replace
|
||||||
|
用于在指定范围内将所有等于某个特定值的元素替换为另一个值
|
||||||
|
|
||||||
|
```
|
||||||
|
template <class ForwardIterator, class T>
|
||||||
|
void replace(ForwardIterator first, ForwardIterator last, const T& old_value, const T& new_value);
|
||||||
|
```
|
||||||
|
+ ForwardIterator:正向迭代器类型,表示要操作的范围的起始和结束位置。
|
||||||
|
+ first:指向范围的起始位置的迭代器。
|
||||||
|
+ last:指向范围的结束位置的迭代器(不包含)。
|
||||||
|
+ `old_value`:要被替换的旧值。
|
||||||
|
+ `new_value`:用于替换的新值。
|
||||||
|
|
||||||
|
如果需要更复杂的替换逻辑(例如基于条件的替换),可以结合 `std::replace_if` 使用,后者允许传入一个谓词函数来定义替换条件。
|
||||||
|
|
||||||
|
### reverse
|
||||||
|
反转指定范围内的元素顺序,要求输入范围的迭代器是双向迭代器,即支持双向遍历
|
||||||
|
|
||||||
|
```
|
||||||
|
template <class BidirectionalIterator>
|
||||||
|
void reverse(BidirectionalIterator first, BidirectionalIterator last);
|
||||||
|
```
|
||||||
|
+ BidirectionalIterator:双向迭代器类型,表示要反转的范围的起始和结束位置。
|
||||||
|
+ first:指向范围的起始位置的迭代器。
|
||||||
|
+ last:指向范围的结束位置的迭代器(不包含)
|
||||||
|
|
||||||
|
## 排序算法
|
||||||
|
### sort
|
||||||
|
指定范围内的元素进行排序,要求输入范围的迭代器是随机访问迭代器,是不稳定的排序算法,平均时间复杂度为 O(n log n)
|
||||||
|
|
||||||
|
```
|
||||||
|
template <class RandomAccessIterator>
|
||||||
|
void sort(RandomAccessIterator first, RandomAccessIterator last);
|
||||||
|
```
|
||||||
|
+ RandomAccessIterator:随机访问迭代器类型,表示要排序的范围的起始和结束位置
|
||||||
|
+ first:指向范围的起始位置的迭代器
|
||||||
|
+ last:指向范围的结束位置的迭代器(不包含)
|
||||||
|
|
||||||
|
此外,std::sort 还支持自定义比较函数
|
||||||
|
```
|
||||||
|
template <class RandomAccessIterator, class Compare>
|
||||||
|
void sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp);
|
||||||
|
```
|
||||||
|
|
||||||
|
### stable-sort
|
||||||
|
是一个稳定排序算法,对指定范围内的元素进行排序,同时保证相等元素的相对顺序不变
|
||||||
|
|
||||||
|
```
|
||||||
|
template <class RandomAccessIterator>
|
||||||
|
void stable_sort(RandomAccessIterator first, RandomAccessIterator last);
|
||||||
|
|
||||||
|
template <class RandomAccessIterator, class Compare>
|
||||||
|
void stable_sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp);
|
||||||
|
```
|
||||||
|
+ first 和 last:随机访问迭代器,分别指向要排序范围的起始位置和结束位置(不包含)
|
||||||
|
+ Compare:可选的比较函数,用于定义排序规则。如果未提供,默认使用 < 运算符
|
||||||
|
|
||||||
|
如果有足够的额外内存,`std::stable_sort` 的时间复杂度为 O(n log n),内存不足,时间复杂度可能退化为 O(n log² n)
|
||||||
|
|
||||||
|
|
||||||
|
### nth-element
|
||||||
|
用于部分排序序列,使得第 k 小的元素被放置到正确的位置,同时保证所有在它之前的元素都不大于它,所有在它之后的元素都不小于它,平均时间复杂度:O(n),最坏时间复杂度:O(n²)
|
||||||
|
|
||||||
|
```
|
||||||
|
template <class RandomIt>
|
||||||
|
void nth_element(RandomIt first, RandomIt nth, RandomIt last);
|
||||||
|
|
||||||
|
template <class RandomIt, class Compare>
|
||||||
|
void nth_element(RandomIt first, RandomIt nth, RandomIt last, Compare comp);
|
||||||
|
```
|
||||||
|
+ first:指向序列起始位置的随机访问迭代器。
|
||||||
|
+ nth:指向序列中第 k 个位置的迭代器(0-based index)。
|
||||||
|
+ last:指向序列结束位置的迭代器。
|
||||||
|
+ comp(可选):自定义比较函数,默认使用 std::less
|
||||||
|
|
||||||
|
> 不会完全排序整个序列,它只保证第 k 小的元素在正确的位置上
|
||||||
|
> 该算法的性能优于完全排序
|
||||||
|
|
||||||
|
## 数值算法
|
||||||
|
### accumulate
|
||||||
|
用于计算指定范围内元素的累积和,时间复杂度为 O(n)
|
||||||
|
|
||||||
|
`std::accumulate` 从 first 开始,逐个处理范围内的元素,将每个元素与累积结果进行操作(默认为加法),并将最终结果返回
|
||||||
|
|
||||||
|
```
|
||||||
|
template <class InputIterator, class T>
|
||||||
|
T accumulate(InputIterator first, InputIterator last, T init);
|
||||||
|
|
||||||
|
template <class InputIterator, class T, class BinaryOperation>
|
||||||
|
T accumulate(InputIterator first, InputIterator last, T init, BinaryOperation op);
|
||||||
|
```
|
||||||
|
+ InputIterator:输入迭代器类型,表示要操作的范围的起始和结束位置。
|
||||||
|
+ first:指向范围的起始位置的迭代器。
|
||||||
|
+ last:指向范围的结束位置的迭代器(不包含)。
|
||||||
|
+ T:累积结果的类型。
|
||||||
|
+ init:初始值,用于开始累积操作。
|
||||||
|
+ BinaryOperation(可选):二元操作函数,用于定义累积操作。如果未提供,默认使用加法操作 `std::plus<T>` [预定义函数符](./containers.md#)
|
||||||
|
|
||||||
|
### inner-product
|
||||||
|
|
||||||
|
## 集合算法
|
||||||
|
### set-difference
|
||||||
|
### merge
|
||||||
|
|
||||||
|
## 其他算法
|
||||||
|
### unique
|
||||||
|
用于移除序列中相邻的重复元素,并返回一个指向“新序列”结束位置的迭代器。它不会改变原序列的长度,而是将重复元素移动到序列末尾,并返回一个指向“有效部分”结束位置的迭代器。因此,通常需要结合容器的 erase 方法来真正移除重复元素,O(n)
|
||||||
|
|
||||||
|
```
|
||||||
|
template <class ForwardIterator>
|
||||||
|
ForwardIterator unique(ForwardIterator first, ForwardIterator last);
|
||||||
|
|
||||||
|
template <class ForwardIterator, class BinaryPredicate>
|
||||||
|
ForwardIterator unique(ForwardIterator first, ForwardIterator last, BinaryPredicate pred);
|
||||||
|
```
|
||||||
|
+ ForwardIterator:正向迭代器类型,表示要操作的序列的起始和结束位置。
|
||||||
|
+ first:指向序列起始位置的迭代器。
|
||||||
|
+ last:指向序列结束位置的迭代器(不包含)。
|
||||||
|
+ BinaryPredicate(可选):二元谓词函数,用于定义两个元素是否相等。如果未提供,默认使用 operator==
|
||||||
|
|
||||||
|
### shuffle
|
||||||
|
随机打乱指定范围内元素的顺序
|
||||||
|
|
||||||
|
```
|
||||||
|
template <class RandomAccessIterator, class URNG>
|
||||||
|
void shuffle(RandomAccessIterator first, RandomAccessIterator last, URNG&& g);
|
||||||
|
```
|
||||||
|
+ first 和 last:随机访问迭代器,分别指向要打乱范围的起始位置和结束位置(不包含)
|
||||||
|
+ URNG:均匀随机数生成器,例如 `std::mt19937` 或 `std::default_random_enginei`
|
||||||
|
|
||||||
|
```
|
||||||
|
// 使用随机数生成器
|
||||||
|
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
|
||||||
|
std::mt19937 rng(seed);
|
||||||
|
|
||||||
|
// 打乱顺序
|
||||||
|
std::shuffle(vec.begin(), vec.end(), rng);
|
||||||
|
```
|
240
program/c_cpp/STL/containers.md
Normal file
240
program/c_cpp/STL/containers.md
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
# STL 容器
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
- [概念](#)
|
||||||
|
- [通性](#)
|
||||||
|
- [序列容器](#)
|
||||||
|
- [vector](#)
|
||||||
|
- [deque](#)
|
||||||
|
- [list](#)
|
||||||
|
- [关联容器](#)
|
||||||
|
- [set](#)
|
||||||
|
- [multiset](#)
|
||||||
|
- [map](#)
|
||||||
|
- [multimap](#)
|
||||||
|
- [无序容器](#)
|
||||||
|
- [`unordered_set`](#unordered_set)
|
||||||
|
- [`unordered_multiset`](#unordered_multiset)
|
||||||
|
- [`unordered_map`](#unordered_map)
|
||||||
|
- [`unordered_multimap`](#unordered_multimap)
|
||||||
|
- [预定义函数符](#)
|
||||||
|
|
||||||
|
## 概念
|
||||||
|
|
||||||
|
**函数符**概念
|
||||||
|
|
||||||
|
其实就是重载了()的伪函数
|
||||||
|
|
||||||
|
- 生成器:无参数
|
||||||
|
- 一元函数:一个参数
|
||||||
|
- 二元函数:两个参数
|
||||||
|
- 谓词:返回bool的一元函数
|
||||||
|
- 二元谓词:返回bool的二元函数
|
||||||
|
|
||||||
|
## 通性
|
||||||
|
|
||||||
|
+ `begin()` 和 `end()` 用于获取容器的迭代器,指向容器的第一个元素和最后一个元素的“后继”
|
||||||
|
+ `rbegin()` 和 `rend()` 用于获取容器的反向迭代器,指向容器的最后一个元素和第一个元素的“前驱”位置
|
||||||
|
+ `size()` 返回容器中元素的数量
|
||||||
|
+ `empty()` 如果容器为空,返回true;否则返回false
|
||||||
|
+ `max_size()` 返回容器可能存储的最大元素数量
|
||||||
|
+ `clear()` 清空容器中的所有元素,但不释放内存
|
||||||
|
+ `swap()` 交换两个容器的内容
|
||||||
|
+ `data()` **仅适用于序列容器** 返回指向容器底层存储的指针
|
||||||
|
+ 提供对容器底层数据的直接访问
|
||||||
|
+ 适用于需要与C语言风格的API交互的场景
|
||||||
|
+ `front()` 和 `back()` **仅适用于序列容器** 返回容器的第一个元素和最后一个元素的引用
|
||||||
|
+ `operator[]` 和 `at()` **仅适用于序列容器** 访问容器中的特定元素
|
||||||
|
+ at() 进行边界检查,如果索引超出范围,会抛出`std::out_of_range`异常
|
||||||
|
|
||||||
|
## 序列容器
|
||||||
|
|
||||||
|
存储元素的顺序与插入顺序一致
|
||||||
|
|
||||||
|
### vector
|
||||||
|
|
||||||
|
1. 定义和初始化
|
||||||
|
|
||||||
|
`std::vector<int> vec1; // 定义一个空的 vector`
|
||||||
|
`std::vector<int> vec2 = {1, 2, 3, 4, 5}; // 使用初始化列表初始化`
|
||||||
|
`std::vector<int> vec3(10, 0); // 10个元素,初始值为0`
|
||||||
|
`std::vector<int> vec4(vec2); // 拷贝构造`
|
||||||
|
`std::vector<int> vec5(std::move(vec2)); // 移动构造`
|
||||||
|
|
||||||
|
2. 元素访问
|
||||||
|
|
||||||
|
支持序列容器的大部分访问方法
|
||||||
|
|
||||||
|
3. 修改容器
|
||||||
|
|
||||||
|
`push_back()` 在容器末尾添加一个元素
|
||||||
|
`pop_back()` 删除容器末尾的元素
|
||||||
|
`insert()` 在指定位置插入一个或多个元素
|
||||||
|
`erase()` 删除指定位置的元素
|
||||||
|
|
||||||
|
4. 容量和大小
|
||||||
|
|
||||||
|
`capacity()` 返回容器当前分配的内存容量(以元素数量计)
|
||||||
|
`reserve()` 预分配内存,减少动态扩展的次数
|
||||||
|
`shrink_to_fit()` 收缩内存,释放多余空间
|
||||||
|
|
||||||
|
__使用技巧__
|
||||||
|
|
||||||
|
1. 预分配内存
|
||||||
|
|
||||||
|
如果知道容器将存储大量元素,可以使用 reserve() 预分配内存,以减少动态扩展的次数
|
||||||
|
|
||||||
|
2. 使用 `std::move()`
|
||||||
|
|
||||||
|
`vec2.push_back(std::move(vec1[0])); // 将vec1的第一个元素移动到vec2`
|
||||||
|
|
||||||
|
3. 使用vector的bool值特性
|
||||||
|
|
||||||
|
`std::vector<bool>` 是一个特化版本,它使用位存储来优化空间占用,但可能会牺牲某些操作的性能
|
||||||
|
|
||||||
|
4. 使用 `std::vector` 的指针特性
|
||||||
|
|
||||||
|
如果需要存储动态分配的对象,可以使用 `std::vector<std::unique_ptr<T>>` 或 `std::vector<std::shared_ptr<T>>`
|
||||||
|
|
||||||
|
|
||||||
|
__vector 的 capacity 和 size 属性区别__
|
||||||
|
|
||||||
|
size 是当前 vector 容器真实占用的大小,也就是容器当前拥有多少个容器。
|
||||||
|
|
||||||
|
capacity 是指在发生 realloc 前能允许的最大元素数,即预分配的内存空间。
|
||||||
|
|
||||||
|
使用 resize() 容器内的对象内存空间是真正存在的。
|
||||||
|
|
||||||
|
使用 reserve() 仅仅只是修改了 capacity 的值,容器内的对象并没有真实的内存空间(空间是"野"的)。
|
||||||
|
|
||||||
|
### deque
|
||||||
|
1. 插入和删除
|
||||||
|
+ `push_back()` 和 `pop_back()`:尾部操作
|
||||||
|
+ `push_front()` 和 `pop_front()`:头部操作
|
||||||
|
+ `insert()` 和 `erase()`:在任意位置插入或删除
|
||||||
|
|
||||||
|
2. 大小操作
|
||||||
|
+ `resize()`:调整容器大小
|
||||||
|
|
||||||
|
__使用技巧__
|
||||||
|
> 高效头部操作:`deque` 是处理头部和尾部频繁插入删除的理想选择
|
||||||
|
> 随机访问优化:虽然 `deque` 的内存不连续,但通过下标访问效率较高
|
||||||
|
> 排序:由于支持随机访问,可以使用 `std::sort` 对 `deque` 进行排序
|
||||||
|
> 迭代器失效:在添加或删除元素后,迭代器可能失效,需要重新获取
|
||||||
|
|
||||||
|
__注意事项__
|
||||||
|
> 内存不连续:`deque` 的元素可能分散在多个内存块中,但通过下标或迭代器访问不会受到影响
|
||||||
|
> 迭代器失效:在容器大小发生变化时(如插入或删除元素),迭代器可能会失效
|
||||||
|
> 性能权衡:虽然 `deque` 在头部和尾部操作高效,但在中间插入或删除元素的性能不如 `list`
|
||||||
|
|
||||||
|
__相比vector的优势__
|
||||||
|
> 头部操作高效:deque 在头部插入和删除操作的时间复杂度为 O(1),而 vector 为 O(n)。
|
||||||
|
> 动态变化灵活:deque 的*分块内存*分配使其更灵活,性能损耗更小,且内存不足时不用搬运所有元素
|
||||||
|
> 随机访问性能接近:虽然 deque 的随机访问效率略低于 vector,但差距不大
|
||||||
|
|
||||||
|
### list
|
||||||
|
1. 特点
|
||||||
|
+ 双向链表结构:每个元素包含指向前后元素的指针,支持双向遍历
|
||||||
|
+ 高效插入和删除:在任意位置插入或删除元素的时间复杂度为 O(1),前提是已知位置
|
||||||
|
+ 不支持随机访问:无法通过索引直接访问元素,只能通过迭代器遍历
|
||||||
|
+ 稳定的迭代器:插入和删除操作不会使迭代器失效,除非删除了迭代器所指向的元素
|
||||||
|
|
||||||
|
1. 插入和删除
|
||||||
|
+ `push_back()` 和 `pop_back()`:尾部操作
|
||||||
|
+ `push_front()` 和 `pop_front()`:头部操作
|
||||||
|
+ `insert()` 和 `erase()`:在任意位置插入或删除
|
||||||
|
|
||||||
|
2. 其他
|
||||||
|
+ resize():调整容器大小
|
||||||
|
+ swap():交换两个 list 的内容
|
||||||
|
+ splice():将一个 list 的元素插入到另一个 list 的指定位置
|
||||||
|
+ sort()、merge()、reverse():排序、合并和反转
|
||||||
|
|
||||||
|
__注意事项__
|
||||||
|
> 不支持随机访问:无法通过索引访问元素,只能通过迭代器
|
||||||
|
> 内存开销:每个元素存储额外的指针,内存开销较大
|
||||||
|
> 缓存局部性差:元素不连续存储,遍历性能不如 std::vector
|
||||||
|
> 适用场景有限:只有在需要频繁中间插入和删除时才适合使用
|
||||||
|
|
||||||
|
|
||||||
|
## 关联容器
|
||||||
|
|
||||||
|
存储元素时会自动排序,通常基于键值对
|
||||||
|
|
||||||
|
### set
|
||||||
|
基于红黑树实现 适用于需要去重、排序和*高效查找*的场景
|
||||||
|
|
||||||
|
1. 特点
|
||||||
|
+ 元素唯一性:容器中不允许存储重复元素
|
||||||
|
+ 自动排序:元素会根据指定的比较规则自动排序,默认为升序
|
||||||
|
+ 高效查找:插入、删除和查找操作的时间复杂度均为 O(log n)
|
||||||
|
|
||||||
|
2. 构造与初始化
|
||||||
|
+ 默认构造
|
||||||
|
+ 初始化列表
|
||||||
|
+ 拷贝构造
|
||||||
|
+ 自定义比较规则
|
||||||
|
```
|
||||||
|
struct Compare {
|
||||||
|
bool operator()(int a, int b) const {
|
||||||
|
return a > b; // 降序排序
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
3. 常用操作
|
||||||
|
+ 插入元素 `s1.insert(5);`
|
||||||
|
+ 删除元素 `s1.erase(3); // 删除值为 3 的元素`
|
||||||
|
+ 查找元素 `s1.find(4); // 返回指向元素的迭代器,未找到时返回 s1.end()`
|
||||||
|
+ 统计元素 `int count = s1.count(4);`
|
||||||
|
+ 范围查询
|
||||||
|
```
|
||||||
|
auto lower = s1.lower_bound(3); // 返回第一个 >= 3 的元素的迭代器
|
||||||
|
auto upper = s1.upper_bound(5); // 返回第一个 > 5 的元素的迭代器
|
||||||
|
```
|
||||||
|
|
||||||
|
4. 高级用法
|
||||||
|
+ 自定义排序规则:使用仿函数或 `std::greater` 可以改变排序规则
|
||||||
|
+ 存储复杂数据类型:可以存储 `std::pair` 或自定义结构体,通过自定义比较函数排序
|
||||||
|
+ 范围删除 `s1.erase(s1.lower_bound(10), s1.upper_bound(50)); // 删除值在 [10, 50) 范围内的所有元素`
|
||||||
|
|
||||||
|
__注意事项__
|
||||||
|
> 修改元素:无法直接修改容器中的元素值,需要先删除再插入
|
||||||
|
> 性能开销:由于自动排序的特性,插入和删除操作比无序容器慢
|
||||||
|
> 迭代器失效:插入操作不会使迭代器失效,但删除操作会使指向被删除元素的迭代器失效
|
||||||
|
|
||||||
|
### map
|
||||||
|
用于存储键值对(key-value pairs),并根据键自动排序
|
||||||
|
|
||||||
|
1. 特点
|
||||||
|
+ 键的唯一性:每个键在 map 中是唯一的,不允许重复
|
||||||
|
+ 自动排序:容器会根据键的默认比较规则(通常是 < 运算符)自动排序
|
||||||
|
+ 高效操作:插入、删除和查找操作的时间复杂度均为 O(log n),其中 n 是容器中元素的数量
|
||||||
|
|
||||||
|
2. 常用操作
|
||||||
|
+ 插入元素:`map1.insert({4, "four"});`或`map1[5] = "five"; // 如果键不存在,则插入新键值对;如果键存在,则更新值`
|
||||||
|
+ 查找元素:`map1.find(3);` 或者使用 `operator[]` 直接访问键对应的值
|
||||||
|
+ 删除元素:`map1.erase(3); // 删除键为 3 的元素。`
|
||||||
|
|
||||||
|
## 无序容器
|
||||||
|
|
||||||
|
存储元素时不排序,基于哈希表实现
|
||||||
|
|
||||||
|
## 预定义函数符
|
||||||
|
|
||||||
|
+ `+` plus
|
||||||
|
+ `-` minus
|
||||||
|
+ `*` multiplies
|
||||||
|
+ `/` divides
|
||||||
|
+ `%` modulus
|
||||||
|
|
||||||
|
+ `==` `equal_to`
|
||||||
|
+ `!=` `not_equal_to`
|
||||||
|
+ `>` `greater`
|
||||||
|
+ `<` `less`
|
||||||
|
+ `>=` `greater_equal`
|
||||||
|
+ `<=` `less_equal`
|
||||||
|
+ `&&` `logical_and`
|
||||||
|
+ `||` `logical_or`
|
||||||
|
+ `!` `logical_not`
|
@ -87,5 +87,5 @@
|
|||||||
|
|
||||||
## 神奇转换函数
|
## 神奇转换函数
|
||||||
```cpp
|
```cpp
|
||||||
string to_ strinf(任何类型); //将好多类型转换成string
|
string to_strinf(任何类型); //将好多类型转换成string
|
||||||
```
|
```
|
2
program/c_cpp/library/offsetof.h
Normal file
2
program/c_cpp/library/offsetof.h
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#define offsetof(type, struct_name) (size_t)&(((struct type*)0)->struct_name)
|
||||||
|
// 计算结构体成员相对结构体首地址的偏移度
|
10
program/c_cpp/library/string_hash.c
Normal file
10
program/c_cpp/library/string_hash.c
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// 非加密型hash,速度极快,支持种子
|
||||||
|
uint32_t murmur3_32(const char *key, size_t len, uint32_t seed) {
|
||||||
|
for(uint32_t i=0; i<len; i++)
|
||||||
|
{
|
||||||
|
seed ^= (const uint8_t)key[i];
|
||||||
|
seed *= 0x5bd1e995;
|
||||||
|
seed ^= seed>> 15;
|
||||||
|
}
|
||||||
|
return seed;
|
||||||
|
}
|
73
program/c_cpp/library/thread-pool.cpp
Normal file
73
program/c_cpp/library/thread-pool.cpp
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
#include <queue>
|
||||||
|
#include <functional>
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
|
class ThreadPool {
|
||||||
|
public:
|
||||||
|
ThreadPool(size_t num_threads);
|
||||||
|
~ThreadPool();
|
||||||
|
void enqueue(std::function<void()> task);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::thread> workers;
|
||||||
|
std::queue<std::function<void()>> tasks;
|
||||||
|
std::mutex queue_mutex;
|
||||||
|
std::condition_variable condition;
|
||||||
|
bool stop;
|
||||||
|
};
|
||||||
|
|
||||||
|
ThreadPool::ThreadPool(size_t num_threads) : stop(false) {
|
||||||
|
for (size_t i = 0; i < num_threads; ++i) {
|
||||||
|
workers.emplace_back([this] {
|
||||||
|
while (true) {
|
||||||
|
std::function<void()> task;
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(this->queue_mutex);
|
||||||
|
this->condition.wait(lock, [this] { return this->stop || !this->tasks.empty(); });
|
||||||
|
if (this->stop && this->tasks.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
task = std::move(this->tasks.front());
|
||||||
|
this->tasks.pop();
|
||||||
|
}
|
||||||
|
task();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ThreadPool::~ThreadPool() {
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(queue_mutex);
|
||||||
|
stop = true;
|
||||||
|
}
|
||||||
|
condition.notify_all();
|
||||||
|
for (std::thread& worker : workers) {
|
||||||
|
worker.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadPool::enqueue(std::function<void()> task) {
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(queue_mutex);
|
||||||
|
if (stop) {
|
||||||
|
throw std::runtime_error("enqueue on stopped ThreadPool");
|
||||||
|
}
|
||||||
|
tasks.emplace(task);
|
||||||
|
}
|
||||||
|
condition.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
ThreadPool pool(4);
|
||||||
|
for (int i = 0; i < 8; ++i) {
|
||||||
|
pool.enqueue([i] {
|
||||||
|
std::cout << "Task " << i << " is running on thread " << std::this_thread::get_id() << '\n';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
24
program/c_cpp/linux/ncurses.c
Normal file
24
program/c_cpp/linux/ncurses.c
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <ncurses.h>
|
||||||
|
|
||||||
|
char fastRead();
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
char ch;
|
||||||
|
printf("Please down any key\n");
|
||||||
|
ch = fastRead();
|
||||||
|
printf("down : %c --- %d\n", ch, (int)ch);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
char fastRead() {
|
||||||
|
char ch;
|
||||||
|
filter(); // 阻止initscr 清空屏幕
|
||||||
|
initscr(); // 初始化
|
||||||
|
cbreak(); // 禁用缓冲区
|
||||||
|
noecho(); // 禁用回显
|
||||||
|
keypad(stdscr, TRUE);
|
||||||
|
ch = getchar();
|
||||||
|
refresh(); // 刷新
|
||||||
|
endwin(); // 关闭
|
||||||
|
return ch;
|
||||||
|
}
|
25
program/c_cpp/linux/random.md
Normal file
25
program/c_cpp/linux/random.md
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# linux随机数设备
|
||||||
|
从系统熵池进行获取
|
||||||
|
|
||||||
|
## index
|
||||||
|
- [random-urandom](# random-urandom)
|
||||||
|
- [note](# note)
|
||||||
|
|
||||||
|
## random-urandom
|
||||||
|
/dev/random 和 /dev/urandom 的区别
|
||||||
|
+ /dev/random:
|
||||||
|
- 阻塞型设备,当熵池耗尽时会阻塞,直到收集到足够的熵
|
||||||
|
- 适合生成高价值的密钥、证书等
|
||||||
|
- 可能会影响性能,因为可能需要等待
|
||||||
|
|
||||||
|
+ /dev/urandom:
|
||||||
|
- 非阻塞型设备,即使熵池耗尽也会继续提供数据
|
||||||
|
- 使用加密算法从初始熵生成伪随机数
|
||||||
|
- 对于大多数应用来说已经足够安全
|
||||||
|
- 推荐在大多数情况下使用
|
||||||
|
|
||||||
|
## note
|
||||||
|
- 对于大多数应用,使用 /dev/urandom 就足够了,它不会阻塞且性能更好
|
||||||
|
- 只在生成长期加密密钥等极高安全需求时使用 /dev/random
|
||||||
|
- 不要频繁打开和关闭设备文件,可以保持打开状态或重用文件描述符
|
||||||
|
- 检查所有系统调用的返回值,确保操作成功
|
@ -1,19 +1,45 @@
|
|||||||
# 对象和类
|
# 对象和类
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
- [访问控制](#访问控制)
|
||||||
|
- [作用域运算符](#作用域运算符)
|
||||||
|
- [类的六大特殊成员函数](#类的六大特殊成员函数)
|
||||||
|
- [RAII](#RAII)
|
||||||
|
- [move语义](#move)
|
||||||
|
- [右值引用](#右值引用)
|
||||||
|
- [初始化列表](#初始化列表)
|
||||||
|
- [const 成员函数](#const成员函数)
|
||||||
|
- [this指针](#this指针)
|
||||||
|
- [作用域为类的常量](#作用域为类的常量)
|
||||||
|
- [作用域内枚举](#作用域内枚举)
|
||||||
|
- [友元](#友元)
|
||||||
|
- [类的自动转换和强制类型转换](#类的自动转换和强制类型转换)
|
||||||
|
- [转换函数](#转换函数)
|
||||||
|
- [继承](#继承)
|
||||||
|
- [继承方式](#继承方式)
|
||||||
|
- [虚函数](#virtual)
|
||||||
|
- [设计理念](#)
|
||||||
|
- [is a](#)
|
||||||
|
- [AbstactBaseClass](#ABC)
|
||||||
|
|
||||||
## 访问控制
|
## 访问控制
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
class demo {
|
class demo {
|
||||||
public: // 公有接口
|
public : // 公有接口
|
||||||
private: // 私有成员
|
private: // 私有成员
|
||||||
protected: // 保护
|
protected: // 保护,对外部是私有
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
## 作用域运算符(::)
|
## 作用域运算符(::)
|
||||||
|
|
||||||
可用于在类体外指出函数所属的类(命名空间)
|
可用于在类体外指出函数所属的类(命名空间)
|
||||||
|
|
||||||
## 成员函数的参数名不可与类成员相同
|
**成员函数的参数名不可与类成员相同**
|
||||||
|
|
||||||
## 类的六大特殊成员函数(未定义时编译器提供默认版本)
|
## 类的六大特殊成员函数(未定义时编译器提供默认版本)
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
demo::demo(); // 默认构造函数
|
demo::demo(); // 默认构造函数
|
||||||
demo::~demo(); // 默认析构函数
|
demo::~demo(); // 默认析构函数
|
||||||
@ -23,7 +49,57 @@ demo::demo(demo&&); // 移动复制构造函数
|
|||||||
demo& demo::operator = (demo&&); // 移动赋值构造函数
|
demo& demo::operator = (demo&&); // 移动赋值构造函数
|
||||||
```
|
```
|
||||||
|
|
||||||
## const 成员函数 适合的成员函数要尽可能用,以帮助规避错误
|
`demo::demo() = default;`显式声明为默认
|
||||||
|
`demo::demo() = delete;`显式声明为禁用
|
||||||
|
|
||||||
|
|
||||||
|
### RAII
|
||||||
|
|
||||||
|
在类的构造函数中申请堆内存,在析构函数中释放,这样可以保证类失效时内存被释放
|
||||||
|
|
||||||
|
### move
|
||||||
|
|
||||||
|
移动语义的核心思想是转移而非复制。当一个对象被移动时,其资源(如动态分配的内存、文件句柄等)被转移到目标对象,而源对象被置于一种有效但未定义的状态。这种状态通常是清空的,以确保源对象的资源在其生命周期内不会被重复释放
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
MyString(MyString&& other) noexcept : data(other.data) { // 移动构造函数
|
||||||
|
other.data = nullptr;
|
||||||
|
}
|
||||||
|
MyString& operator=(MyString&& other) noexcept { // 移动赋值运算符
|
||||||
|
if (this != &other) {
|
||||||
|
delete[] data; // 释放当前对象的资源
|
||||||
|
data = other.data;
|
||||||
|
other.data = nullptr;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`std::move` 是一个函数模板,用于将左值强制转换为右值。它本身并不执行移动操作,而是通过返回一个右值引用,触发移动构造函数或移动赋值运算符
|
||||||
|
|
||||||
|
`MyString str2 = std::move(str1); // 触发移动构造函数`
|
||||||
|
|
||||||
|
#### 右值引用
|
||||||
|
分为两类
|
||||||
|
> 普通右值引用:直接声明的T&&,用于移动语义
|
||||||
|
> 转发引用:模板函数中声明的T&&,用于完美转发
|
||||||
|
|
||||||
|
- [函数引用重载](./func#重载)
|
||||||
|
|
||||||
|
### 初始化列表
|
||||||
|
|
||||||
|
初始化列表是一种在构造函数中初始化类成员变量的机制
|
||||||
|
|
||||||
|
1. 初始化常量成员变量:常量成员变量必须在构造函数的初始化列表中初始化,不能在构造函数体内赋值。
|
||||||
|
2. 初始化引用成员变量:引用成员变量必须在构造函数的初始化列表中初始化,不能在构造函数体内赋值。
|
||||||
|
3. 调用基类的构造函数:如果类继承自基类,需要在初始化列表中显式调用基类的构造函数。
|
||||||
|
4. 优化性能:对于一些复杂的成员变量(如类对象),使用初始化列表可以避免默认构造后再赋值,从而提高效率。
|
||||||
|
|
||||||
|
> example
|
||||||
|
`MyClass(int a, int b, int c) : Base(a), myConst(b), myRef(c), myValue(10) {}`
|
||||||
|
|
||||||
|
## const成员函数 适合的成员函数要尽可能用,以帮助规避错误
|
||||||
|
|
||||||
`void show() const;` 声明
|
`void show() const;` 声明
|
||||||
`void demo::show() const;` 定义
|
`void demo::show() const;` 定义
|
||||||
表明函数不会修改调用对象
|
表明函数不会修改调用对象
|
||||||
@ -70,3 +146,57 @@ operator typeName();
|
|||||||
+ 必须是类成员
|
+ 必须是类成员
|
||||||
+ 不能有参数
|
+ 不能有参数
|
||||||
+ 不能指定返回类型
|
+ 不能指定返回类型
|
||||||
|
|
||||||
|
## 继承
|
||||||
|
|
||||||
|
基类对象需要在进入派生类的构造函数之前被创建,通常使用初始化列表解决
|
||||||
|
`demo::demo() : base();`
|
||||||
|
### 继承方式
|
||||||
|
1. public
|
||||||
|
+ 基类的公有成员在派生类中仍然是公有的。
|
||||||
|
+ 基类的保护成员在派生类中仍然是保护的。
|
||||||
|
+ 基类的私有成员在派生类中不可访问。
|
||||||
|
+ 派生类*对象*可以访问基类的公有成员。
|
||||||
|
+ 派生类*对象*不能直接访问基类的*私有成员*
|
||||||
|
|
||||||
|
2. protected
|
||||||
|
+ 基类的公有成员和保护成员在派生类中都变成保护的。
|
||||||
|
+ 基类的私有成员在派生类中仍然不可访问。
|
||||||
|
+ 派生类*对象*不能直接访问基类的*所有成员*
|
||||||
|
|
||||||
|
3. private
|
||||||
|
+ 基类所有成员变成私有
|
||||||
|
+ 派生类*对象*不能直接访问基类的*所有成员*
|
||||||
|
|
||||||
|
__保护成员在派生类中的访问性__
|
||||||
|
无论继承方式,派生类都可以访问基类的 `protected` 这是因为保护成员的设计初衷就是允许派生类访问,但不允许*派生类的对象*访问
|
||||||
|
|
||||||
|
### virtual
|
||||||
|
虚函数是通过在基类中使用关键字 virtual 声明的成员函数
|
||||||
|
|
||||||
|
虚函数的主要作用是实现动态绑定或运行时多态.当通过基类指针或引用调用虚函数时,程序会根据对象的实际类型(运行时类型)来调用相应的函数版本
|
||||||
|
|
||||||
|
为了实现动态绑定,C++ 编译器会在每个具有虚函数的类的对象中隐式添加一个指针,指向一个虚函数表(V-Table)。V-Table 是一个函数指针数组,存储了类中所有虚函数的地址。当通过指针或引用调用虚函数时,程序会通过 V-Table 查找并调用正确的函数版本
|
||||||
|
|
||||||
|
**虚函数的特点**
|
||||||
|
+ 必须是成员函数
|
||||||
|
+ 派生类继承基类的虚函数,但可以重写它
|
||||||
|
+ 覆盖:派生类中的虚函数与基类中的虚函数具有相同的签名
|
||||||
|
+ 多态:通过基类指针或引用调用虚函数时,会根据对象的实际类型调用相应的函数版本
|
||||||
|
|
||||||
|
**纯虚函数与抽象类**
|
||||||
|
如果一个虚函数在基类中没有实现,而是通过在函数声明后加上 = 0 来表示,那么这个函数称为纯虚函数。包含纯虚函数的类称为抽象类
|
||||||
|
|
||||||
|
`virtual void display() = 0; // 纯虚函数`
|
||||||
|
|
||||||
|
## 设计理念
|
||||||
|
|
||||||
|
### is-a
|
||||||
|
### ABC
|
||||||
|
即使用[纯虚函数](#virtual)构造的抽象类
|
||||||
|
|
||||||
|
无法构建对象,只能用于构造其他派生类
|
||||||
|
|
||||||
|
用于提取一系列对象的共性以共用
|
||||||
|
|
||||||
|
即抽象类设计理念,把一系列对象的共性提取出来,创建一个*抽象*的类
|
||||||
|
42
program/c_cpp/universal/compile.md
Normal file
42
program/c_cpp/universal/compile.md
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# 预编译指令
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
- [define](#define)
|
||||||
|
- [预定义宏](#预定义宏)
|
||||||
|
- [ifdef](#ifdef)
|
||||||
|
- [ifndef](#ifndef)
|
||||||
|
- [endif](#endif)
|
||||||
|
- [pragma](#pragma)
|
||||||
|
- [error](#error)
|
||||||
|
- [warning](#warning)
|
||||||
|
|
||||||
|
## define
|
||||||
|
### 预定义宏
|
||||||
|
1. 平台相关
|
||||||
|
+ `__STDC__` 如果编译器遵循ANSI C标准,则定义为1
|
||||||
|
+ `__cplusplus` 如果编译器支持C++,则定义为一个版本号 如199711L表示C++98,201103L表示C++11等
|
||||||
|
+ `_WIN32` 在Windows平台下定义,表示目标系统是32位或64位
|
||||||
|
+ `_WIN64`
|
||||||
|
+ `__unix__`
|
||||||
|
+ `__linux__`
|
||||||
|
+ `__APPLE__`
|
||||||
|
|
||||||
|
2. 编译器相关
|
||||||
|
+ `__GNUC__` 如果编译器是GCC,则定义为GCC的主版本号
|
||||||
|
+ `__clang__` 如果编译器是Clang
|
||||||
|
+ `_MSC_VER` 如果编译器是Microsoft Visual C++,则定义为一个版本号
|
||||||
|
+ `__ICC` 如果编译器是Intel C/C++ Compiler,则定义
|
||||||
|
|
||||||
|
3. 文件和行号相关的预定义宏
|
||||||
|
+ `__FILE__` 当前文件的名称
|
||||||
|
+ `__LINE__` 当前文件的行号
|
||||||
|
+ `__DATE__` 编译日期
|
||||||
|
+ `__TIME__` 编译时间
|
||||||
|
|
||||||
|
4. 其他
|
||||||
|
+ `__func__` `__FUNCTION__` 当前函数的名称
|
||||||
|
+ `__PRETTY_FUNCTION__` 在C++中,包含当前函数的完整声明
|
||||||
|
|
||||||
|
## pragma
|
||||||
|
|
||||||
|
`#pragma once` 确保头文件只被包含一次
|
47
program/c_cpp/universal/func.md
Normal file
47
program/c_cpp/universal/func.md
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
# c-cpp function
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
- [extern](#extern)
|
||||||
|
- [noexcept](#noexcept)
|
||||||
|
- [重载](#)
|
||||||
|
- [often](#often)
|
||||||
|
|
||||||
|
## extern
|
||||||
|
|
||||||
|
`exterm` 表明函数在外部定义,在链接期才去查找
|
||||||
|
`extern "C"` 表明以C的方式查找外部函数
|
||||||
|
|
||||||
|
## noexcept
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void myFunction() noexcept {
|
||||||
|
// 这个函数不会抛出异常
|
||||||
|
}
|
||||||
|
```
|
||||||
|
noexcept 的一个重要用途是优化性能,特别是在移动语义中。当一个函数被标记为 noexcept 时,编译器可以更积极地优化代码
|
||||||
|
|
||||||
|
## 重载
|
||||||
|
只要特征标不同就可以重载
|
||||||
|
**特征标**:原型除去返回值都是
|
||||||
|
|
||||||
|
+ 左值:优先选择T&,如果不可用则选择const T&。
|
||||||
|
+ const左值:选择const T&。
|
||||||
|
+ 右值:优先选择T&&, else const T&
|
||||||
|
+ 字面量或临时对象:选择T&&。
|
||||||
|
|
||||||
|
## often
|
||||||
|
|
||||||
|
```
|
||||||
|
abs(x); //求x的绝对值 e.g.abs(-5)=5
|
||||||
|
fabs() //实数绝对值
|
||||||
|
exp(x); //求x的自然指数e^x e.g.exp(1)=2.718282
|
||||||
|
floor(x); //向下取整
|
||||||
|
ceil(x); //向上取整
|
||||||
|
log(x); //求实数x的自然数对数 e.g.log(1)=0
|
||||||
|
pow(x,y); //计算x^y,输出为双精度实数 e.g.pow(2,3)=8
|
||||||
|
sqrt(x); //求x的平方根 e.g.sqrt(25)=5
|
||||||
|
strlen(str);获取字符数组长度(只能用在字符数组)。
|
||||||
|
max(a,b) //两数中最大
|
||||||
|
min(a,b) //两数中最小
|
||||||
|
swap(a,b) //交换两个类型相同的变量
|
||||||
|
```
|
@ -6,6 +6,7 @@
|
|||||||
- [c fio](# c fio)
|
- [c fio](# c fio)
|
||||||
- [cpp stdio](# cpp stdio)
|
- [cpp stdio](# cpp stdio)
|
||||||
- [cpp fio](# cpp fio)
|
- [cpp fio](# cpp fio)
|
||||||
|
- [关闭缓冲区读取](# ../linux/ncurses.c)
|
||||||
|
|
||||||
|
|
||||||
## c stdio
|
## c stdio
|
||||||
|
156
program/c_cpp/universal/ptr.md
Normal file
156
program/c_cpp/universal/ptr.md
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
# c-cpp的指针问题
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
- [NULL and nullptr](#NULL-nullptr)
|
||||||
|
- [cpp智能指针](#cpp智能指针)
|
||||||
|
- [注意事项](#注意事项)
|
||||||
|
- [some example](#some-example)
|
||||||
|
|
||||||
|
## NULL-nullptr
|
||||||
|
|
||||||
|
在C和CPP中,NULL并不相同
|
||||||
|
|
||||||
|
```
|
||||||
|
#ifndef NULL
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define NULL 0
|
||||||
|
#else
|
||||||
|
#define NULL ((void *)0)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
```
|
||||||
|
|
||||||
|
由源码可知, C中 `NULL` 为 `(void *)0`, 而cpp中视为整形常量
|
||||||
|
|
||||||
|
因此cpp中应使用nullptr,否则函数重载中会出现选择错误问题
|
||||||
|
|
||||||
|
## cpp智能指针
|
||||||
|
|
||||||
|
1. `std::unique_ptr`
|
||||||
|
|
||||||
|
表示独占所有权的指针,即同一时刻只能有一个`unique_ptr`指向某个对象。
|
||||||
|
|
||||||
|
* 不可复制(没有拷贝构造函数和拷贝赋值运算符)。
|
||||||
|
* 可以移动(支持移动语义)。
|
||||||
|
* 自动释放资源。
|
||||||
|
|
||||||
|
**由于不可复制,不能将unique_ptr存储在标准容器中(如std::vector)**
|
||||||
|
|
||||||
|
```
|
||||||
|
std::unique_ptr<MyClass> ptr1 = std::make_unique<MyClass>(42); // 创建unique_ptr
|
||||||
|
std::unique_ptr<MyClass> ptr2 = std::move(ptr1); // 移动所有权
|
||||||
|
ptr1 = nullptr; // ptr1不再指向对象,对象由ptr2管理
|
||||||
|
```
|
||||||
|
|
||||||
|
2. `std::shared_ptr`
|
||||||
|
|
||||||
|
表示共享所有权的指针,多个`shared_ptr`可以指向同一个对象
|
||||||
|
|
||||||
|
* 使用引用计数来管理对象的生命周期。
|
||||||
|
* 当最后一个`shared_ptr`被销毁时,对象才会被释放。
|
||||||
|
* 可以复制
|
||||||
|
* 引用计数可能会引入性能开销,尤其是在多线程环境中。
|
||||||
|
* 如果存在循环引用(如双向链表),可能导致内存泄漏。需要使用`std::weak_ptr`来解决。
|
||||||
|
|
||||||
|
```
|
||||||
|
std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>(42);
|
||||||
|
std::shared_ptr<MyClass> ptr2 = ptr1; // 复制,引用计数加1
|
||||||
|
std::cout << "ptr1 use count: " << ptr1.use_count() << std::endl; // 输出2
|
||||||
|
```
|
||||||
|
|
||||||
|
3. `std::weak_ptr`
|
||||||
|
|
||||||
|
解决`shared_ptr`的循环引用问题
|
||||||
|
|
||||||
|
* 不增加引用计数。
|
||||||
|
* 可以通过lock()方法获取一个`shared_ptr`,但需要检查对象是否仍然存在
|
||||||
|
* `weak_ptr`不能直接访问对象,需要通过lock()方法转换为`shared_ptr`。
|
||||||
|
* 如果对象已经被销毁,lock()会返回一个空的`shared_ptr`
|
||||||
|
|
||||||
|
### 注意事项
|
||||||
|
|
||||||
|
***循环引用问题***
|
||||||
|
|
||||||
|
`std::shared_ptr`通过引用计数来管理对象的生命周期。当最后一个`shared_ptr`被销毁时,引用计数归零,对象才会被释放。然而,如果两个或多个`shared_ptr`相互引用,引用计数将永远不会归零,因为它们相互持有对方的引用。
|
||||||
|
|
||||||
|
> example:双向链表中的循环引用
|
||||||
|
```
|
||||||
|
struct Node {
|
||||||
|
std::shared_ptr<Node> next; // 指向下一个节点
|
||||||
|
std::shared_ptr<Node> prev; // 指向前一个节点
|
||||||
|
};
|
||||||
|
auto node1 = std::make_shared<Node>();
|
||||||
|
auto node2 = std::make_shared<Node>();
|
||||||
|
node1->next = node2; // node1 持有 node2 的共享所有权
|
||||||
|
node2->prev = node1; // node2 持有 node1 的共享所有权
|
||||||
|
```
|
||||||
|
|
||||||
|
为了解决循环引用问题,C++标准库提供了`std::weak_ptr`。`std::weak_ptr`是一种弱引用,它不会增加引用计数,但可以指向一个由`std::shared_ptr`管理的对象
|
||||||
|
|
||||||
|
```
|
||||||
|
struct Node {
|
||||||
|
std::shared_ptr<Node> next; // 指向下一个节点
|
||||||
|
std::weak_ptr<Node> prev; // 使用 weak_ptr 指向前一个节点
|
||||||
|
};
|
||||||
|
auto node1 = std::make_shared<Node>();
|
||||||
|
auto node2 = std::make_shared<Node>();
|
||||||
|
node1->next = node2; // node1 持有 node2 的共享所有权
|
||||||
|
node2->prev = node1; // node2 使用 weak_ptr 指向 node1
|
||||||
|
```
|
||||||
|
|
||||||
|
如果对象仍然存在,lock()返回一个指向对象的`std::shared_ptr` 如果对象已经被销毁,lock()返回一个空的`std::shared_ptr`
|
||||||
|
|
||||||
|
|
||||||
|
__正确选择智能指针类型__
|
||||||
|
|
||||||
|
> 如果对象的所有权是唯一的,使用`std::unique_ptr`
|
||||||
|
> 如果对象的所有权需要共享,使用`std::shared_ptr`
|
||||||
|
> 如果需要解决循环引用问题,使用`std::weak_ptr`
|
||||||
|
|
||||||
|
### some-example
|
||||||
|
|
||||||
|
```
|
||||||
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
#include <algorithm> // 用于 std::fill
|
||||||
|
int main() {
|
||||||
|
// 使用 std::unique_ptr 管理1000个 int 的内存空间
|
||||||
|
std::unique_ptr<int[]> data = std::make_unique<int[]>(1000);
|
||||||
|
|
||||||
|
// 初始化数据
|
||||||
|
std::fill(data.get(), data.get() + 1000, 42); // 将所有元素初始化为42
|
||||||
|
// data.get()返回底层指针,可以用于标准库算法(如std::fill)
|
||||||
|
|
||||||
|
// 访问并打印部分数据
|
||||||
|
for (int i = 0; i < 10; ++i) {
|
||||||
|
std::cout << data[i] << " ";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
// 当 unique_ptr 超出作用域时,内存会自动释放
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
```
|
||||||
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
#include <algorithm> // 用于 std::fill
|
||||||
|
int main() {
|
||||||
|
// 使用 std::shared_ptr 管理1000个 int 的内存空间
|
||||||
|
std::shared_ptr<int[]> data(new int[1000]); // 使用 new[] 分配内存
|
||||||
|
// ***std::shared_ptr<int[]>需要显式使用new[]分配内存***
|
||||||
|
|
||||||
|
// 初始化数据
|
||||||
|
std::fill(data.get(), data.get() + 1000, 42); // 将所有元素初始化为42
|
||||||
|
|
||||||
|
// 访问并打印部分数据
|
||||||
|
for (int i = 0; i < 10; ++i) {
|
||||||
|
std::cout << data[i] << " ";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
// 当最后一个 shared_ptr 超出作用域时,内存会自动释放
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
@ -1,12 +1,13 @@
|
|||||||
# 存储说明符
|
# 说明符
|
||||||
+ static
|
|
||||||
+ extern
|
|
||||||
+ mutable
|
|
||||||
+ thread_local
|
|
||||||
|
|
||||||
# cv 说明符
|
## 目录
|
||||||
+ const
|
- [static](#static)
|
||||||
+ volatile
|
- [extern](#extern):引用声明
|
||||||
|
- [mutable](#mutable)
|
||||||
|
- [thread local](#`thread_local`)
|
||||||
|
- [const](#const)
|
||||||
|
- [volatile](#volatile):强制读内存
|
||||||
|
- [restrict](#restrict) : 指示编译器优化指针(C99)
|
||||||
|
|
||||||
|
|
||||||
## static
|
## static
|
||||||
@ -18,7 +19,7 @@
|
|||||||
|
|
||||||
## extern
|
## extern
|
||||||
引用声明
|
引用声明
|
||||||
声明引用在其他地方定义的变量
|
声明引用在其他地方定义的变量或者函数
|
||||||
|
|
||||||
## mutable
|
## mutable
|
||||||
即使结构(类)被声明为const,也可以被修改的成员函数
|
即使结构(类)被声明为const,也可以被修改的成员函数
|
||||||
@ -36,4 +37,15 @@
|
|||||||
就像使用了static
|
就像使用了static
|
||||||
如果希望连接性为外部,则可以用extern覆盖
|
如果希望连接性为外部,则可以用extern覆盖
|
||||||
|
|
||||||
## volatile 强制读内存
|
## restrict
|
||||||
|
- 在没有 restrict 的情况下,编译器需要考虑指针之间可能存在的别名关系。编译器会频繁地从内存中读取数据,以确保每次使用指针时数据是最新的。这会导致不必要的内存访问
|
||||||
|
- 使用 restrict 后,编译器可以假设带有 restrict 的指针是唯一的,不会与其他指针指向同一块内存。因此,编译器可以减少不必要的内存访问
|
||||||
|
|
||||||
|
```c
|
||||||
|
void copy(int *restrict dest, int *restrict src, int n) {
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
dest[i] = src[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
__如果违反了 restrict 的约束(即多个 restrict 指针指向同一块内存),程序的行为是未定义的__
|
||||||
|
@ -1,35 +1,33 @@
|
|||||||
# 模板
|
# 模板
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
- [函数模板](#)
|
||||||
|
- [生成](#)
|
||||||
|
- [类模板](#)
|
||||||
|
- [完美转发](#)
|
||||||
|
- [可变参数](#可变参数)
|
||||||
|
|
||||||
## 函数模板
|
## 函数模板
|
||||||
|
|
||||||
### 基本格式
|
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void swap(T &a, T &b) {
|
void swap(T &a, T &b);
|
||||||
T temp;
|
|
||||||
temp = b;
|
|
||||||
b = a;
|
|
||||||
a = temp;
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
__函数模板必须放在头文件里,因为它不是函数实体,只能算编译指令__
|
__函数模板必须放在编译器可见的地方里,因为不是函数实体,只能算编译指令__
|
||||||
|
|
||||||
### 模板的几个术语
|
### 生成
|
||||||
+ **隐式实例化**
|
**隐式实例化**
|
||||||
```cpp
|
```cpp
|
||||||
int a=0, b=3;
|
int a=0, b=3;
|
||||||
swap<int>(a, b);
|
swap<int>(a, b);
|
||||||
```
|
```
|
||||||
+ **显式实例化**
|
**显式实例化**
|
||||||
```cpp
|
```cpp
|
||||||
template void swap<int>(int&, int&); // 使用模板生成int类型的函数定义
|
template void swap<int>(int&, int&); // 使用模板生成int类型的函数定义
|
||||||
```
|
```
|
||||||
+ **显式具体化**
|
**显式具体化** 这个可以放到其他文件里,因为是有实体的
|
||||||
```cpp
|
```cpp
|
||||||
template <> void swap<int>(int&, int&);
|
template <> void swap<int>(int&, int&);
|
||||||
```
|
```
|
||||||
__这个可以放到其他文件里,因为是有实体的__
|
|
||||||
|
|
||||||
### 类型推导
|
### 类型推导
|
||||||
+ decltype()
|
+ decltype()
|
||||||
@ -39,5 +37,29 @@ decltype(a) var;
|
|||||||
```
|
```
|
||||||
|
|
||||||
## 类模板
|
## 类模板
|
||||||
|
同样没有实体,包括类成员方法等都要写成模板的格式
|
||||||
|
|
||||||
+ 同样没有实体,包括类成员方法等都要写成模板的格式
|
## 完美转发
|
||||||
|
- [右值引用](./class.md#):有关完美转发的基础
|
||||||
|
完美转发允许模板函数将参数原封不动地转发给另一个函数,保留其左值或右值的性质。这在编写通用代码时非常有用,例如模板库或函数包装器
|
||||||
|
|
||||||
|
完美转发的核心是std::forward,它根据模板参数T的类型(左值引用或右值引用)来决定如何转发参数
|
||||||
|
|
||||||
|
```
|
||||||
|
template <typename T>
|
||||||
|
void wrapper(T&& arg) {
|
||||||
|
// 转发 arg 到另一个函数,保留其左值或右值性质
|
||||||
|
targetFunction(std::forward<T>(arg));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 可变参数
|
||||||
|
|
||||||
|
```
|
||||||
|
void print() {} // 终止递归
|
||||||
|
template <typename T, typename... Types)
|
||||||
|
void print(const T& firstArg, const Types&... args) {
|
||||||
|
std::cout << firstArg << std::endl;
|
||||||
|
print(args...);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
void func(int a) {
|
|
||||||
cout << a << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex mtx; // 互斥量
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
|
|
||||||
// 同一个进程的多个线程共享该进程的全部系统资源
|
|
||||||
// 但各个线程有自己的调用栈,寄存器,本地存储
|
|
||||||
|
|
||||||
// thread类
|
|
||||||
// 1.
|
|
||||||
// thread() noexcept;默认构造函数,不执行任何任务
|
|
||||||
// 2.
|
|
||||||
// template<class Funtion, class ...Args>
|
|
||||||
// explicit thread(Function&& fx,Args&&... args);
|
|
||||||
|
|
||||||
thread t1(func, 1); //用2方法创建线程
|
|
||||||
|
|
||||||
// mtx.lock();
|
|
||||||
// mtx.unlock();
|
|
||||||
|
|
||||||
|
|
||||||
if(t1.joinable()) // 判断能否调用join
|
|
||||||
t1.join(); //回收线程t1
|
|
||||||
// t1.detach(); //分离线程
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 注:g++编译器要加 -pthread -std=c++11选项编译
|
|
130
program/c_cpp/universal/thread.md
Normal file
130
program/c_cpp/universal/thread.md
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
# cpp多线程
|
||||||
|
C++11引入了标准的线程库 `<thread>`,使得多线程编程更加方便和标准化
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
- [创建线程](#)
|
||||||
|
- [线程的分离和结合](#)
|
||||||
|
- [传递参数给线程函数](#)
|
||||||
|
- [线程的同步](#)
|
||||||
|
- [互斥锁](#mutex)
|
||||||
|
- [lock-guard](#)
|
||||||
|
- [条件变量](#)
|
||||||
|
- [原子操作](#atomic)
|
||||||
|
- [高级接口](#高级接口)
|
||||||
|
- [线程池](#)
|
||||||
|
|
||||||
|
## 创建线程
|
||||||
|
通过 `std::thread` 类来创建和管理线程
|
||||||
|
```
|
||||||
|
std::thread t(thread_function); // 创建线程并执行 thread_function
|
||||||
|
t.join(); // 等待线程结束
|
||||||
|
```
|
||||||
|
|
||||||
|
## 线程的分离和结合
|
||||||
|
+ `join()`:主线程等待子线程执行完毕。
|
||||||
|
+ `detach()`:将子线程与主线程分离,子线程在后台独立运行。
|
||||||
|
|
||||||
|
## 传递参数给线程函数
|
||||||
|
可以通过 `std::thread` 的构造函数传递参数给线程函数
|
||||||
|
|
||||||
|
`std::thread t(thread_function, 10, "Hello");`
|
||||||
|
|
||||||
|
## 线程的同步
|
||||||
|
多个线程访问共享资源时,可能会出现竞争条件(Race Condition)。为了避免这种情况,可以使用互斥锁(Mutex)来同步线程
|
||||||
|
|
||||||
|
### 互斥锁
|
||||||
|
`std::mutex` 用于保护共享资源,确保同一时间只有一个线程可以访问,`<mutex>`
|
||||||
|
|
||||||
|
```
|
||||||
|
std::mutex mtx; // 互斥量
|
||||||
|
void print_block() {
|
||||||
|
mtx.lock(); // 锁定互斥锁
|
||||||
|
// ...
|
||||||
|
mtx.unlock(); // 解锁互斥锁
|
||||||
|
}
|
||||||
|
// in main ->
|
||||||
|
std::thread t1(print_block, 50, '*');
|
||||||
|
std::thread t2(print_block, 50, '$');
|
||||||
|
t1.join();
|
||||||
|
t2.join();
|
||||||
|
```
|
||||||
|
|
||||||
|
### lock-guard
|
||||||
|
`std::lock_guard` 是一个 RAII 风格的互斥锁管理类,它在构造时锁定互斥锁,在析构时自动解锁0
|
||||||
|
|
||||||
|
```
|
||||||
|
std::mutex mtx;
|
||||||
|
std::lock_guard<std::mutex> lock(mtx);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 条件变量
|
||||||
|
条件变量用于线程间的同步,允许线程在某些条件不满足时等待,直到其他线程通知条件满足
|
||||||
|
|
||||||
|
`<condition_variable>`
|
||||||
|
```cpp
|
||||||
|
std::mutex mtx;
|
||||||
|
std::condition_variable cv;
|
||||||
|
bool ready = false;
|
||||||
|
void print_id(int id) {
|
||||||
|
std::unique_lock<std::mutex> lock(mtx);
|
||||||
|
while (!ready) {
|
||||||
|
cv.wait(lock); // 线程等待条件变量
|
||||||
|
}
|
||||||
|
std::cout << "thread " << id << '\n';
|
||||||
|
}
|
||||||
|
void go() {
|
||||||
|
std::unique_lock<std::mutex> lock(mtx);
|
||||||
|
ready = true;
|
||||||
|
cv.notify_all(); // 通知所有等待的线程
|
||||||
|
}
|
||||||
|
// main
|
||||||
|
std::thread threads[10];
|
||||||
|
for (int i = 0; i < 10; ++i) {
|
||||||
|
threads[i] = std::thread(print_id, i);
|
||||||
|
}
|
||||||
|
go();
|
||||||
|
for (auto& th : threads) {
|
||||||
|
th.join();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## atomic
|
||||||
|
`std::atomic` 提供了原子操作,确保对共享变量的操作是不可分割的
|
||||||
|
|
||||||
|
## 高级接口
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void wait_s(time_t sec) { // 延时函数
|
||||||
|
std::cout << "BEGIN" << std::endl;
|
||||||
|
time_t begin = time(0);
|
||||||
|
while((time(0) - begin) < sec);
|
||||||
|
}
|
||||||
|
int main() {
|
||||||
|
std::future<void> r1(std::async(wait_s, 10));
|
||||||
|
// async let `a piece of functionality` run in alone thread
|
||||||
|
|
||||||
|
wait_s(10);
|
||||||
|
r1.get(); // 获得返回值,确保必将被调用
|
||||||
|
|
||||||
|
std::cout << "END" << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 线程池
|
||||||
|
通过 `std::thread` 和任务队列来实现一个简单的[线程池](../library/thread-pool.cpp)
|
||||||
|
|
||||||
|
// thread类
|
||||||
|
// 1.
|
||||||
|
// thread() noexcept;默认构造函数,不执行任何任务
|
||||||
|
// 2.
|
||||||
|
// template<class Funtion, class ...Args>
|
||||||
|
// explicit thread(Function&& fx,Args&&... args);
|
||||||
|
|
||||||
|
if(t1.joinable()) // 判断能否调用join
|
||||||
|
t1.join(); //回收线程t1
|
||||||
|
// t1.detach(); //分离线程
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
__注:g++编译器要加 -pthread -std=c++11选项编译__
|
@ -1,34 +0,0 @@
|
|||||||
abs(x); //求x的绝对值 e.g.abs(-5)=5
|
|
||||||
fabs() //实数绝对值
|
|
||||||
a=clock();测量从程序开始到目前的时间,并把值给a。(单位毫秒级)
|
|
||||||
exp(x); //求x的自然指数e^x e.g.exp(1)=2.718282
|
|
||||||
floor(x); //向下取整
|
|
||||||
ceil(x); //向上取整
|
|
||||||
log(x); //求实数x的自然数对数 e.g.log(1)=0
|
|
||||||
pow(x,y); //计算x^y,输出为双精度实数 e.g.pow(2,3)=8
|
|
||||||
sqrt(x); //求x的平方根 e.g.sqrt(25)=5
|
|
||||||
str.length();获取字符串长度(只能用在字符串)string b="123456789";//字符串定义 初始化。
|
|
||||||
str.size();
|
|
||||||
strlen(str);获取字符数组长度(只能用在字符数组)。
|
|
||||||
abort() //终止程序运行 不能结束工作
|
|
||||||
exit() //终止程序运行 做结束工作
|
|
||||||
max(a,b) //两数中最大
|
|
||||||
min(a,b) //两数中最小
|
|
||||||
swap(a,b) //交换两个类型相同的变量
|
|
||||||
|
|
||||||
sort(数组名+起始单元,数组名+结束单元,排序方法cmp倒);
|
|
||||||
sort(a,a+n);//sort默认为升序
|
|
||||||
int cmp(int a,int b)
|
|
||||||
{
|
|
||||||
return a>b;
|
|
||||||
}
|
|
||||||
|
|
||||||
Sleep(s时间);//程序运行到此处时暂停s毫秒,注意大小写,需调用头文件#include<windows.h>
|
|
||||||
|
|
||||||
void color(const unsigned short textColor) //颜色字函数
|
|
||||||
{
|
|
||||||
if(textColor>=0&&textColor<=15)
|
|
||||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),textColor);
|
|
||||||
else
|
|
||||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),7);
|
|
||||||
}
|
|
@ -1,6 +1,7 @@
|
|||||||
a1 = int(input("input:")) # input
|
a1 = int(input("input:")) # input
|
||||||
|
a, b = map(int, input().split()) # 读取输入分割并转化
|
||||||
print('%8d'%a1, '\n') # print
|
print('%8d'%a1, '\n') # print
|
||||||
# print(objects, sep=' ', wnd='\n')
|
# print(objects, sep=' ', end='\n')
|
||||||
|
|
||||||
|
|
||||||
# 数据类型
|
# 数据类型
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
# 字符串
|
|
||||||
s = str("Hello world")
|
|
||||||
|
|
||||||
print(s[3])
|
|
||||||
print(s[-3])
|
|
||||||
print(s[0:3]) # 字符串切片
|
|
||||||
print(s[3:])
|
|
||||||
print(s[:5])
|
|
||||||
print(s[:-5])
|
|
||||||
print(s[::-1]) # 倒序
|
|
||||||
len(s) # 计算长度
|
|
||||||
|
|
||||||
# 字符串查询
|
|
||||||
s.find('w')
|
|
||||||
s.count('l')
|
|
||||||
|
|
||||||
s.replace('H','h') # H变成h
|
|
||||||
s.casefold() # 大写转小写
|
|
||||||
s.upper() # 小写转大写
|
|
||||||
s.swapcase() # 转换大小写
|
|
||||||
eval('12+3') # 计算值 返回15
|
|
||||||
|
|
||||||
|
|
97
program/python/basics/summary.md
Normal file
97
program/python/basics/summary.md
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
# python基础合集
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
- [程序之始](#run)
|
||||||
|
- [IO](#IO)
|
||||||
|
- [格式化输出](#)
|
||||||
|
- [字符串](#string)
|
||||||
|
- [DEBUG](#Debug)
|
||||||
|
- [变量](#)
|
||||||
|
- [数值类型](#)
|
||||||
|
|
||||||
|
## run
|
||||||
|
|
||||||
|
`if __name__ == '__main__'` 判断程序是否在主函数内(区别与模块等)
|
||||||
|
|
||||||
|
## IO
|
||||||
|
|
||||||
|
`print(values, sep, end)` 值, 分割符, 结尾符
|
||||||
|
> `print("hello", sep=',', end='_')`
|
||||||
|
> `print('%8d'%a1, '\n')`
|
||||||
|
|
||||||
|
a1 = int(input("input:")) # input
|
||||||
|
a, b = map(int, input().split()) # 读取输入分割并转化
|
||||||
|
|
||||||
|
### 格式化输出
|
||||||
|
1. 占位符
|
||||||
|
+ `%`
|
||||||
|
+ `format()`
|
||||||
|
+ `格式化f`
|
||||||
|
|
||||||
|
> example
|
||||||
|
`print("%4d" % a)`
|
||||||
|
|
||||||
|
|
||||||
|
## string
|
||||||
|
|
||||||
|
字符串可以用单引号或者双引号
|
||||||
|
|
||||||
|
三引号可以跨行
|
||||||
|
|
||||||
|
> example
|
||||||
|
```python
|
||||||
|
print('''Hello
|
||||||
|
world''')
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
s = str("Hello world")
|
||||||
|
print(s[3])
|
||||||
|
print(s[-3])
|
||||||
|
print(s[0:3]) # 字符串切片
|
||||||
|
print(s[3:])
|
||||||
|
print(s[:5])
|
||||||
|
print(s[:-5])
|
||||||
|
print(s[::-1]) # 倒序
|
||||||
|
len(s) # 计算长度
|
||||||
|
|
||||||
|
s.find('w')
|
||||||
|
s.count('l')
|
||||||
|
|
||||||
|
s.replace('H','h') # H变成h
|
||||||
|
s.casefold() # 大写转小写
|
||||||
|
s.upper() # 小写转大写
|
||||||
|
s.swapcase() # 转换大小写
|
||||||
|
eval('12+3') # 计算值 返回15
|
||||||
|
```
|
||||||
|
|
||||||
|
## Debug
|
||||||
|
|
||||||
|
1. pdb
|
||||||
|
`import pdb; pdb.set_trace()` 程序运行到这行代码时会进入调试模式
|
||||||
|
+ n(next):执行下一行代码。
|
||||||
|
+ c(continue):继续运行直到遇到下一个断点。
|
||||||
|
+ q(quit):退出调试。
|
||||||
|
+ p <变量>:打印变量的值。
|
||||||
|
+ l(list):显示当前代码上下文。
|
||||||
|
+ b <行号>:设置断点。
|
||||||
|
+ cl(clear):清除断点。
|
||||||
|
```
|
||||||
|
def add(a, b):
|
||||||
|
import pdb; pdb.set_trace() # 从这里进入断点调试
|
||||||
|
return a + b
|
||||||
|
print(add(3,5))
|
||||||
|
```
|
||||||
|
|
||||||
|
## 变量
|
||||||
|
name = value
|
||||||
|
|
||||||
|
### 数值类型
|
||||||
|
+ int
|
||||||
|
+ float
|
||||||
|
+ bool True = 1 False = 0
|
||||||
|
+ complex
|
||||||
|
+ [str](#string)
|
||||||
|
|
||||||
|
type()
|
@ -1,8 +1,39 @@
|
|||||||
安装docker
|
# docker
|
||||||
sudo apt-get install docker-compose
|
是一个开源的应用容器引擎
|
||||||
|
|
||||||
配置/etc/docker/daemon.json
|
## 目录
|
||||||
|
- [核心组件](#)
|
||||||
|
- [install](#)
|
||||||
|
- [基本命令](#)
|
||||||
|
- [样例](#example-command)
|
||||||
|
- [数据管理](#)
|
||||||
|
- [高级用法](#)
|
||||||
|
- [daemon.json](#)
|
||||||
|
|
||||||
|
## 核心组件
|
||||||
|
+ 镜像(Image):只读模板,包含运行应用所需的所有内容,如代码、运行时、库等
|
||||||
|
+ 容器(Container):镜像的运行实例,隔离运行应用的环境
|
||||||
|
+ 仓库(Repository):存储和分发镜像的地方,Docker Hub 是最常用的公共仓库
|
||||||
|
|
||||||
|
|
||||||
|
## install
|
||||||
|
+ 更新系统并安装依赖包
|
||||||
|
+ 添加 Docker 官方 GPG 密钥并设置存储库
|
||||||
|
+ 安装 Docker 引擎并启动服务
|
||||||
|
+ 设置 Docker 开机自启
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt-get update
|
||||||
|
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
|
||||||
|
echo "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable" | sudo tee -a /etc/apt/sources.list.d/docker.list
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install docker-ce docker-ce-cli containerd.io
|
||||||
|
# 验证安装
|
||||||
|
sudo docker --version
|
||||||
|
```
|
||||||
|
|
||||||
|
__配置/etc/docker/daemon.json__
|
||||||
|
```
|
||||||
{
|
{
|
||||||
"registry-mirrors":
|
"registry-mirrors":
|
||||||
[
|
[
|
||||||
@ -11,23 +42,173 @@
|
|||||||
"https://docker.nju.edu.cn"
|
"https://docker.nju.edu.cn"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
||||||
docker ps #查看所有运行容器
|
## 基本命令
|
||||||
docker ps -a #全部
|
1. 镜像操作
|
||||||
|
+ `docker pull <镜像名>` : 从仓库拉取镜像
|
||||||
|
+ `docker image ls` : 列出本地镜像
|
||||||
|
+ `docker rmi <镜像ID>` : 删除镜像
|
||||||
|
|
||||||
docker stop [ID / NAME] #停止某容器
|
2. 容器操作
|
||||||
|
+ `docker run -d <镜像名>` : 创建并后台运行容器
|
||||||
|
+ `docker ps` : 列出所有运行中容器
|
||||||
|
+ `docker stop [ID / NAME]` : 停止某容器
|
||||||
|
+ `docker start [ID / NAME]` : 启动已经停止的容器
|
||||||
|
+ `docker rm [ID / NAME]` : 删除容器
|
||||||
|
+ `docker commit <容器ID或名称> <新镜像名称>:<标签>` 将运行中的容器保存为镜像
|
||||||
|
+ `docker save -o my-new-image.tar my-new-image:latest` 导出为tar文件
|
||||||
|
+ `docker load -i my-new-image.tar` 导入镜像到目标环境
|
||||||
|
|
||||||
docker start [ID / NAME] #启动和删除容器
|
3. 其他
|
||||||
docker rm [ID / NAME]
|
+ `docker search <镜像名>` 搜索镜像
|
||||||
|
+ `docker logs <容器ID>` : 查看容器日志
|
||||||
|
+ `docker exec -it [ID / NAME] /bin/bash` : 进入容器
|
||||||
|
+ `c-P c-Q` : 退出容器
|
||||||
|
+ `sudo systemctl daemon-reload && sudo systemctl restart docker` 重启
|
||||||
|
+ `docker load < xxx.tar` #导入tar为镜像
|
||||||
|
+ `docker commit [ID] [镜像名]` #容器保存为镜像
|
||||||
|
|
||||||
docker pull 仓库名/镜像名
|
### example-command
|
||||||
|
> `docker pull ubuntu` 拉取 Ubuntu 镜像
|
||||||
|
> `docker run -it ubuntu /bin/bash` 运行 Ubuntu 容器并进入交互式 shell
|
||||||
|
> `docker ps -a` 列出所有容器(包括停止的)
|
||||||
|
> `docker run -it --name mc-ser ubuntu -v /opt/mc:/opt/mc -p 25565:25565 /bin/bash`
|
||||||
|
|
||||||
docker save [ID] > xxx.tar #导出为tar文件
|
## 数据管理
|
||||||
docker load < xxx.tar #导入tar为镜像
|
为了持久化数据,Docker 提供了多种数据管理方式,主要包括 数据卷(Volumes)、绑定挂载(Bind Mounts) 和 临时文件系统(tmpfs)
|
||||||
|
|
||||||
docker commit [ID] [镜像名] #容器保存为镜像
|
1. Docker 数据卷(Volumes)
|
||||||
|
数据卷是 Docker 推荐的数据持久化方式。数据卷存储在 Docker 管理的文件系统中(通常是 /var/lib/docker/volumes/),与容器的生命周期分离,即使容器被删除,数据卷仍然存在
|
||||||
|
|
||||||
docker image ls #查看本地所有镜像
|
+ 持久化:数据卷独立于容器,容器删除后数据仍然保留。
|
||||||
docker rmi [ID / NAME] #删除镜像
|
+ 高性能:数据卷通常比绑定挂载性能更好。
|
||||||
|
+ 易于备份和迁移:数据卷可以通过 Docker 命令轻松备份和恢复。
|
||||||
|
|
||||||
docker exec -it [ID / NAME] bash #操作容器
|
> `docker volume create my_volume` 创建数据卷
|
||||||
|
> `docker volume ls` 查看数据卷
|
||||||
|
> `docker volume inspect my_volume` 查看数据卷详细信息
|
||||||
|
> `docker run -d --name my_container -v my_volume:/path/in/container <image_name>` 挂载数据卷到容器
|
||||||
|
> `docker volume rm my_volume` 删除数据卷
|
||||||
|
> `docker volume prune` 清理未使用的数据卷
|
||||||
|
|
||||||
|
2. 绑定挂载(Bind Mounts)
|
||||||
|
绑定挂载是将主机上的文件或目录直接挂载到容器中
|
||||||
|
|
||||||
|
+ 灵活性:可以直接挂载主机上的任意文件或目录。
|
||||||
|
+ 实时同步:主机和容器之间的文件修改会实时同步。
|
||||||
|
+ 依赖主机文件系统:绑定挂载的路径必须存在于主机上。
|
||||||
|
|
||||||
|
- `docker run -d --name my_container -v /host/path:/container/path <image_name>` 挂载主机目录到容器
|
||||||
|
|
||||||
|
3. 临时文件系统(tmpfs)
|
||||||
|
tmpfs 是一种基于内存的文件系统,适用于需要临时存储数据的场景。数据仅存储在内存中,容器停止后数据会丢失
|
||||||
|
|
||||||
|
+ 高性能:数据存储在内存中,读写速度快。
|
||||||
|
+ 临时性:数据不会持久化,容器停止后数据丢失。
|
||||||
|
|
||||||
|
`docker run -d --name my_container --tmpfs /container/path <image_name>` 挂载 tmpfs 到容器
|
||||||
|
|
||||||
|
4. 数据卷的高级用法
|
||||||
|
多个容器可以共享同一个数据卷,实现数据共享
|
||||||
|
```
|
||||||
|
docker run -d --name container1 -v my_volume:/data <image_name>
|
||||||
|
docker run -d --name container2 -v my_volume:/data <image_name>
|
||||||
|
```
|
||||||
|
|
||||||
|
可以将数据卷或绑定挂载设置为只读,防止容器修改数据
|
||||||
|
`docker run -d --name my_container -v my_volume:/data:ro <image_name>`
|
||||||
|
|
||||||
|
## 高级用法
|
||||||
|
1. Dockerfile
|
||||||
|
Dockerfile 是用于构建镜像的脚本文件,包含一系列指令,用于定义镜像的构建过程
|
||||||
|
```
|
||||||
|
# 使用基础镜像
|
||||||
|
FROM ubuntu:latest
|
||||||
|
|
||||||
|
# 维护者信息
|
||||||
|
MAINTAINER Your Name <your.email@example.com>
|
||||||
|
|
||||||
|
# 更新包索引并安装软件
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
software-properties-common \
|
||||||
|
python3
|
||||||
|
|
||||||
|
# 设置工作目录
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# 复制当前目录下的文件到容器中的 /app 目录
|
||||||
|
COPY . /app
|
||||||
|
|
||||||
|
# 暴露端口
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
# 设置环境变量
|
||||||
|
ENV NAME World
|
||||||
|
|
||||||
|
# 运行命令
|
||||||
|
CMD ["python3", "app.py"]
|
||||||
|
```
|
||||||
|
`docker build -t <image_name> .` 构建镜像
|
||||||
|
|
||||||
|
2. Docker 网络
|
||||||
|
`docker network create <network_name>` 创建网络
|
||||||
|
|
||||||
|
`docker network ls` 查看网络
|
||||||
|
|
||||||
|
`docker network connect <network_name> <container_id>` 连接容器到网络
|
||||||
|
|
||||||
|
3. Docker 数据管理
|
||||||
|
`docker volume create <volume_name>` 创建数据卷
|
||||||
|
|
||||||
|
`docker volume ls` 查看数据卷
|
||||||
|
|
||||||
|
`docker run -v <volume_name>:/path/in/container <image_name>` 挂载数据卷到容器
|
||||||
|
|
||||||
|
4. Docker 资源限制
|
||||||
|
`docker run -m 512m <image_name>` 限制内存
|
||||||
|
|
||||||
|
`docker run --cpus="1.5" <image_name>` 限制 CPU
|
||||||
|
|
||||||
|
5. Docker 安全
|
||||||
|
> 使用非 root 用户运行容器
|
||||||
|
```dockerfile
|
||||||
|
FROM ubuntu
|
||||||
|
RUN useradd -m myuser
|
||||||
|
USER myuser
|
||||||
|
```
|
||||||
|
> 限制容器权限
|
||||||
|
`docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE <image_name>`
|
||||||
|
|
||||||
|
## daemon.json
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"registry-mirrors": [
|
||||||
|
"https://docker.1ms.run",
|
||||||
|
"https://docker.xuanyuan.me",
|
||||||
|
"https://docker.zhai.cm",
|
||||||
|
"https://a.ussh.net",
|
||||||
|
"https://hub.littlediary.cn",
|
||||||
|
"https://hub.rat.dev",
|
||||||
|
"https://atomhub.openatom.cn",
|
||||||
|
"https://docker.m.daocloud.io",
|
||||||
|
"https://dytt.online",
|
||||||
|
"https://func.ink",
|
||||||
|
"https://lispy.org",
|
||||||
|
"https://docker.xiaogenban1993.com",
|
||||||
|
"https://docker.mybacc.com",
|
||||||
|
"https://docker.yomansunter.com",
|
||||||
|
"https://dockerhub.websoft9.com",
|
||||||
|
"https://docker-0.unsee.tech",
|
||||||
|
"https://docker-cf.registry.cyou",
|
||||||
|
"https://docker.1panel.live",
|
||||||
|
"https://docker.imgdb.de",
|
||||||
|
"https://docker.hlmirror.com",
|
||||||
|
"https://dockerpull.org",
|
||||||
|
"https://dockerhub.icu",
|
||||||
|
"https://proxy.1panel.live",
|
||||||
|
"https://docker.1panel.top",
|
||||||
|
"https://docker.ketches.cn"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
g++ -S test.s test.cpp #编译成汇编文件
|
|
||||||
g++ -c test.o test.s #目标文件
|
|
||||||
g++ -o test test.o #链接
|
|
||||||
|
|
||||||
g++ -O1/-O2/-O3 // 优化选项
|
|
||||||
|
|
||||||
g++ -S -o - -fverbose-asm xxx.cpp > xxx.s // 输出带注释的汇编
|
|
||||||
|
|
||||||
|
|
||||||
#静态库制作:
|
|
||||||
g++ -c -o libtest.a {test.cpp 源代码文件清单}
|
|
||||||
// g++ -c test.cpp
|
|
||||||
// ar -crv libtest.a test.o
|
|
||||||
|
|
||||||
|
|
||||||
#动态库制作
|
|
||||||
g++ -fPIC -shared -o libtest.so {test.cpp 源代码文件清单}
|
|
||||||
// g++ -fPIC -c test.cpp
|
|
||||||
// g++ -shared -o libtest.so tset.o
|
|
||||||
两种方法
|
|
||||||
1 + .so 放到 /usr/lib 或 /lib
|
|
||||||
2 + 路径放到/etc/ld.so.conf 运行ldconfd 重建/etc/ld.so.cache
|
|
||||||
|
|
||||||
# 库使用
|
|
||||||
g++ -o main -l库名 -L库路径 -I头文件路径
|
|
||||||
// g++ -o main -ltest -L/home/e0x1a/test
|
|
||||||
|
|
||||||
如果是动态库,需要指定 LD_LIBRARY_PATH 环境变量 //待查
|
|
||||||
用 echo $LD_LIBRARY_PATH 查看
|
|
43
program/tool/gcc_g++.md
Normal file
43
program/tool/gcc_g++.md
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# gcc-g++ 编译器
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
- [编译选项](#编译选项)
|
||||||
|
- [制作库文件](#制作库文件)
|
||||||
|
|
||||||
|
## 编译选项
|
||||||
|
`g++ -S test.s test.cpp` 编译成汇编文件
|
||||||
|
`g++ -c test.o test.s` 目标文件
|
||||||
|
`g++ -o test test.o` 链接
|
||||||
|
|
||||||
|
`g++ -O1/-O2/-O3` // 优化选项
|
||||||
|
|
||||||
|
`g++ -S -o - -fverbose-asm xxx.cpp > xxx.s` // 输出带注释的汇编
|
||||||
|
|
||||||
|
`gcc -s` 选项用于剥除可执行文件中的符号表和重定位信息,减小可执行文件的大小
|
||||||
|
- **正常功能保持**
|
||||||
|
- **性能无显著差异**
|
||||||
|
- **调试困难**:符号表中包含了函数名、变量名等调试信息。使用 `-s` 选项后,这些信息会被移除,使得调试变得非常困难
|
||||||
|
- **反汇编和分析不便**:没有符号表,反汇编工具(如 `objdump`)无法显示函数名和变量名等信息,只能显示汇编指令和地址。这会增加对程序进行反汇编分析的难度。
|
||||||
|
|
||||||
|
|
||||||
|
## 制作库文件
|
||||||
|
> 静态库制作:
|
||||||
|
g++ -c -o libtest.a {test.cpp 源代码文件清单}
|
||||||
|
// g++ -c test.cpp
|
||||||
|
// ar -crv libtest.a test.o
|
||||||
|
|
||||||
|
|
||||||
|
> 动态库制作
|
||||||
|
g++ -fPIC -shared -o libtest.so {test.cpp 源代码文件清单}
|
||||||
|
// g++ -fPIC -c test.cpp
|
||||||
|
// g++ -shared -o libtest.so tset.o
|
||||||
|
两种方法
|
||||||
|
1 + .so 放到 /usr/lib 或 /lib
|
||||||
|
2 + 路径放到/etc/ld.so.conf 运行ldconfd 重建/etc/ld.so.cache
|
||||||
|
|
||||||
|
> 库使用
|
||||||
|
g++ -o main -l库名 -L库路径 -I头文件路径
|
||||||
|
// g++ -o main -ltest -L/home/e0x1a/test
|
||||||
|
|
||||||
|
如果是动态库,需要指定 LD_LIBRARY_PATH 环境变量 //待查
|
||||||
|
用 echo $LD_LIBRARY_PATH 查看
|
63
program/tool/gdb.md
Normal file
63
program/tool/gdb.md
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
# gdb c/c++ 代码调试工具
|
||||||
|
使用 -g 生成调试文件,不可以加 -O 选项
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
- [基础使用](#基础使用)
|
||||||
|
- [run](#run)
|
||||||
|
- [set](#set)
|
||||||
|
- [mem](#mem)
|
||||||
|
- [disassemble](#disassemble)
|
||||||
|
- [info](#info)
|
||||||
|
- [core](#core)
|
||||||
|
|
||||||
|
## 基础使用
|
||||||
|
`l n` 列出源码
|
||||||
|
`b n` 在第n行打断点
|
||||||
|
`break main if var_name > 10` 满足条件时打断点
|
||||||
|
`d n` 删除断点
|
||||||
|
`lay next` 切换窗口布局TUI
|
||||||
|
`Ctrl-x a` 退出TUI
|
||||||
|
`Ctrl-x 1` 恢复单窗口布局
|
||||||
|
`Ctrl-x o` 切换窗口焦点
|
||||||
|
`ref``Ctrl-L` 刷新布局
|
||||||
|
|
||||||
|
### run
|
||||||
|
`r` 开始运行到第一个断点
|
||||||
|
`c` 继续运行到下一个断点
|
||||||
|
`s` 步入
|
||||||
|
`si` 单步汇编
|
||||||
|
`n` 步过
|
||||||
|
`ni`
|
||||||
|
`q` 退出
|
||||||
|
|
||||||
|
### set
|
||||||
|
`set [argc]` 传入参数
|
||||||
|
`set var []` # 修改变量的值
|
||||||
|
`set $rsp = 0x7ccc` # 修改寄存器的值
|
||||||
|
|
||||||
|
### mem
|
||||||
|
`p` # 查看特定变量或表达式的值
|
||||||
|
`bt` # 查看函数调用栈
|
||||||
|
`bt full` # 详细信息
|
||||||
|
`x/10gx $rsp` # 查看内存中由$rsp开始的10个八字节数据 g:八字节 x:16进制
|
||||||
|
|
||||||
|
### disassemble
|
||||||
|
`disassemble` # 查看当前函数的汇编,可在后面加函数名看指定汇编
|
||||||
|
`x/i $pc` # 检查pc处的汇编
|
||||||
|
|
||||||
|
### info
|
||||||
|
`info locals` # 查看局部变量
|
||||||
|
`info registers` # 查看寄存器状态
|
||||||
|
`info program` # 查看程序运行信息
|
||||||
|
`info break` # 查看断点信息
|
||||||
|
`info threads` # 查看所有线程
|
||||||
|
|
||||||
|
## core
|
||||||
|
1. `ulimit -c unlimited` 使挂掉的程序产生core文件
|
||||||
|
|
||||||
|
2. 修改 `/proc/sys/kernel/core_pattern` 使其在当前目录下生成core文件
|
||||||
|
> `sudo echo "./core" > /proc/sys/kernel/core_pattern
|
||||||
|
|
||||||
|
3. gdb ./a.out core
|
||||||
|
|
||||||
|
gdb demo -p [pid] # 调试运行中的程序
|
@ -1,35 +0,0 @@
|
|||||||
gdb c/c++ 代码调试工具
|
|
||||||
使用 g++ -g 生成调试文件,不可以加 -O 选项
|
|
||||||
|
|
||||||
set [argc] # 传入参数
|
|
||||||
l n # 列出源码
|
|
||||||
r # 开始运行到第一个断点
|
|
||||||
b n # 在第n行打断点
|
|
||||||
break main if var_name > 10 # 满足条件时打断点
|
|
||||||
d n # 删除断点
|
|
||||||
c # 继续运行到下一个断点
|
|
||||||
s # 单步执行
|
|
||||||
si # 单步汇编
|
|
||||||
n # 单步执行,不进入函数
|
|
||||||
q # 退出
|
|
||||||
|
|
||||||
set var [] # 修改变量的值
|
|
||||||
set $rsp = 0x7ccccccc # 修改寄存器的值
|
|
||||||
|
|
||||||
p # 查看特定变量或表达式的值
|
|
||||||
bt # 查看函数调用栈
|
|
||||||
bt full # 详细信息
|
|
||||||
disassemble # 查看当前函数的汇编,可在后面加函数名看指定汇编
|
|
||||||
x/10gx $rsp # 查看内存中由$rsp开始的10个八字节数据 g:八字节 x:16进制
|
|
||||||
|
|
||||||
info locals # 查看局部变量
|
|
||||||
info registers # 查看寄存器状态
|
|
||||||
info program # 查看程序运行信息
|
|
||||||
info break # 查看断点信息
|
|
||||||
info threads # 查看所有线程
|
|
||||||
|
|
||||||
使用gdb调试core文件
|
|
||||||
使用ulimit -c unlimited 使挂掉的程序产生core文件
|
|
||||||
gdb ./a.out core
|
|
||||||
|
|
||||||
gdb demo -p [pid] # 调试运行中的程序
|
|
@ -1,46 +1,486 @@
|
|||||||
# makefile
|
# make
|
||||||
|
|
||||||
makefile 是一个通用的项目代码构建器
|
## 目录
|
||||||
由规则 依赖 命令构成
|
- [参数](#参数)
|
||||||
|
- [makefile](#makefile)
|
||||||
|
|
||||||
|
## 参数
|
||||||
|
`-n` 参数可以打印出make会执行的命令,但不真正执行
|
||||||
|
`-f <filename>` 指定makefile
|
||||||
|
`-i` 忽略错误
|
||||||
|
`-k` 在某个目标失败时,尽量构建其他
|
||||||
|
`-s` 静默
|
||||||
|
`-j4` 4线程
|
||||||
|
`-C /dir` 进入指定目录再运行
|
||||||
|
`-d` debug
|
||||||
|
`-w` 打印工作目录
|
||||||
|
`-B` 强制重新构建
|
||||||
|
|
||||||
|
## makefile
|
||||||
|
Makefile 是一种用于自动化构建和管理项目的工具,尤其在 C/C++ 项目中广泛使用。除了基本的规则和依赖关系,Makefile 还支持一些高级语法和功能,可以帮助你编写更灵活和高效的构建脚本
|
||||||
|
|
||||||
规则:依赖
|
规则:依赖
|
||||||
命令
|
命令
|
||||||
|
__注意: 命令前面必须要用Tab__
|
||||||
|
|
||||||
+ -n 参数可以打印出make会执行的命令,但不真正执行
|
## 普通变量定义
|
||||||
|
|
||||||
# 注意: 命令前面必须要用Tab
|
|
||||||
|
|
||||||
# 伪目标
|
|
||||||
.PHONY:clean
|
|
||||||
|
|
||||||
# 自动变量
|
|
||||||
$@ 目标文件
|
|
||||||
$< 第一个依赖文件
|
|
||||||
$^ 全部的依赖文件
|
|
||||||
|
|
||||||
# 普通变量定义
|
|
||||||
OPTION = -O3 -Wall
|
OPTION = -O3 -Wall
|
||||||
|
|
||||||
# 变量使用
|
## 变量使用
|
||||||
g++ $(OPTION) xxx
|
g++ $(OPTION) xxx
|
||||||
|
|
||||||
# 使用通配符
|
### 1. 变量和赋值
|
||||||
%.o: %.c
|
Makefile 支持多种变量赋值方式:
|
||||||
g++ $(OPTION) -c $< -o $@
|
|
||||||
|
|
||||||
|
- **`=`**:递归展开变量,变量值在使用时展开。
|
||||||
|
- **`:=`**:简单展开变量,变量值在定义时展开。
|
||||||
|
- **`?=`**:条件赋值,只有当变量未定义时才赋值。
|
||||||
|
- **`+=`**:追加赋值,将值追加到变量末尾。
|
||||||
|
|
||||||
```makefile
|
```makefile
|
||||||
.PHONY:clean
|
CC = gcc
|
||||||
INCLUDE = -I/home/e0x2d/include
|
CFLAGS := -Wall -O2
|
||||||
main: file1.o file2.o
|
CFLAGS += -g
|
||||||
g++ -o $@ file1.o file2.o
|
```
|
||||||
|
|
||||||
file1.o: file1.cpp
|
### 2. 自动变量
|
||||||
g++ -c file1.o file1.cpp
|
Makefile 提供了一些自动变量,用于简化规则的编写:
|
||||||
|
|
||||||
file2.o: file2.cpp
|
- **`$@`**:目标文件名。
|
||||||
g++ -c file2.o file2.cpp ${INCLUDE}
|
- **`$<`**:第一个依赖文件名。
|
||||||
|
- **`$^`**:所有依赖文件列表。
|
||||||
|
- **`$?`**:所有比目标新的依赖文件列表。
|
||||||
|
- **`$*`**:目标文件的主干名(不包含扩展名)。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 模式规则
|
||||||
|
模式规则允许你使用通配符来定义规则,适用于多个文件。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 函数
|
||||||
|
Makefile 提供了一些内置函数,用于处理字符串、文件名等。
|
||||||
|
|
||||||
|
- **`$(wildcard pattern)`**:匹配文件名模式。
|
||||||
|
- **`$(patsubst pattern,replacement,text)`**:模式替换。
|
||||||
|
- **`$(shell command)`**:执行 shell 命令并返回结果。
|
||||||
|
- **`$(foreach var,list,text)`**:循环遍历列表。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
SRCS = $(wildcard *.c)
|
||||||
|
OBJS = $(patsubst %.c,%.o,$(SRCS))
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. 条件判断
|
||||||
|
Makefile 支持条件判断,可以根据条件执行不同的操作。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
ifeq ($(DEBUG),1)
|
||||||
|
CFLAGS += -DDEBUG
|
||||||
|
else
|
||||||
|
CFLAGS += -DNDEBUG
|
||||||
|
endif
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. 包含其他 Makefile
|
||||||
|
你可以使用 `include` 指令将其他 Makefile 包含到当前 Makefile 中。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
include config.mk
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7. 多目标规则
|
||||||
|
你可以为一个规则定义多个目标,这样它们可以共享相同的命令。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
all: target1 target2
|
||||||
|
|
||||||
|
target1 target2:
|
||||||
|
@echo Building $@
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8. 伪目标
|
||||||
|
伪目标是指那些不对应实际文件的目标,通常用于执行一些操作,如清理、安装等。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
.PHONY: clean
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm *.o demo
|
rm -f *.o
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9. 嵌套 Makefile
|
||||||
|
你可以在 Makefile 中调用另一个 Makefile,通常用于构建子目录中的项目。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
SUBDIRS = dir1 dir2
|
||||||
|
|
||||||
|
$(SUBDIRS):
|
||||||
|
$(MAKE) -C $@
|
||||||
|
|
||||||
|
all: $(SUBDIRS)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 10. 自定义函数
|
||||||
|
你可以通过 `define` 和 `endef` 定义自定义函数。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
define greet
|
||||||
|
@echo "Hello, $(1)!"
|
||||||
|
endef
|
||||||
|
|
||||||
|
all:
|
||||||
|
$(call greet,World)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 11. 错误处理
|
||||||
|
你可以使用 `$(error text)` 和 `$(warning text)` 来生成错误或警告信息。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
ifeq ($(CC),)
|
||||||
|
$(error CC is not set)
|
||||||
|
endif
|
||||||
|
```
|
||||||
|
|
||||||
|
### 13. 隐式规则
|
||||||
|
Makefile 有一些内置的隐式规则,可以自动推导如何从源文件生成目标文件。你可以通过定义自己的隐式规则来覆盖默认行为。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
```
|
||||||
|
|
||||||
|
### 14. 动态依赖
|
||||||
|
你可以使用 `-include` 来包含动态生成的依赖文件,通常用于自动生成头文件依赖。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
-include $(OBJS:.o=.d)
|
||||||
|
|
||||||
|
%.d: %.c
|
||||||
|
@$(CC) -MM $< > $@.$$$$; \
|
||||||
|
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
|
||||||
|
rm -f $@.$$$$
|
||||||
|
```
|
||||||
|
|
||||||
|
### 16. 环境变量
|
||||||
|
Makefile 可以访问环境变量,并且可以通过 `export` 将变量传递给子 Makefile。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
export PATH := $(PATH):/usr/local/bin
|
||||||
|
```
|
||||||
|
|
||||||
|
### 17. 多行命令
|
||||||
|
你可以使用反斜杠 `\` 将长命令分成多行。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
all:
|
||||||
|
@echo "This is a long command that spans \
|
||||||
|
multiple lines."
|
||||||
|
```
|
||||||
|
|
||||||
|
### 18. 命令前缀
|
||||||
|
命令前缀可以控制命令的执行方式:
|
||||||
|
|
||||||
|
- **`@`**:不显示命令本身,只显示输出。
|
||||||
|
- **`-`**:忽略命令的错误,继续执行。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
all:
|
||||||
|
@echo "This command will not be displayed"
|
||||||
|
-rm -f non_existent_file
|
||||||
|
```
|
||||||
|
|
||||||
|
### 19. 文件搜索路径
|
||||||
|
你可以使用 `VPATH` 或 `vpath` 来指定源文件的搜索路径。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
VPATH = src:include
|
||||||
|
|
||||||
|
vpath %.c src
|
||||||
|
vpath %.h include
|
||||||
|
```
|
||||||
|
|
||||||
|
### 20. 递归扩展变量
|
||||||
|
递归扩展变量在使用时才会展开,可以用于动态生成内容。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
FOO = $(BAR)
|
||||||
|
BAR = $(BAZ)
|
||||||
|
BAZ = Hello
|
||||||
|
|
||||||
|
all:
|
||||||
|
@echo $(FOO) # 输出 Hello
|
||||||
|
```
|
||||||
|
|
||||||
|
### 21. 静态模式规则
|
||||||
|
静态模式规则允许你为特定目标定义规则。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
objects = foo.o bar.o
|
||||||
|
|
||||||
|
$(objects): %.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -c $< -o $@
|
||||||
|
```
|
||||||
|
|
||||||
|
### 22. 多架构支持
|
||||||
|
你可以通过条件判断来支持多架构编译。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
ifeq ($(ARCH),x86)
|
||||||
|
CFLAGS += -m32
|
||||||
|
else ifeq ($(ARCH),x64)
|
||||||
|
CFLAGS += -m64
|
||||||
|
endif
|
||||||
|
```
|
||||||
|
|
||||||
|
### 23. 自定义后缀规则
|
||||||
|
你可以定义自定义的后缀规则来处理特定类型的文件。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
.SUFFIXES: .cpp .o
|
||||||
|
|
||||||
|
.cpp.o:
|
||||||
|
$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||||
|
```
|
||||||
|
|
||||||
|
### 24. 使用 `eval` 动态生成规则
|
||||||
|
`eval` 函数可以动态生成 Makefile 规则。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
define MAKE_RULE
|
||||||
|
$(1): $(2)
|
||||||
|
$(CC) $(CFLAGS) -c $$< -o $$@
|
||||||
|
endef
|
||||||
|
|
||||||
|
$(eval $(call MAKE_RULE,foo.o,foo.c))
|
||||||
|
```
|
||||||
|
|
||||||
|
### 25. 使用 `foreach` 循环
|
||||||
|
`foreach` 函数可以用于循环处理列表中的每个元素。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
DIRS = dir1 dir2 dir3
|
||||||
|
|
||||||
|
all:
|
||||||
|
$(foreach dir,$(DIRS),$(MAKE) -C $(dir);)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 26. 使用 `call` 调用自定义函数
|
||||||
|
`call` 函数可以调用自定义函数,并传递参数。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
define greet
|
||||||
|
@echo "Hello, $(1)!"
|
||||||
|
endef
|
||||||
|
|
||||||
|
all:
|
||||||
|
$(call greet,World)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 27. 使用 `shell` 函数执行外部命令
|
||||||
|
`shell` 函数可以执行外部命令并返回结果。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
DATE := $(shell date)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 28. 使用 `info` 和 `warning` 输出信息
|
||||||
|
`info` 和 `warning` 函数可以用于输出信息。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
$(info Building target $(TARGET))
|
||||||
|
$(warning This is a warning message)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 29. 使用 `if` 条件判断
|
||||||
|
`if` 函数可以用于条件判断。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
DEBUG = 1
|
||||||
|
|
||||||
|
CFLAGS += $(if $(DEBUG),-g,-O2)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 30. 使用 `or` 和 `and` 逻辑操作
|
||||||
|
`or` 和 `and` 函数可以用于逻辑操作。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
ifeq ($(DEBUG),1)
|
||||||
|
CFLAGS += -g
|
||||||
|
else ifeq ($(OPTIMIZE),1)
|
||||||
|
CFLAGS += -O2
|
||||||
|
endif
|
||||||
|
```
|
||||||
|
|
||||||
|
### 31. 使用 `not` 取反
|
||||||
|
`not` 函数可以用于取反操作。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
ifneq ($(DEBUG),1)
|
||||||
|
CFLAGS += -O2
|
||||||
|
endif
|
||||||
|
```
|
||||||
|
|
||||||
|
### 32. 使用 `filter` 和 `filter-out` 过滤列表
|
||||||
|
`filter` 和 `filter-out` 函数可以用于过滤列表。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
SRCS = foo.c bar.c baz.c
|
||||||
|
|
||||||
|
C_SRCS = $(filter %.c,$(SRCS))
|
||||||
|
NON_C_SRCS = $(filter-out %.c,$(SRCS))
|
||||||
|
```
|
||||||
|
|
||||||
|
### 33. 使用 `sort` 排序列表
|
||||||
|
`sort` 函数可以用于排序列表。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
SRCS = foo.c bar.c baz.c
|
||||||
|
|
||||||
|
SORTED_SRCS = $(sort $(SRCS))
|
||||||
|
```
|
||||||
|
|
||||||
|
### 34. 使用 `strip` 去除空格
|
||||||
|
`strip` 函数可以用于去除字符串中的空格。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
STR = foo bar
|
||||||
|
|
||||||
|
STRIPED_STR = $(strip $(STR))
|
||||||
|
```
|
||||||
|
|
||||||
|
### 35. 使用 `findstring` 查找子字符串
|
||||||
|
`findstring` 函数可以用于查找子字符串。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
ifeq ($(findstring foo,$(STR)),foo)
|
||||||
|
@echo "Found foo"
|
||||||
|
endif
|
||||||
|
```
|
||||||
|
|
||||||
|
### 36. 使用 `subst` 替换字符串
|
||||||
|
`subst` 函数可以用于替换字符串。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
STR = foo bar baz
|
||||||
|
|
||||||
|
NEW_STR = $(subst foo,FOO,$(STR))
|
||||||
|
```
|
||||||
|
|
||||||
|
### 37. 使用 `patsubst` 模式替换
|
||||||
|
`patsubst` 函数可以用于模式替换。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
SRCS = foo.c bar.c baz.c
|
||||||
|
|
||||||
|
OBJS = $(patsubst %.c,%.o,$(SRCS))
|
||||||
|
```
|
||||||
|
|
||||||
|
### 38. 使用 `wildcard` 匹配文件名
|
||||||
|
`wildcard` 函数可以用于匹配文件名。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
SRCS = $(wildcard *.c)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 39. 使用 `dir` 和 `notdir` 获取目录和文件名
|
||||||
|
`dir` 和 `notdir` 函数可以用于获取目录和文件名。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
FILE = /path/to/file.c
|
||||||
|
|
||||||
|
DIR = $(dir $(FILE))
|
||||||
|
NAME = $(notdir $(FILE))
|
||||||
|
```
|
||||||
|
|
||||||
|
### 40. 使用 `suffix` 和 `basename` 获取后缀和主干名
|
||||||
|
`suffix` 和 `basename` 函数可以用于获取文件的后缀和主干名。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
FILE = file.c
|
||||||
|
|
||||||
|
SUFFIX = $(suffix $(FILE))
|
||||||
|
BASENAME = $(basename $(FILE))
|
||||||
|
```
|
||||||
|
|
||||||
|
### 41. 使用 `addsuffix` 和 `addprefix` 添加后缀和前缀
|
||||||
|
`addsuffix` 和 `addprefix` 函数可以用于添加后缀和前缀。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
FILES = foo bar baz
|
||||||
|
|
||||||
|
FILES_WITH_SUFFIX = $(addsuffix .c,$(FILES))
|
||||||
|
FILES_WITH_PREFIX = $(addprefix src/,$(FILES))
|
||||||
|
```
|
||||||
|
|
||||||
|
### 42. 使用 `join` 连接列表
|
||||||
|
`join` 函数可以用于连接两个列表。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
LIST1 = foo bar
|
||||||
|
LIST2 = baz qux
|
||||||
|
|
||||||
|
JOINED_LIST = $(join $(LIST1),$(LIST2))
|
||||||
|
```
|
||||||
|
|
||||||
|
### 43. 使用 `word` 和 `wordlist` 获取列表中的元素
|
||||||
|
`word` 和 `wordlist` 函数可以用于获取列表中的元素。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
LIST = foo bar baz
|
||||||
|
|
||||||
|
FIRST = $(word 1,$(LIST))
|
||||||
|
SUBLIST = $(wordlist 2,3,$(LIST))
|
||||||
|
```
|
||||||
|
|
||||||
|
### 44. 使用 `words` 获取列表长度
|
||||||
|
`words` 函数可以用于获取列表的长度。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
LIST = foo bar baz
|
||||||
|
|
||||||
|
LENGTH = $(words $(LIST))
|
||||||
|
```
|
||||||
|
|
||||||
|
### 45. 使用 `firstword` 获取列表的第一个元素
|
||||||
|
`firstword` 函数可以用于获取列表的第一个元素。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
LIST = foo bar baz
|
||||||
|
|
||||||
|
FIRST = $(firstword $(LIST))
|
||||||
|
```
|
||||||
|
|
||||||
|
### 46. 使用 `lastword` 获取列表的最后一个元素
|
||||||
|
`lastword` 函数可以用于获取列表的最后一个元素。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
LIST = foo bar baz
|
||||||
|
|
||||||
|
LAST = $(lastword $(LIST))
|
||||||
|
```
|
||||||
|
|
||||||
|
### 47. 使用 `abspath` 获取绝对路径
|
||||||
|
`abspath` 函数可以用于获取绝对路径。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
FILE = file.c
|
||||||
|
|
||||||
|
ABS_PATH = $(abspath $(FILE))
|
||||||
|
```
|
||||||
|
|
||||||
|
### 48. 使用 `realpath` 获取规范化的绝对路径
|
||||||
|
`realpath` 函数可以用于获取规范化的绝对路径。
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
FILE = ../file.c
|
||||||
|
|
||||||
|
REAL_PATH = $(realpath $(FILE))
|
||||||
```
|
```
|
||||||
|
37
radio/antenna.md
Normal file
37
radio/antenna.md
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# 天线相关
|
||||||
|
|
||||||
|
## index
|
||||||
|
- [极化](# 极化)
|
||||||
|
|
||||||
|
## 极化
|
||||||
|
在无线电通信中,垂直极化和水平极化是两种常见的天线极化方式,它们的区别主要体现在电磁波的振动方向、传播特性以及应用场景上。以下是具体对比:
|
||||||
|
|
||||||
|
### **1. 极化方向**
|
||||||
|
- **垂直极化**:电磁波的电场分量(E-field)与地面垂直振动,天线通常垂直于地面放置(如直立杆状天线)。
|
||||||
|
- **水平极化**:电磁波的电场分量与地面平行振动,天线通常水平架设(如水平拉长的偶极天线)。
|
||||||
|
|
||||||
|
### **2. 传播特性**
|
||||||
|
- **地面反射影响**:
|
||||||
|
- 垂直极化波在地面反射时相位变化较小,更适合地面波传播(如AM广播、车载通信)。
|
||||||
|
- 水平极化波的地面反射可能导致信号抵消(尤其在仰角较低时),但对天波传播(如短波通信)更有利。
|
||||||
|
- **抗干扰能力**:
|
||||||
|
- 垂直极化更容易受到地面物体(如建筑物、树木)的反射干扰。
|
||||||
|
- 水平极化受地面干扰较小,但在城市环境中可能受多径效应影响。
|
||||||
|
|
||||||
|
### **3. 应用场景**
|
||||||
|
- **垂直极化**:
|
||||||
|
- **移动通信**(如车载天线、对讲机):便于安装,适应移动设备姿态变化。
|
||||||
|
- **低频段通信**(如30MHz以下):地波传播效率高。
|
||||||
|
- **水平极化**:
|
||||||
|
- **电视广播**(传统地面电视):减少地面反射干扰,覆盖更稳定。
|
||||||
|
- **卫星通信**:减少电离层对极化旋转的影响(常与圆极化结合使用)。
|
||||||
|
- **短波通信**:利用电离层反射时效率更高。
|
||||||
|
|
||||||
|
### **4. 天线安装与兼容性**
|
||||||
|
- **极化匹配**:
|
||||||
|
- 收发天线极化方式需一致,否则会导致严重信号衰减(如垂直天线无法有效接收水平极化波)。
|
||||||
|
- 特殊场景(如卫星通信)可能采用圆极化以避免极化失配。
|
||||||
|
|
||||||
|
### **总结选择依据**
|
||||||
|
- **优先垂直极化**:移动通信、地波传播、简化安装。
|
||||||
|
- **优先水平极化**:固定点对点通信、减少地面干扰、高频段应用。
|
@ -1,15 +0,0 @@
|
|||||||
加速器
|
|
||||||
https://cloud.tsinghua.edu.cn/d/df482a15afb64dfeaff8/
|
|
||||||
推送到github
|
|
||||||
git remote add origin https://
|
|
||||||
git branch -M master
|
|
||||||
git push -u origin master
|
|
||||||
|
|
||||||
github访问令牌
|
|
||||||
创建:
|
|
||||||
用户头像 -> setting -> 最后一项 -> 创建令牌
|
|
||||||
tips:令牌要当场复制,离开页面就没有了
|
|
||||||
|
|
||||||
使用:
|
|
||||||
git remote set-url origin https://<your_token>@github.com/<USERNAME>/<REPO>.git
|
|
||||||
|
|
40
tool/git/github.md
Normal file
40
tool/git/github.md
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# github
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
- [search](#search)
|
||||||
|
|
||||||
|
## search
|
||||||
|
|
||||||
|
1. 限定搜索范围
|
||||||
|
- `in:name`:搜索仓库名称。
|
||||||
|
- `in:description`:搜索仓库描述。
|
||||||
|
- 使用`is:issue`或`is:pr`搜索Issue或Pull Request。
|
||||||
|
- **星标筛选**:使用`stars:>1000`筛选星标数超过1000的项目。
|
||||||
|
- **fork数量筛选**:使用`forks:>100`筛选fork数量超过100的项目。
|
||||||
|
- **语言筛选**:使用`language:java`筛选使用Java语言的项目。
|
||||||
|
- **仓库大小筛选**:使用`size:>=1000`筛选仓库大小超过1000KB的项目。
|
||||||
|
- **更新时间筛选**:使用`pushed:>2020-01-01`筛选自2020年1月1日之后有更新的项目。
|
||||||
|
- **搜索特定用户或组织的仓库**:使用`user:username`或`org:organization`。
|
||||||
|
- **搜索特定文件**:使用`filename:README.md`搜索包含特定文件名的项目。
|
||||||
|
- **搜索代码**:必须登录GitHub账户,且仅对默认分支和小于384KB的文件进行索引。
|
||||||
|
|
||||||
|
2. 排序搜索结果
|
||||||
|
- **按交互排序**:`sort:interactions`按反应和评论的最高组合数排序。
|
||||||
|
- **按反应排序**:`sort:reactions`按最高反应数排序。
|
||||||
|
- **按作者日期排序**:`sort:author-date`按作者日期降序排序。
|
||||||
|
|
||||||
|
加速器
|
||||||
|
https://cloud.tsinghua.edu.cn/d/df482a15afb64dfeaff8/
|
||||||
|
推送到github
|
||||||
|
git remote add origin https://
|
||||||
|
git branch -M master
|
||||||
|
git push -u origin master
|
||||||
|
|
||||||
|
github访问令牌
|
||||||
|
创建:
|
||||||
|
用户头像 -> setting -> 最后一项 -> 创建令牌
|
||||||
|
tips:令牌要当场复制,离开页面就没有了
|
||||||
|
|
||||||
|
使用:
|
||||||
|
git remote set-url origin https://<your_token>@github.com/<USERNAME>/<REPO>.git
|
||||||
|
|
31
tool/konsole.md
Normal file
31
tool/konsole.md
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# konsole-use
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
- [strat](#start)
|
||||||
|
- [标签页管理](#标签页管理)
|
||||||
|
- [窗口分割](#窗口分割)
|
||||||
|
- [shortkey](#shortkey)
|
||||||
|
|
||||||
|
## strat
|
||||||
|
`Ctrl-Alt-t`
|
||||||
|
|
||||||
|
## 标签页管理
|
||||||
|
`Ctrl-T` 打开新标签页
|
||||||
|
`Ctrl-W` 关闭标签页
|
||||||
|
`Ctrl-PgUp` and `Ctrl-PgDn` 切换标签页
|
||||||
|
`Alt-[num]` 切换到指定标签页
|
||||||
|
|
||||||
|
## 窗口分割
|
||||||
|
`Ctrl-(` 水平分割
|
||||||
|
`Ctrl-)` 垂直分割
|
||||||
|
`Ctrl-Shift-方向键` 聚焦指定方向的终端
|
||||||
|
`Ctrl-Shift-H` 分离
|
||||||
|
|
||||||
|
## shortkey
|
||||||
|
`Ctrl-F` 查找
|
||||||
|
`Shift-F3` 查找上一个
|
||||||
|
`F3` 查找下一个
|
||||||
|
|
||||||
|
`Shift-F10` 打开菜单
|
||||||
|
|
@ -14,28 +14,73 @@ set cursorline "光标行高亮
|
|||||||
set hlsearch "高亮显示搜索结果
|
set hlsearch "高亮显示搜索结果
|
||||||
set incsearch "搜索模式下,每输入一个字符,就跳到对应结果
|
set incsearch "搜索模式下,每输入一个字符,就跳到对应结果
|
||||||
set ignorecase "忽略搜索大小写
|
set ignorecase "忽略搜索大小写
|
||||||
|
set tags=./tags;,tags "表示从当前文件所在的目录开始查找 tags 文件,如果没有,则向上递归查找
|
||||||
|
|
||||||
|
"缓冲区操作
|
||||||
nnoremap <space>b :buffers<cr>:b<space>
|
nnoremap <space>b :buffers<cr>:b<space>
|
||||||
nnoremap <space>e :b#<cr>
|
nnoremap <space>e :b#<cr>
|
||||||
nnoremap <space>n :bnext<cr>
|
nnoremap <space>n :bnext<cr>
|
||||||
|
|
||||||
|
"页面分割操作
|
||||||
nnoremap <space>s :split<space>
|
nnoremap <space>s :split<space>
|
||||||
nnoremap <space>v :vsp<space>
|
nnoremap <space>v :vsp<space>
|
||||||
nnoremap <space>d <c-w>w
|
nnoremap <space>d <c-w>w
|
||||||
|
|
||||||
|
"保存
|
||||||
nnoremap <space>w :w<cr>
|
nnoremap <space>w :w<cr>
|
||||||
nnoremap <space>q :q<cr>
|
nnoremap <space>q :q<cr>
|
||||||
nnoremap <space>fq :q!<cr>
|
nnoremap <space>fq :q!<cr>
|
||||||
|
nnoremap <space>pq :%s/\t/ /g<cr>:wq<cr>
|
||||||
|
|
||||||
|
"多标签页
|
||||||
nnoremap <space>tt :tabedit<space>
|
nnoremap <space>tt :tabedit<space>
|
||||||
nnoremap <space>tm :vert term<cr>
|
nnoremap <space>tm :vert term<cr>
|
||||||
|
|
||||||
|
"操作优化
|
||||||
|
nnoremap gm $
|
||||||
|
nnoremap <space>r :reg<cr>
|
||||||
inoremap jf <esc>
|
inoremap jf <esc>
|
||||||
inoremap jl <c-x><c-l>
|
|
||||||
cnoremap jf <c-c>
|
cnoremap jf <c-c>
|
||||||
"inoremap jq <esc>:wq<cr>
|
vnoremap gm $
|
||||||
"inoremap jw <c-x><c-n>
|
inoremap ! !
|
||||||
"nnoremap <space>to :tabonly<cr>
|
inoremap ( (
|
||||||
|
inoremap ) )
|
||||||
|
inoremap 【 [
|
||||||
|
inoremap 】 ]
|
||||||
|
inoremap ; ;
|
||||||
|
inoremap : :
|
||||||
|
inoremap ‘ '
|
||||||
|
inoremap “ "
|
||||||
|
inoremap , ,
|
||||||
|
inoremap 。 .
|
||||||
|
inoremap ? ?
|
||||||
|
inoremap 《 <
|
||||||
|
inoremap 》 >
|
||||||
|
inoremap · `
|
||||||
|
|
||||||
|
"自动补全
|
||||||
|
inoremap jl <c-x><c-l>
|
||||||
|
inoremap jbf <c-x><c-f>
|
||||||
|
inoremap jk <c-x><c-k>
|
||||||
|
|
||||||
|
" 启用字典补全(Ctrl-X Ctrl-K)
|
||||||
|
set complete+=k
|
||||||
|
|
||||||
|
" 加载字典补全功能
|
||||||
|
|
||||||
|
" 根据文件类型设置不同的字典文件
|
||||||
|
autocmd FileType c setlocal dictionary+=~/.vim/dict/cpp.dict
|
||||||
|
autocmd FileType cpp setlocal dictionary+=~/.vim/dict/cpp.dict
|
||||||
|
"autocmd FileType python setlocal dictionary+=~/.vim/dict/python.dict
|
||||||
|
"autocmd FileType javascript setlocal dictionary+=~/.vim/dict/javascript.dict
|
||||||
|
"autocmd FileType html setlocal dictionary+=~/.vim/dict/html.dict
|
||||||
|
"autocmd FileType css setlocal dictionary+=~/.vim/dict/css.dict
|
||||||
|
|
||||||
|
|
||||||
augroup numbertoggle "智能切换绝对行号和相对行号
|
augroup numbertoggle "智能切换绝对行号和相对行号
|
||||||
autocmd!
|
autocmd!
|
||||||
autocmd BufEnter,FocusGained,InsertLeave,WinEnter * if &nu && mode() != "i" | set rnu | endif
|
autocmd BufEnter,FocusGained,InsertLeave,WinEnter * if &nu && mode() != "i" | set rnu | endif
|
||||||
autocmd BufLeave,FocusLost,InsertEnter,WinLeave * if &nu | set nornu | endif
|
autocmd BufLeave,FocusLost,InsertEnter,WinLeave * if &nu | set nornu | endif
|
||||||
augroup END
|
augroup END
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
# 小技巧
|
|
||||||
使用 q[Key] 开始录制宏,再次点击q结束录制
|
|
||||||
@[Key] 调用宏
|
|
||||||
@@ 重复调用
|
|
||||||
|
|
||||||
# vim中打开终端
|
|
||||||
`:term`或`:vert term`
|
|
||||||
从终端转到普通模式:`<c-\>+<c-n>`
|
|
||||||
|
|
||||||
# 快捷键
|
|
||||||
|
|
||||||
> 移动
|
|
||||||
## 0 gm
|
|
||||||
行首行尾移动
|
|
||||||
## ngg
|
|
||||||
移动到第n行
|
|
||||||
## fc tc
|
|
||||||
搜索字符 ; , 可重复
|
|
||||||
|
|
||||||
> 插入
|
|
||||||
## r R
|
|
||||||
替换光标下的字符
|
|
||||||
## n<< n>>
|
|
||||||
多行左右移动
|
|
||||||
|
|
||||||
|
|
||||||
> 删除
|
|
||||||
## x
|
|
||||||
删除光标下字符
|
|
||||||
## J
|
|
||||||
与下一行合并
|
|
||||||
|
|
||||||
> 复制
|
|
||||||
## "x
|
|
||||||
使用寄存器x进行下一次复制 粘贴 删除
|
|
||||||
:reg 显示所有寄存器
|
|
||||||
|
|
||||||
|
|
||||||
> 可视模式
|
|
||||||
## o
|
|
||||||
交换选择区域另一端和光标的位置
|
|
||||||
## aw as ap ab aB
|
|
||||||
选择一个单词 句子 段落 () {}
|
|
||||||
## vi{
|
|
||||||
选中一整个大括号内
|
|
||||||
## va{
|
|
||||||
选中一整个大括号全部
|
|
||||||
|
|
||||||
|
|
||||||
## ]f
|
|
||||||
在文件中若出现文件名,指针放在上面使用这个快捷键可直接打开
|
|
||||||
|
|
157
tool/vim/cpp.dict
Normal file
157
tool/vim/cpp.dict
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
include
|
||||||
|
auto
|
||||||
|
break
|
||||||
|
case
|
||||||
|
char
|
||||||
|
const
|
||||||
|
continue
|
||||||
|
default
|
||||||
|
do
|
||||||
|
double
|
||||||
|
else
|
||||||
|
enum
|
||||||
|
extern
|
||||||
|
float
|
||||||
|
for
|
||||||
|
goto
|
||||||
|
if
|
||||||
|
int
|
||||||
|
long
|
||||||
|
register
|
||||||
|
return
|
||||||
|
short
|
||||||
|
signed
|
||||||
|
sizeof
|
||||||
|
static
|
||||||
|
struct
|
||||||
|
switch
|
||||||
|
typedef
|
||||||
|
union
|
||||||
|
unsigned
|
||||||
|
void
|
||||||
|
volatile
|
||||||
|
while
|
||||||
|
|
||||||
|
class
|
||||||
|
delete
|
||||||
|
explicit
|
||||||
|
friend
|
||||||
|
inline
|
||||||
|
namespace
|
||||||
|
new
|
||||||
|
operator
|
||||||
|
private
|
||||||
|
protected
|
||||||
|
public
|
||||||
|
template
|
||||||
|
this
|
||||||
|
throw
|
||||||
|
try
|
||||||
|
catch
|
||||||
|
virtual
|
||||||
|
using
|
||||||
|
typename
|
||||||
|
mutable
|
||||||
|
const_cast
|
||||||
|
dynamic_cast
|
||||||
|
reinterpret_cast
|
||||||
|
static_cast
|
||||||
|
typeid
|
||||||
|
endl
|
||||||
|
|
||||||
|
printf
|
||||||
|
scanf
|
||||||
|
fopen
|
||||||
|
fclose
|
||||||
|
fgets
|
||||||
|
fputs
|
||||||
|
fread
|
||||||
|
fwrite
|
||||||
|
sprintf
|
||||||
|
sscanf
|
||||||
|
|
||||||
|
malloc
|
||||||
|
free
|
||||||
|
calloc
|
||||||
|
realloc
|
||||||
|
exit
|
||||||
|
atoi
|
||||||
|
atof
|
||||||
|
rand
|
||||||
|
srand
|
||||||
|
|
||||||
|
strcpy
|
||||||
|
strncpy
|
||||||
|
strcat
|
||||||
|
strncat
|
||||||
|
strcmp
|
||||||
|
strncmp
|
||||||
|
strlen
|
||||||
|
strstr
|
||||||
|
strtok
|
||||||
|
memset
|
||||||
|
memcpy
|
||||||
|
memmove
|
||||||
|
|
||||||
|
sin
|
||||||
|
cos
|
||||||
|
tan
|
||||||
|
sqrt
|
||||||
|
pow
|
||||||
|
log
|
||||||
|
exp
|
||||||
|
ceil
|
||||||
|
floor
|
||||||
|
fabs
|
||||||
|
|
||||||
|
time
|
||||||
|
clock
|
||||||
|
difftime
|
||||||
|
gmtime
|
||||||
|
localtime
|
||||||
|
strftime
|
||||||
|
|
||||||
|
vector
|
||||||
|
list
|
||||||
|
map
|
||||||
|
unordered_map
|
||||||
|
set
|
||||||
|
unordered_set
|
||||||
|
queue
|
||||||
|
stack
|
||||||
|
deque
|
||||||
|
pair
|
||||||
|
tuple
|
||||||
|
|
||||||
|
sort
|
||||||
|
find
|
||||||
|
copy
|
||||||
|
transform
|
||||||
|
accumulate
|
||||||
|
for_each
|
||||||
|
count
|
||||||
|
reverse
|
||||||
|
max_element
|
||||||
|
min_element
|
||||||
|
|
||||||
|
define
|
||||||
|
NULL
|
||||||
|
EOF
|
||||||
|
true
|
||||||
|
false
|
||||||
|
stdin
|
||||||
|
stdout
|
||||||
|
stderr
|
||||||
|
EXIT_SUCCESS
|
||||||
|
EXIT_FAILURE
|
||||||
|
|
||||||
|
open
|
||||||
|
close
|
||||||
|
read
|
||||||
|
write
|
||||||
|
fork
|
||||||
|
exec
|
||||||
|
pipe
|
||||||
|
dup2
|
||||||
|
select
|
||||||
|
poll
|
89
tool/vim/shortcutKeys.md
Normal file
89
tool/vim/shortcutKeys.md
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
# vim小技巧
|
||||||
|
`.` 重复上一个操作
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
- [录制宏](# 录制宏)
|
||||||
|
- [打开终端](# 打开终端)
|
||||||
|
- [快捷键](# 快捷键)
|
||||||
|
- [移动](# 移动)
|
||||||
|
- [插入](# 插入)
|
||||||
|
- [修改](# 修改)
|
||||||
|
- [删除](# 删除)
|
||||||
|
- [复制](# 复制)
|
||||||
|
- [基本补全](# 基本补全)
|
||||||
|
- [补全菜单](# 补全菜单)
|
||||||
|
- [vimrc](# ./.vimrc)
|
||||||
|
|
||||||
|
## 录制宏
|
||||||
|
使用 q[Key] 开始录制宏,再次点击q结束录制
|
||||||
|
@[Key] 调用宏
|
||||||
|
@@ 重复调用
|
||||||
|
|
||||||
|
## 打开终端
|
||||||
|
`:term`或`:vert term`
|
||||||
|
从终端转到普通模式:`<c-\>+<c-n>`
|
||||||
|
|
||||||
|
## 快捷键
|
||||||
|
### 移动
|
||||||
|
+ 0 gm 行首行尾
|
||||||
|
+ ngg 移动到第n行
|
||||||
|
+ fc tc 搜索字符 ; , 可重复
|
||||||
|
+ c-u 上半屏
|
||||||
|
+ c-d 下半屏
|
||||||
|
+ Shift-[ 跳转到上一个空行
|
||||||
|
+ * 移动到下一个与当前指针下相同单词的位置
|
||||||
|
+ # 移动到上一个与当前指针下相同单词的位置
|
||||||
|
+ Ctrl + ] 跳转到标签,依赖于tags文件
|
||||||
|
+ `ctags -R .` 创建目录下的跳转文件
|
||||||
|
+ Vim 会记录跳转历史,使用 Ctrl + T 或 Ctrl + O 返回到上一个位置
|
||||||
|
+ gf 跳转到文件路径
|
||||||
|
+ `c-o` 后退一步
|
||||||
|
+ `c-i` 前进一步
|
||||||
|
+ `[a-z] / `[A-Z] 跳转到标记位置 大写全局,小写本文件,用m[a-z]设置标记
|
||||||
|
+ ` 上次跳转的位置
|
||||||
|
+ . 最后一次修改的位置
|
||||||
|
|
||||||
|
### 插入
|
||||||
|
+ I A 行首 行末 插入
|
||||||
|
+ n<< n>> 多行左右移动
|
||||||
|
|
||||||
|
## 修改
|
||||||
|
+ r R 替换光标下的字符
|
||||||
|
+ c-i-( 替换括号内的内容可以使用任何括号匹配
|
||||||
|
|
||||||
|
### 删除
|
||||||
|
+ x 删除光标下字符
|
||||||
|
+ J 与下一行合并
|
||||||
|
+ Shift-d 从当前字符删除到行末
|
||||||
|
|
||||||
|
### 复制
|
||||||
|
+ "x 使用寄存器x进行下一次复制 粘贴 删除
|
||||||
|
:reg 显示所有寄存器
|
||||||
|
|
||||||
|
### 可视模式
|
||||||
|
+ o
|
||||||
|
交换选择区域另一端和光标的位置
|
||||||
|
+ aw as ap ab aB
|
||||||
|
选择一个单词 句子 段落 () {}
|
||||||
|
+ vi{
|
||||||
|
选中一整个大括号内
|
||||||
|
+ va{
|
||||||
|
选中一整个大括号全部
|
||||||
|
+ ]f
|
||||||
|
在文件中若出现文件名,指针放在上面使用这个快捷键可直接打开
|
||||||
|
|
||||||
|
## 基本补全
|
||||||
|
1. Ctrl+n - 普通关键字补全(向下浏览)
|
||||||
|
- 在当前文件和包含文件中查找匹配项
|
||||||
|
- 适用于变量名、函数名等
|
||||||
|
2. Ctrl+p - 普通关键字补全(向上浏览)
|
||||||
|
- 与 Ctrl+n 相同,只是方向相反
|
||||||
|
3. Ctrl+x Ctrl+f - 文件名补全
|
||||||
|
- 在输入路径时自动补全文件名
|
||||||
|
4. Ctrl+x Ctrl+l - 整行补全
|
||||||
|
- 补全整行代码(从当前文件中查找相似行)
|
||||||
|
|
||||||
|
### 补全菜单
|
||||||
|
1. `c-n``c-p` 上下移动
|
||||||
|
2. `c-y` 确认
|
||||||
|
3. `c-e` 退出
|
Loading…
x
Reference in New Issue
Block a user