unordered_map 的排序

unordered_map是C++的哈希表结构, unorded_map并不能直接排序, 如果要排序,一般来说需要将unordered_map转换为vector再通过自定义排序函数使用sort进行排序。

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
bool cmp(pair<char, int>& a, pair<char,int>& b) {
return a.second > b.second; // 按照second降序
}

void sort_unordered_map() {
unordered_map<char, int> mp;

int idx = 1;
for(char c = 'a'; c <= 'z'; c++) {
mp[c] = idx++;
}

// 利用vector构造函数快速转换
vector<pair<char, int>> sorted_mp(mp.begin(), mp.end());

sort(sorted_mp.begin(), sorted_mp.end(), cmp);

// 此时可以选择直接使用排序后的vector或者再转换为哈希表
for(auto [a, b] : sorted_mp) {
cout << a << "" << b << endl;
}
}
阅读全文 »

二叉树的知识每次用都要重新复习一遍,所以索性写一篇博客加强记忆

二叉树的遍历有四种方式:前序遍历、中序遍历、后续遍历、层序遍历,下面主要通过递归和显式栈的方式来实现前中后序遍历, 层序遍历使用队列实现

前中后序遍历可以简便的记为: ‘中’的位置,即

​ 前序遍历为:中左右

​ 中序遍历为:左中右

​ 后续遍历为:左右中

阅读全文 »

文件描述符在Unix系统中是一个整数,用来标识打开的文件或者I/O资源,每个进程默认会打开三个标准文件描述符(File Descriptors, FDs),用于处理输入和输出。下面介绍这三个FD

  1. 标准输入(Standard Input)
    • 文件描述符编号0
    • 作用:用于进程读取输入数据(默认来自键盘输入)
    • 相关符号:在Shell中通常用 <<< 进行重定向(如 command < input.txt
  2. 标准输出(Standard Output)
    • 文件描述符编号1
    • 作用:用于进程输出正常结果(默认显示到终端)
    • 相关符号:在Shell中通常用 >>> 进行重定向(如 command > output.txt
  3. 标准错误(Standard Error)
    • 文件描述符编号2
    • 作用:用于输出错误或诊断信息(默认显示到终端)
    • 相关符号:在Shell中用 2>2>> 重定向错误(如 command 2> error.txt

阅读全文 »

使用strace工具追踪main.c的gcc编译过程及a.out的执行过程

追踪gcc编译过程

1
strace -o /dev/stdout gcc hello.c 2>&1 | vim -

将strace追踪信息利用|(管道) 传递给vim, 这边要注意的是strace的输出是直接发送到标准错误输出stderr, 而不是标准输出stdout, 所以用-o dev/stdout将输出写到标准输出中, 2>&1是将标准错误stderr(文件描述符2)重定向到标准输出stdout(文件描述符1)中, 详情见此处.

阅读全文 »

一些gcc常用的选项

  • -c: 只编译但不链接, 生成目标文件(.o), 无法识别的文件将被忽略; 原文:

Compile or assemble the source files, but do not link. The linking stage simply is not done. The ultimate output is in the form of an object file for each source file.

By default, the object file name for a source file is made by replacing the suffix ‘.c’, ‘.i’, ‘.s’, etc., with ‘.o’.

Unrecognized input files, not requiring compilation or assembly, are ignored.

  • -S : 将源代码编译成汇编代码,而不是直接生成机器代码或可执行文件。使用这个选项时,GCC会执行编译过程中的前几个步骤(如预处理、编译),但会停在生成汇编代码这一步,不会进一步进行汇编成目标代码或进行链接。

  • -E: -E选项用于仅执行预处理步骤。GCC会处理源代码中的预处理指令,如宏定义的扩展、条件编译指令的处理、包含文件的插入等,但它不会编译、汇编或链接代码。注意: 默认情况下,这个输出会直接发送到标准输出(即屏幕), 所以可以使用|传到vim或者其他编辑器中查看:

    1
    gcc -E helloworld.c | vim -  
  • -o: 这一部分强烈推荐看原文, -o选项允许指定主输出文件的名称和位置,这适用于任何类型的输出,无论是可执行文件、目标文件、汇编文件还是预处理的C代码。

    阅读全文 »

concat 是一个常见的宏编程技术,用于将两个或多个预处理器标记(通常是宏参数或宏定义)连接(concatenate)成一个单一的标记, 通常通过使用预处理器的 ## 操作符实现,该操作符用于连接两个标记。

`Concat`宏的基本用法

假设有一个 concat 宏定义如下:

1
#define concat(a, b) a ## b

这里,## 操作符会将它的两个参数 a 和 b 连接成一个单一的标记。

阅读全文 »

原文

some notes:

返回值: main()的返回值应该是int, 而不是void. 虽然在一些编译器中,void main()可以通过编译,但并非所有编译器都支持 void main(),因为标准中从来没有定义过 void main 。

main返回值类型:
main返回值类型

main()函数传参

1
int main(int argc , char* argv[],char* envp[]); 

参数说明:

①、第一个参数argc表示的是传入参数的个数 。

②、第二个参数char* argv[],是字符串数组,用来存放指向的字符串参数的指针数组,每一个元素指向一个参数。各成员含义如下:

argv[0]:指向程序运行的全路径名。

argv[1]:指向执行程序名后的第一个字符串 ,表示真正传入的第一个参数。

argv[2]:指向执行程序名后的第二个字符串 ,表示传入的第二个参数。

……argv[n]:指向执行程序名后的第n个字符串 ,表示传入的第n个参数。

规定:argv[argc]为NULL ,表示参数的结尾。

阅读全文 »

在读nemu/src/monitor/monitor.c中遇到了这个函数,原文如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
static inline void parse_args(int argc, char *argv[]) {
const struct option table[] = {
{"batch" , no_argument , NULL, 'b'},
{"log" , required_argument, NULL, 'l'},
{"diff" , required_argument, NULL, 'd'},
{"port" , required_argument, NULL, 'p'},
{"help" , no_argument , NULL, 'h'},
{0 , 0 , NULL, 0 },
};
int o;
while ( (o = getopt_long(argc, argv, "-bhl:d:p:", table, NULL)) != -1) {
switch (o) {
case 'b': batch_mode = true; break;
case 'p': sscanf(optarg, "%d", &difftest_port); break;
case 'l': log_file = optarg; break;
case 'd': diff_so_file = optarg; break;
case 1:
if (img_file != NULL) Log("too much argument '%s', ignored", optarg);
else img_file = optarg;
break;
default:
printf("Usage: %s [OPTION...] IMAGE\n\n", argv[0]);
printf("\t-b,--batch run with batch mode\n");
printf("\t-l,--log=FILE output log to FILE\n");
printf("\t-d,--diff=REF_SO run DiffTest with reference REF_SO\n");
printf("\t-p,--port=PORT run DiffTest with port PORT\n");
printf("\n");
exit(0);
}
}
}
阅读全文 »

开天辟地的篇章

从状态机视角理解程序运行

1
2
3
4
5
6
7
// PC: instruction    | // label: statement
0: mov r1, 0 | pc0: r1 = 0;
1: mov r2, 0 | pc1: r2 = 0;
2: addi r2, r2, 1 | pc2: r2 = r2 + 1;
3: add r1, r1, r2 | pc3: r1 = r1 + r2;
4: blt r2, 100, 2 | pc4: if (r2 < 100) goto pc2; // branch if less than
5: jmp 5 | pc5: goto pc5;

Q:画出这个程序的状态机

需要更新的状态只包括PC,r1和r0,所以用三元组表示程序的所有状态:

(0, x, x) -> (1, 0, x) -> (2, 0, 0) -> (3, 0, 1) -> (4, 1, 1) -> (2, 1, 1) -> (3, 1, 2) -> (4, 3, 2) -> … -> (2, 4851, 98) -> (3, 4851, 99) -> (4, 4950, 99) -> (2, 4950, 99) -> (3, 4950, 100) -> (4, 5050, 100) -> (5, 5050, 100)

  • Thoughts : 如果不是实验中给出了初始的(0, x, x) -> (1, 0, x) -> (2, 0, 0) -> .. , 以我的感觉我极有可能会写(0, 1, x) -> (1, 0, 0) -> .. 我的逻辑是在pc0的时候,r1赋值为0了, 但是在状态机中表示的是一个瞬间的状态所以在pc0的时候, r1还没有被赋值,所以上面的(0, x, x)是对的
阅读全文 »

Linux 命令总结

文件管理

  • cd <directory>: 更改当前工作目录到指定的目录。
  • pwd: 显示当前工作目录的完整路径。
  • mkdir <directory>: 创建一个新目录。
  • rmdir <directory>: 删除一个空目录。如果目录非空,使用rm -r <directory>
  • ls [options] [file]: 列出目录内容。
    • -l: 长格式列出信息。
    • -a: 列出所有文件,包括隐藏文件。
    • -h: 与-l一起使用时,以易读的方式显示文件大小。
  • cp [options] <source> <destination>: 复制文件或目录。
    • -r--recursive: 递归复制目录及其内容。
    • -i--interactive: 在覆盖文件之前提示用户确认。
    • -v--verbose: 显示详细信息。
  • rm [options] <file>: 删除文件或目录。
    • -r--recursive: 递归地删除目录及其内容。
    • -f--force: 强制删除,不提示确认。
  • mv [options] <source> <destination>: 移动或重命名文件或目录。
  • tar [options] <filename> [files]: 用于归档文件,同时可对文件进行压缩或解压。
    • -c: 创建归档。
    • -x: 从归档中提取文件。
    • -z: 通过gzip进行压缩或解压。
    • -v: 显示被处理的文件名。
    • -f: 指定归档文件的名称。
      阅读全文 »
0%