追过很多新技术,迷茫于还有太多东西要学,有些找不到方向、不知所措。常在一个叫酷壳的网站上转悠,渐渐想明白了,其实学习技术也像看电影看书一样,要看就看经典的。我们的生命如此短暂,作为程序员的职业生涯可能会更短。与其追逐各种新潮的技术,不如把有限的精力投入到经典的技术之中。
追过很多新技术,迷茫于还有太多东西要学,有些找不到方向、不知所措。常在一个叫酷壳的网站上转悠,渐渐想明白了,其实学习技术也像看电影看书一样,要看就看经典的。我们的生命如此短暂,作为程序员的职业生涯可能会更短。与其追逐各种新潮的技术,不如把有限的精力投入到经典的技术之中。
lower = 0;
upper = 50;
step = 10;
printf(“%s\t%s\n”, “Celsius”, “Fahr”);
celsius = lower;
while (celsius <= upper) {
fahr = celsius * 9.0 / 5.0 + 32.0;
printf(“%3.0f\t%6.1f\n”, celsius, fahr);
celsius = celsius + step;
}
}
int c;
while ((c = getchar()) != EOF) {
if (c >= ‘a’ && c <= ‘z’)
++freq[c - 'a'];
}
int i, j;
for (i = 0; i < 26; ++i) {
printf(“%c:\t”, ‘a’ + i);
for (j = 0; j < freq[i]; ++j)
putchar(‘*’);
putchar(‘\n’);
}
}
int getline2(char line[], int maxline); //与stdio.h中的getline冲突
main()
{
int len;
char line[MAXLINE];
while ((len = getline2(line, MAXLINE)) > 0)
if (len > 80) {
printf(“%s\n”, line);
}
return 0;
}
// locate last letter
while (i >= 0 && (s[i] == ‘ ‘ || s[i] == ‘\t’))
–i;
if (i >= 0) {
++i;
s[i] = ‘\n’;
++i;
s[i] = ‘\0′; // terminate the string
}
return i;
}
j = 0;
while (s[j] != ‘\0′)
++j;
char temp;
for (i=0,j=j-1; i<j; ++i,–j) {
temp = s[i];
s[i] = s[j];
s[j] = temp;
}
}
main()
{
char s[] = “abcdefg”;
reverse(s);
printf(“%s\n”, s);
char s2[] = “123456″;
reverse(s2);
printf(“%s\n”, s2);
return 0;
}
WndProc函数传回一个型态为LRESULT的值,该值简单地被定义为一个LONG。WinMain函数被指定了一个WINAPI型态(在表头文件中定义的所有Windows函数都被指定这种型态),而WndProc函数被指定一个CALLBACK型态。这两个标识符都被定义为_stdcall,表示在Windows本身和使用者的应用程序之间发生的函数呼叫的呼叫参数传递方式。
typedef WCHAR * PWCHAR, * LPWCH, * PWCH, * NWPSTR, * LPWSTR, * PWSTR ;
1. 从Verycd下载压缩包[Mac.OSX操作系统].Mac.OS.X.Lion.10.7.2.Vmware.Workstation.8.With.iReSign.zip
2. 按照里面的Readme.txt的说明,首先安装Vmware 8,已附上序列号。
3. 重启机器并在进程管理器里停掉所有Vmware服务,大概五六个。
4. 拷贝压缩包里的补丁文件夹到C盘(如果Vmware装在C盘的话)。
5. 已管理员权限运行CMD.exe,并执行补丁中的install.cmd。
6. 重启机器后打开Vmware,并导入Mac OS虚拟机。
count的4个元素的存储空间也是相邻的。结构体成员可以是基本数据类型,也可以是复合数据类型,数组中的元素也是如此。根据组合规则,我们可以定义一个由4个结构体元素组成的数组:count[-1]或是count[100]这样的访问越界错误,编译时能顺利通过,所以属于运行时错误。但有时候这种错误很隐蔽,发生访问越界时程序可能并不会立即崩溃,而执行到后面某个正确的语句时却有可能突然崩溃(在第 4 节 “段错误”我们会看到这样的例子)。count[-1]这种技巧其实并不少见,不应该当作错误。)a = b这个表达式,a和b都是数组类型的变量,但是b做右值使用,自动转换成指针类型,而左边仍然是数组类型,所以编译器报的错是error: incompatible types in assignment。int i;
for (i = 0; i < 10; i++) {
array2[i] = array1[i];
}
for (i = 0; i < 10; i++) {
printf(“%d, “, array2[i]);
}
return 0;
}
rand函数,使用这个函数需要包含头文件stdlib.h,它没有参数,返回值是一个介于0和RAND_MAX之间的接近均匀分布的整数。RAND_MAX是该头文件中定义的一个常量,在不同的平台上有不同的取值,但可以肯定它是一个非常大的整数。srand函数指定Seed。通常我们通过别的途径得到一个不确定的数作为Seed,例如调用time函数得到当前系统时间距1970年1月1日00:00:00的秒数,然后传给srand:rand,得到的随机数就和刚才完全不同了。调用time函数需要包含头文件time.h,这里的NULL表示空指针。rand函数生成[10, 20]之间的随机整数,表达式应该怎么写?main函数,以可视化的形式打印直方图。int i, histogram[UPPER] = {0};
for (i = 0; i < N; i++)
histogram[a[i]]++;
for (i = 0; i < UPPER; i++)
printf(“%d\t”, i);
printf(“\n”);
do { // 实际上只可能循环N次,因此外层while循环可改为for 0-> N-1,变量breakLoop也可以省了
int breakLoop = 1;
for (i = 0; i < UPPER; i++) {
if (histogram[i] > 0) {
printf(“%c\t”, ‘*’);
histogram[i]–;
breakLoop = 0;
} else {
return 0;
}
N个数中取M个数做组合而不是做排列,就不能用原来的递归过程了,想想组合的递归过程应该怎么描述,编程实现它。'\0'做结束符,这里的\0是ASCII码的八进制表示,也就是ASCII码为0的Null字符,在C语言中这种字符串也称为以零结尾的字符串(Null-terminated String)。数组元素可以通过数组名加下标的方式访问,而字符串字面值也可以像数组名一样使用,可以加下标访问其中的字符:printf会从数组str的开头一直打印到Null字符为止,Null字符本身是Non-printable字符,不打印。str中没有Null字符,那么printf函数就会访问数组越界,后果可能会很诡异:有时候打印出乱码,有时候看起来没错误,有时候引起程序崩溃。图 8.3. 多维数组

图 8.4. 多维字符数组

case、printf和break,如果漏写一个break就要出Bug。这个程序之所以简洁,是因为用数据代替了代码。具体来说,通过下标访问字符串组成的数组可以代替一堆case分支判断,这样就可以把每个case里重复的代码(printf调用)提取出来,从而又一次达到了“提取公因式”的效果。这种方法称为数据驱动的编程(Data-driven Programming),写代码最重要的是选择正确的数据结构来组织信息,设计控制流程和算法尚在其次,只要数据结构选择得正确,其它代码自然而然就变得容易理解和维护了,就像这里的printf自然而然就被提取出来了。(man - computer + 4) % 3 - 1这个神奇的表达式是如何比较出0、1、2这三个数字在“剪刀石头布”意义上的大小的?
1. 并发编程
随着单机上CPU核数的不断增多,以及互联网中大型网站每天产生的海量数据,并发编程将会成为程序员必不可少的技能。
学习《Erlang程序设计》和Scala,理解函数式编程,搞清Actor模式以及并发编程的消息传递方式。
2. 汇编语言
懂一些计算机底层的知识才会明白咱们每天使用的计算机硬件是怎样运行的,操作系统是怎样启动的,写好的源代码是怎样编译成机器码被操作系统加载的。
学习《汇编语言》(第二版)、《80×86汇编语言程序设计教程》,了解计算机的构造CPU、内存、硬盘等,搞明白CPU是怎样寻址,什么是保护模式,保护模式和实模式有什么不同。
另外推荐《程序员的自我修养》、《天书夜读-从汇编语言到Windows内核编程》、《琢石成器:Windows32位汇编语言程序设计》。
3. 操作系统内核
Linux内核源码很多,里面包含很多算法和设计,学习起来真的很难。但挑重点的学习了解一下,对提高编程水平还是有很大帮助的。比如操作系统怎样通过Loader加载,进程的切换和调度等。
学习Linux四库全书:《Linux内核设计与分析》、《深入理解Linux内核》、《Linux内核源代码情景分析》、《Linux设备驱动开发》。再推荐一本《Orange’s 一个操作系统的实现》。
最重要的一点:read the fucking source code!
4. 游戏开发
游戏尤其是3D游戏开发是学习数学和算法的一个好途径,由于3D游戏通常很耗费资源,因此也是学习代码优化的好方法。比如怎样渲染图形的表面,怎样把空间坐标上的3D图形是怎样通过矩阵运算投射到摄影机屏幕上的,比如学习分析计算关键代码段的大O值并试着优化。
推荐《3D数学基础:图形与游戏开发》,以及DirectX的学习。
5. 数学和算法
这是编程的基础,编程一路学到底层东西时,自然而然就想补一补自己的数学和算法知识。
数学:《什么是数学》、《具体数学》。
算法:《计算机程序设计艺术》、《算法导论》。
通过做题检验自己,书后习题以及各大公司的笔试题。带着问题去看这些书,也许会增加一些动力。
6. 散文杂文
学累了,该放松一下了。
《代码之美》、《Java夜未眠》、《Unix编程艺术》、《疯狂的程序员》
看着看着就睡着了,梦到有一天自己成为武林中的编程高手。。。
if语句、while语句中的控制表达式的值也不能是结构体类型。main函数测试本节的所有代码。想一想这个打印函数应该属于上图中的哪一层?rational以及相关的函数,rational结构体之间可以做加减乘除运算,运算的结果仍然是rational。注意要约分为最简分数,例如1/8和-1/8相减的打印结果应该是1/4而不是2/8,可以利用第 3 节 “递归”练习题中的Euclid算法来约分。if (abs(a.x) > abs(a.y)) {
gcdnum = gcd(abs(a.x), abs(a.y));
} else {
gcdnum = gcd(abs(a.y), abs(a.x));
}
a.x = a.x / gcdnum;
a.y = a.y / gcdnum;
return a;
RECTANGULAR就表示常量0,POLAR表示常量1。如果不希望从0开始分配,可以这样定义:case分支的判断条件。