然后,这里推荐一本书,Ask the Right Questions: A Guide to Critical Thinking,《学会提问:批判性思维指南》。
关于逻辑,关于批判性思维,我有太多的话要说,但我怕说的太多,就不多说了。《学会提问》这本书会告诉你“是什么、为什么、怎么做”。对于这代人,这本书试图教给你一些我们的教育本该教给你却没有教给你的东西。
什么是shell自己版本的echo呢?原来,shell中可以使用的命令有“内建命令”(built-in)和外部命令之分。内建命令有shell本身实现,即和shell进程同属于一个地址空间执行,比如echo可能是shell中的一个函数实现的。内置命令通常是无法或者不适以外部命令的形式实现的命令,比如cd, source, alias, bind, history, set等等。外部命令是一些独立的可执行文件,由shell以fork/exec的形式执行。
使用type命令可以获取命令的类型。由type type可以知道type命令本身也是内建命令。
知道这些,通过–help选项输出echo的帮助信息就不是什么难事了,
1 2 3 4 | ~$ which echo /bin/echo ~$ /bin/echo --help ...... |
多数情况下,咱们编辑文档是逐行进行的。偶尔我们可能还需要按列编辑,比如项目编号,比如只有若干列不同的多行文本等。Vim为列模式编辑提供了比较“简洁”的支持,即可视化文本块(Visual Block)模式,它是三种可视化模式的一种(一种使用命令v按字符选取区域,一种使用命令V按行选取区域,另外一种就是这里的按矩形块选取区域,使用命令Ctrl-v)。例如,现在想要把一段C++代码中连续几行(比如3行)代码的某一列后面的部分注释掉,我们要做的就是把光标定位到该列,按下Ctrl-v,按两下j使该列3行高亮显示,再按下I,输入C++注释符//,然后按退出键
但,简单的Vim命令的功能也仅限于此。若想完成更复杂的功能,就不得不动用高级一点的技巧了。比如为文档的每一行加上行号可以使用命令
:g/^/s//\=line(".")/ " 等价于:g/^/s/^/\=line(".")/ |
解释一下:
- :g/pat/,命令g查找模式pat(此处为^,行首,即每一行都会匹配),为每一个匹配行执行接下来的命令;
- s/pat/str/,命令s在当前行查找模式pat,并使用str替代之;
- \=,指示此处的字符串将由接下来的表达式的产生;
- line(expr),函数line返回由字符串expr指示的行号,”.”代表当前行。
调试内存转储文件。内存转储文件(core dump)是程序发生严重错误时操作系统产生的文件,它包含了程序崩溃时占用的内存页面的拷贝,因此使用core文件在一定程度上可以再现崩溃前夕程序的状态。
多种原因下程序会崩溃,从而被系统终止,生成core文件,经常见到的是访存错误(段错误,Segment fault)。另外,系统是否生成core文件以及core文件的最大尺寸还受系统参数的控制。例如ubuntu下面普通用户程序是不允许生成core文件的,这可以使用ulimit命令来修改。不带参数的ulimit -c输出当前core文件的最大允许值,为了能够生成core文件,使用ulimit -c size设置大小,简单地,ulimit -c unlimited将其设为没有限制。
1 2 3 4 5 6 7 8 9 10 | void foo(const char* s) { char c = *s; } int main() { foo(0); return 0; } |
列位安好。简单总结下GDB调试器的使用。
准备
默认情况下,gcc/g++编译的可执行文件是不包含调试信息的,GDB是一个源代码级的调试器,使用GDB调试程序需要程序的源代码、符号及其对应的行号等,其中符号和行号可以是单独的文件,亦可以在编译时嵌入到可执行文件中。使用gcc/g++时使用-g选项即可将必要的调试信息包含到可执行文件中,使用-g3选项还可以将源代码中的宏信息也包含进去。
另外,调试过程中需要随时查看源代码,但源代码并没有包含到可执行文件中。通常GDB在当前目录查找源文件,但某些情况下(比如调试系统命令)需要手动指明源代码的查找目录,directory ~向GDB指明到$HOME下查找源文件。
启动
GDB的启动很灵活,它的各种特性,你可以在Shell下通过选项和参数指定,也可以在GDB启动之后在GDB自己的命令行下使用GDB内置的命令来指定。最常用的是直接使用命令gdb PROGRAM启动,这样gdb自动加载符号表等调试信息。若要向被调试程序传递参数,可以采用gdb –args program ARG1 ARG2的形式,其中–args(或者-args)是必须的,它告诉GDB该选项之后已经没有GDB需要的选项了。另外,还可以直接使用gdb启动,然后使用file program加载调试信息。此时若要设置被调试程序的参数,可以使用set命令的args子命令,如set args ARG1 ARG2. 还有一种传递参数的方法,在下面介绍。
列位,近来俺系统地学习了一下shell编程,好家伙,那可不是一般的纷繁琐碎啊,可谓陷阱重重,防不胜防。摸索中,遇到这个页面,总结了Bash编程中的很多陷阱及必要的解决技巧。在这里,结合这本GNU Bash Reference Manual,我有选择地简要地把这些个Pitfalls给您用百姓喜闻乐见的中文展示出来。由于能力有限,我也不是专职的系统管理员,肯定不能详尽地把所有问题都解释清楚,我本人也觉得没有这个必要。仅供参考而已,欢迎指正和补充。
1 2 3 4 5 6 | for i in *.mp3 do COMMANDS done # 单行形式就是for i in *.mp3; do COMMANDS; done # ;只是起到命令和关键字间的分割符的作用,完全可以用换行符来代替 |
不多说,都在代码里了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #include <stdio.h> int main(int AC, char **AV) { FILE *fd = fopen("data", "w+"); fprintf(fd, "%x%c", 0x41, '1'); fseek(fd, 0, SEEK_SET); int n; fscanf(fd, "%d", &n); fseek(fd, 0, SEEK_SET); char s[4]; int c = fread(s, 1, sizeof(s), fd); s[c] = '\0'; printf("%d, %s\n", n, s); fclose(fd); return 0; } |
简单实现了常见的几种内部排序算法,包括冒泡(Bubble),插入(Insert),快速排序(Quick Sort),堆排序(Heap Sort),归并(Merge),希尔排序(Shell Sort),并对这些算法的耗时在伪随机数上进行了简单的测试。
说明:
- 没有实现计数、基数排序等线性复杂度的算法;
- 各算法只是对算法思想的一次简单模拟,没有过多的优化;
- 各排序主程序接口参数均为整型数组及元素个数;
- 程序计时使用了glibc的gettimeofday(),因此。。。;
- 归并排序中,每次调用都申请和释放堆空间,因此比较耗时。可以采用原地归并、使用全局/静态的方法加以优化;
- 快速排序中,对待排子序列的长度进行的了判断,对短序列进行优先排序可以减小函数的递归深度(而不是次数);
- 希尔排序中,为了简洁,步长因子统一取做2.2(11/5)。
写程序时,尤其在C/C++程序中,有大量的配对的符号(surrounding):( ), [ ], { }, < > ‘ ‘, ” “,另外标记语言(如XML)更是由无数的配对标记组成:
. 如果能够快速地处理这些surroundings,就能大大提升编程的效率。
Vim本身就有这种配对符号的能力,在Vim中这叫做text object,可以使用:h text-objects查看这些text objects。你会发现Vim只能对这些配对符所包含的文本或者整个text object进行删除和修改,却不能对surrounding进行修改,更不能为普通文本添加surrounding。
既然有这种需求,就肯定会有热心人士努力,来满足这种需求,方便了自己,也方便了整个Vim用户群。Tim Pope同志就为Vim写了这款插件,surround.vim:
This plugin is a tool for dealing with pairs of “surroundings.” Examples of surroundings include parentheses, quotes, and HTML tags. They are closely related to what Vim refers to as |text-objects|. Provided are mappings to allow for removing, changing, and adding surroundings.
在StackOverflow上面看到的,分析一下下面的代码,对初学者理解什么是堆,什么是栈,对象是如何拷贝的有所帮助。
1 2 3 4 5 6 7 8 9 10 11 12 13 | #include <stdio.h> typedef struct node { int i; struct node *next; }node; node getnode(int a) { struct node n; n.i=a; n.next=NULL; return n; } |