星海's Blog

老头初学编程

求2的N次方(要求,最简算法复杂度为lgn)

 

/*
 * =========================================================================
 *
 *       Filename:  mypow.c
 *
 *    Description:  编写一个函数double mypow(double x, int n);
 *    求x的n次方,参数n是正整数。算法复杂度考虑lgn。  !!递归版
 *
 *        Created:  2010年12月05日 17时20分36秒
 *       Compiler:  gcc
 * ==========================================================================
 */
#include <stdio.h>

double mypow(double x, int n)
{
	if (n == 0)
		return 1;
	if (n == 1)
		return x;
	if (n % 2 != 0)
		return x * mypow(x, n - 1);
	else
		return mypow(x*x, n / 2);
}

int main(void)
{
	printf("%f\n", mypow(2, 11));
	return 0;
}
#include	<math.h>
#include	<stdio.h>
#include    <stdio.h>
#include    <math.h>

double mypow(double x, int n)
{
	double result = 1.0;
	if (n == 0)
		return 1;
	while (n) {
		if (n & 1)
			result *= x;
		x *= x;
		n >>= 1;
	}
	return result;
}

int main(void)
{
	for (int i = 0; i < 16; i++)
		printf("%-2d: mypow: %-10.0f \t pow:%-10.0f\n", i,
		       mypow(2, i), pow(2, i));
	return 0;
}

 

折半算法

 

/*
 *       Filename:  binary.c
 *    Description: 从一组排序好的序列里找出某个元素的位置(折半查找) 
 * ==========================================================================
 */
#include <stdio.h>
#define LEN 8

int a[LEN] = { 1, 2, 2, 5, 5, 6, 8, 9 };

int binary(int number)
{
	int mid, start = 0, end = LEN - 1;

	while (start <= end) {
		mid = (start + end) / 2;
		if (a[mid] < number)
			start = mid + 1;
		else if (a[mid] > number)
			end = mid - 1;
		else {
			while (a[mid] == number) {
				--mid;
			};	//返回最早出现的匹配位值
			return mid + 1;
		}
	}
	return -1;
}

int main(void)
{
	printf("%d\n", binary(2));
	return 0;
}

 

算法相关的网址

http://zh.wikipedia.org/zh-cn/Category:%E7%AE%97%E6%B3%95

 

http://en.wikipedia.org/wiki/Category:Algorithms

有问题的汇编程序(不知错在哪里)

bios设置为用软盘启动,通过软盘第一扇区内容引导硬盘第一扇区至0:7c00h处,然后引导硬盘系统

 

 

~\桌面\STARTSYS.ASM.html
 1 assume cs:codesg
 2 stack segment
 3     db 32 dup (0)
 4 stack ends
 5 
 6 codesg segment
 7 start:
 8     mov ax,stack
 9     mov ss,ax
10     mov sp,32
11 
12     push cs
13     pop ds
14     mov si,offset starsys ;cs[si]指向starsys段
15 
16     mov ax,0
17     mov es,ax
18     mov di,200h ;es:[di]指向0:200h内存
19 
20     mov cx,offset starsysend-offset starsys
21     cld
22     rep movsb ;将starsys段内容复制到0:200h
23 
24     mov ax,0
25     mov es,ax
26     mov bx,200h
27 
28     mov al,1
29     mov ch,0
30     mov cl,1
31     mov dl,0
32     mov dh,0
33 
34     mov ah,3
35     int 13h  ;调用13h中断,将0:200内容复制到软盘第一扇区
36 
37     mov ax,4c00h
38     int 21h
39 
40 starsys:
41     mov ax,0
42     mov es,ax
43     mov bx,7c00h  ;开机时,系统用0:7c00h存放启动设备第一扇区
44 
45     mov al,1
46     mov ch,0
47     mov cl,1
48     mov dl,80h
49     mov dh,0
50     mov ah,2
51     int 13h ;读取硬盘第一扇区至0:7c00h
52 
53     mov ax,0
54     push ax
55     mov ax,7c00h
56     push ax
57     retf  ;将cs,ip改为0:7c00
58 
59 starsysend:nop
60 
61 codesg ends
62 end start
63 

王爽《汇编语言》程序设计1

 

assume cs:codesg 
data segment 
db '1975','1976','1977','1978','1979','1980','1981','1982','1983' 
db '1984','1985','1986','1987','1988','1989','1990','1991','1992' 
db '1993','1994','1995' 
dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514 
dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000 
dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226 
dw 11542,14430,15257,17800 
data ends 
 
tablestr segment
db 840 dup (' ')
tablestr ends
 
stack segment
dw 16 dup (0)
stack ends
 
codesg segment
start:
mov ax,data
mov es,ax
mov di,0
 
mov ax,stack
mov ss,ax
mov sp,32
 
mov ax,tablestr
mov ds,ax
mov si,0
mov bx,0
 
mov cx,21
 
s: mov ax,es:[di] 
mov ds:[si],ax 
mov ax,es:2[di] 
mov ds:2[si],ax 
                 
mov ax,es:54h[di] 
mov dx,es:56h[di] 
add si,10
call dwtoc
sub si,10
     
div word ptr es:0a8h[bx]
  mov dx,0
add si,31
call dwtoc
mov byte ptr ds:5[si],0
sub si,31
          
mov ax,es:0a8h[bx] 
mov dx,0
add si,20
call dwtoc
sub si,20
 
 
add si,40
add di,4
add bx,2
    
loop s
 
mov cx,21
mov dh,3
mov si,0
mov dl,5
mov bx,0
 
s0: push cx
mov cl,4ah
call show_str
inc dh
add si,40
pop cx
loop s0
 
  mov ax,4c00h
int 21h
 
;将dword型数据转为十进制ascii码形式
;ax为例
dwtoc: push cx
push dx
push di
push si
push ax
push bx
mov di,0
dtoc: push ax
mov cx,10
mov ax,dx
mov dx,0
div cx
 
mov bx,ax ;bx为除法结果的高十六位
pop ax
div cx
 
push dx ;余数压栈
mov dx,bx ;此时ax除法结果低十六位,dx为高十六位
 
mov cx,ax
add cx,bx
inc di
jcxz reverse
jmp short dtoc
 
reverse:mov cx,di
 
dtocs: pop bx
add bl,30H
mov byte ptr ds:[si],bl
inc si
loop dtocs
 
dec si
;mov byte ptr ds:[si],0
pop bx
pop ax
pop si
pop di
pop dx
pop cx
ret
 
show_str:push cx 
push si 
push ax 
push di 
push es 
push dx  ;全部压栈   
mov ax,0b800h  ;0页显示 
mov es,ax 
               
mov al,0a0h 
mov ah,0 
mul dh    
;此时ax中存放dh行数的字节数 
mov dh,0 
add dl,dl 
add ax,dx 
mov di,ax 
;di存放显示代码所在的偏移值                 
      mov ah,cl
                                           
display:mov cl,ds:[si] 
mov ch,0 
jcxz short strover 
mov al,ds:[si] 
mov es:[di],al 
inc di 
mov byte ptr es:[di],ah 
inc di
inc si
      jmp short display 
                 
strover:pop dx
pop es
pop di
pop ax
pop si
pop cx
ret
 
codesg ends
end start
 

漫谈C语言及如何学习C语言(转)

 

漫谈C语言及如何学习C语言

云风最近写了一篇博客《C语言的前世今生》。作为长期使用C语言开发网络游戏服务器的程序员,云风是有理由写这样一篇文字,不过还是感觉谈的不够深入,C语言在业界使用的现状没有怎么描写,有些意犹未尽。

为什么要学习C语言?

为什么要学习、使用C语言?为什么要学习一个可能比自己都岁数大的编程语言?

我在前面如何学习编程语言的博客文章http://sunxiunan.com/?p=1597 里提到,选择一门编程语言,“为什么而学”这个目的是最重要的,目的不明确就没法学好。这也是为什么很多学生朋友在大学里必修C语言却觉得没学明白的原因。因为学习的目的不明确,学习当然也没有动力。还有一个原因是C语言是工程实践性很强的语言,它不是来自某个研究所某个大学学院,而是实实在在从项目需要中产生,伴随着Unix的兴起而流行,语义简明清晰,功能强大而不臃肿,简洁而又不过分简单,实在是居家旅行工作学习必备之良友。

C语言相比C++的优点之一就是最小惊讶原则,一是一二是二,不会在私底下产生一些莫名其妙的额外产物。用C++做个例子,比如这样一个函数原型void PassWithClassValue(COneClass clsParam1),稍微了解C++的朋友都会知道,如果你没有实现COneClass的拷贝构造函数,编译器会好心的帮你实现一个,而且在调用这个函数PassWithClassValue的时候,偷偷地调用拷贝构造函数产生一个临时对象作为参数传递,对于某些情况,比如编写操作系统这类必须优化性能的情景下,这些自以为是的东西是非常邪恶的事情。

C语言本身只提供必要的语言特性,其它复杂一点功能如文件处理、数学计算等等都以库函数方式提供,甚至连malloc、free这种“必须有”的功能,也是以标准库函数的方式提供,而不是作为C语言核心出现。在伟大的著名的无所不包的《K&R》开头部分就提到了,for其实可以通过while来完成,只不过for可以写的更简洁,言外之意,对于C语言for其实不是必要的。跑题一点说,在其它程序语言中Lua可以说继承了C语言简洁的设计哲学,甚至连continue这种几乎必备的关键字都一直拒绝加入,在Lua的maillist以及wiki里都提到过continue这个问题,Lua语言维护者认为continue对于Lua而言不是必要的,也不考虑在后续版本中添加这个关键字。这种简洁哲学也让C语言的可移植性、便携性特别优秀,也使得很多嵌入式系统依然使用C语言作为主要编程工作语言。

Java语言有一个口号:“一次编写,处处运行”,就是跨平台这个噱头。实际上C语言从早期开始就几乎达到了“一次编写,处处编译”,在ANSI在1989年统一了C语言标准以后(称之为C89),只要特定平台上的编译器完整实现了C89标准,而且你的代码没有使用某些特殊的扩展(GCC以及微软都有自己的编译器特定扩展),那么代码一定可以编译通过,再实现一下操作系统相关的函数库,C语言的移植就是很简单的事情。可以用Lua作为例子,Lua本身是完全遵循C89标准,没有使用任何特定扩展,这也保证了有C语言编译器的平台,都可以编译使用Lua。可以编译运行C语言的硬件平台可以从A排到Z,真是非常有意思的事情。

C语言也是一个比较少见的应用领域极为广泛的语言。比如编写操作系统这种高难问题,只有C++、汇编语言可以做到。C语言可以编写服务器端软件如Apache、Nginx,或者编写GUI程序,如GTK。大多数程序语言的第一版是通过C语言实现,借助前面提到的“一次编写处处编译”,最大的保证了这些程序语言的可移植性。在Web开发领域,C语言的应用相对较少,这也是一种取舍的结果,Web开发需要使用PHP、Ruby、Python这样的动态语言,可以快速上线快速修改,可以最大程度满足用户时时变化的需求,这也是C语言的弱项。如果把程序语言的应用领域从硬件到管理软件、Web程序做一个很粗略从下到上的排列,C语言适合领域是比较底层靠近硬件的部分,而新兴语言比较偏重于高层管理或者Web开发这种相对贴近最终用户的领域。比较流行的混合开发模式是使用C语言编写底层高性能部分代码或后台服务器代码,而使用动态语言如Python做前端开发,充分发挥它们各自的优势力量。

提到C语言的缺点,常常是它缺少这种或者那种特性,比如有人建议加入GC,有人建议加入并行或者并发支持,有人提到没有一个比较完整的类似C++的异常策略。这些特性有的可以通过引入第三方库来实现,但C语言的设计哲学其实决定了它不会像C++那样“非常强大”。即使引入了某些人期望的特性,依然会是某些人喜欢某些人不喜欢的情形,现在的功能对于C语言应用领域来说已经够用,其它特性可以通过特定程序语言实现,并且通过C API与C语言编写的程序进行交互。任何一个工匠都不可能只使用一个工具完成他的工作,不同工具结合起来才能更快更好的完成任务。

提到C API,也稍微介绍一下,我们知道windows操作系统的api也好,Linux的系统api也好,或者是想给Ruby、Python编写扩展模块,C语言形式的函数定义都是唯一的选择。C语言就好像是一个中间层或者是胶水,如果想把不同编程语言实现的功能模块混合使用,C语言是最佳的选择。

提了这么多关于C语言的好处,那么学习C语言是否适合就看你自己的判断了,例如要进行一个嵌入式项目,或者需要进行服务器端开发,或者写一个性能相关的组件等等,C语言都是比较好用的选择。另外也可以在C++的使用过程中有意的使用C语言的思考方式,汲取C语言简洁明快清晰地设计思路,对编程设计水平会有很大的提高。

C语言学习方法

在前面http://sunxiunan.com/?p=1597 曾经提到过一个比较系统学习一门新的编程语言的方式,C语言学习也可以按照类似的顺序:阅读参考书,阅读代码,编写调试实际程序,上网参与讨论,研究高级话题。

学习语言的开始一般是阅读参考书。我建议选择几本非常经典的好书,仔细完整反复阅读几遍,“书读百遍其义自现”。选择C语言学习的好处是,这几本书基本上完整涵盖了C语言编程领域的方方面面,不会像C++那样,即使读完一堆书还是有些糊涂,依然有这样那样难懂的陷阱。

1,参考书籍

在豆瓣上列了一个书单,大家可以直接参考http://book.douban.com/doulist/636329/

在下面简单点评一下,阅读顺序最好参照列出的顺序。

《The C Programming Language》http://book.douban.com/subject/1230004/

image

如果你只想买一本书学习C语言,只需要买这一本就够了。如果你经费足够,建议你多买几本,办公室、家里都放上一本,随手都可以翻翻。用三个词语来形容它就是:经典!经典!经典!这本薄薄的只有二百多页的小书涵盖了C语言的方方面面,前无古人而且后无来者,任何溢美之词都不足以形容它。

《The C Programming Language》(后面称为 K&R)里面包含了一个简单的语法解析器,包含了malloc如何实现,包含了一个完整的操作系统目录浏览程序,这些程序的实用性极高,可以这样说,如果学习任何一门语言能够自己独立动手实现以上的功能,基本上就可以算是入门了。K&R书里面每段都蕴含着非常值得探究的软件开发工程实践经验,如果没有一定的开发经验,其实是看不出来这些冰山下面的内容的,比如开头一章就提出用写完整代码这种方式来教学,而在书中那些C语言的陷阱或者可能出问题的地方,都有提到,但是由于篇幅所限,写的非常简约,很难让人一下就看懂。我正在完整的逐字逐句的阅读此书,希望能稍作注解,写几篇博客分享一下。

《C陷阱与缺陷》http://book.douban.com/subject/2778632/

《C专家编程》http://book.douban.com/subject/2377310/

这两本书也是学习及使用C语言的朋友必备的两本书,比如《C专家编程》,专门用两三个章节详细介绍C语言中数组与指针的不同之处,这两本书在某种程度上算是对K&R略过的地方做了详细补充,强烈推荐。

《C语言参考手册》http://book.douban.com/subject/2132084/

这是最后一本强烈推荐你最好买回家作为案头书必备的参考书。前面几本书或者稍显简略,或者专注某个特定专题,都不适合遇到问题时翻查。这本《C语言参考手册》可以看作是C语言编程的《新华字典》,全面而权威。里面还涵盖了C99的内容,紧跟时代潮流。

下面几本书都可以作为交叉参考,也都很有价值,也是建议大家都买下来,好书如朋友,日久弥新,像是我推荐的这几本书在douban或者amazon上评分都非常高,而且反复再版。

《C和指针》http://book.douban.com/subject/1229973/

指针的重要性如何,学过C语言(或者C++)的朋友都知道,这本书更是把指针拔高到了与C语言平起平坐的地位,其实也是从头开始介绍,作为教学参考书也是可以的。

《C标准库》http://book.douban.com/subject/3775842/

这本书是专门介绍C语言的标准库如何实现的,比如malloc算法,用标准的C语言该如何写?strlen这个函数应该如何实现?尽管书中不少代码与真实的C标准库相差很多(由于标准库需要考虑性能优化,很多函数有一些特定的trick),但是绝对值得参考。

《你必须知道的495个C语言问题》 http://book.douban.com/subject/3422332/

这本书其实就是C-FAQ的印刷版本,C-FAQ在各种编程语言的FAQ中可以称得上质量一流。如果你想应聘或者招聘C语言相关程序员,这本书一定要参考。

《Linux C编程一站式学习》http://book.douban.com/subject/4141733/

学习C语言,一定不能只读书,应该动手练习完成书里面的项目需求(比如编写一个目录浏览器)以及每章的练习题目。这就需要有可以实验的环境,下面针对不同操作系统简单做一下介绍。

2,动手实验环境搭建

也没有调查过,不知道现在学校里学习C语言是不是依然跟着谭浩强老师用TurboC2.0编程,如果还是这个组合的话,那就太差劲了,赶快抛开它们。

下面主要介绍不同操作系统平台下的集成编程环境,基于初学者以及我个人喜好,就不推荐大家命令行下用vim编程了,直接上IDE。

Windows系统下推荐大家使用Code::blocks这个软件。这个软件最大优点是自带了基于mingw的GCC以及GDB,只要下载70M左右软件包,就可以完整支持C++、C语言编程了。各种功能(比如调试功能)也很强大,版本更新也比较快。注意下载选择名字有mingw的文件,比如最新版本是codeblocks-10.05mingw-setup.exe(版本也许有所不同)。

主页:http://www.codeblocks.org/

image

3,网络资源

如果想用十分钟时间了解一下C语言的来龙去脉、前世今生,维基百科这个页面http://en.wikipedia.org/wiki/C_%28programming_language%29 是最佳选择。

从维基百科可以看到,C语言1972年由Dennis Ritchie设计的命令式、结构化范式编程语言。类型为静态的弱类型,需要显式定义。最新国际标准为C99。设计上主要受到了B、ALGOL68、汇编语言、PL/I、FORTRAN的影响,C语言也影响了大量编程语言,如C++、Objective-C、C#、Java、Go、PHP、Python等等(个人觉得受C影响很大的是PHP,基本上有C编程基础的程序员,很容易就能上手PHP了,除了PHP的OO部分)。

在维基百科条目中有很大篇幅介绍了作者认为C语言缺失的特性,比如面向对象、多线程、GC、异常处理等等,当然这有些吹毛求疵,如果需要这些特性,完全可以用其它程序语言。另外一个介绍的重点是“未定义行为”,有些我们认为理所当然的结果,其实在C语言标准中并没有明确定义,假定这些行为应该如何,当程序使用另外的编译器或者不同版本编译器编译运行,都可能有bug产生。

接下来维基百科条目谈到了C语言的用处,必须承认尽管现在编程语言成百上千,能称之为“系统级”的少之又少,新兴语言中只有Go还能称得上。现在大规模软件项目中完全选用C语言可能性不大,但是核心部分完全可以用C搭建,相对C++开发工具的高昂价格,C语言相关的免费辅助开发软件非常丰富,比如splint,valgrind,不少核心库经过长期使用也都非常稳定。

由于C语言广泛支持各种平台以及编译器相对成熟可靠,不少编程语言选择C语言作为一个中间层,比如Glasgow Haskell编译器就是这样做的。

另一个可以找到大量C语言编程相关资料的地方是“美味书签”,通过搜索特定关键字 (C + programming)就可以找到很多值得挖掘的资源http://delicious.com/search?p=c+programming

还可以参考dmoz.org的C语言分类http://www.dmoz.org/Computers/Programming/Languages/C/ 相比美味书签时效性能差点,但是分类比较系统,查找也要容易一些。

程序员往往是懒惰的,“拿来主义”、“拷贝主义”很流行也很有效,当对某个函数或者关键字不是很理解的时候,看看别人是怎么使用的,会非常有启发性。这里介绍几个常用的代码搜索网站,最常用的是google的codesearch:http://codesearch.google.com ,可以通过不同条件及正则表达式搜索特定关键词。另外可以参考维基百科上一个“带有C语言示例的文章”分类,里面代码写的也很不错。还可以在github.com上搜索相关项目。在前面博客文章我还介绍了一个名为罗塞塔代码的网站http://rosettacode.org/ 这个网站上可以找到不同程序语言针对某个问题的解决方案,用于学习比较非常便利。

学习编程也需要大量阅读名家经典代码,与学中文英文需要大量阅读名著一个道理,C语言编程优质项目那是“彩旗飘舞,人山人海”,个人建议可以看看Lua、Sqlite、Nginx这些项目的代码,代码量不多,而且代码质量也都比较高。另外可以看看Linux内核代码,坊间有不少书籍可以帮助解读。关于如何很好的阅读代码,大家可以参考《Code Reading》这本书。

书看了几本,代码写了一些,也略微读了读其他人的代码,就应该用C语言来完成真实工作中碰到的问题,让C语言真正成为你的瑞士军刀。只有当你经常使用C语言来进行编程工作,经常思考如何通过C设计一个优雅高效的系统,才能更深刻的理解C语言设计哲学。

还可以到http://stackoverflow.com 参与回答问题,浏览其他人的问题解答来汲取知识,比如这篇http://stackoverflow.com/questions/2054939/char-is-signed-or-unsigned-by-default 就介绍了一个C语言关于char类型的小陷阱。

C语言学习当中,有一些难点需要多加注意,如pointer与array的不同之处,复杂类型定义如何解读,如何正确使用预处理preprocessor以及宏定义。其实这些内容在前面书籍都是反复提到,如果按部就班学习下来,应该不成问题。

当C语言学习的差不多时候,还可以学习一门动态语言,比如Lua或者Python,试着在实际工作项目中混合使用动态语言与C语言,一加一发挥出来的力量不仅仅是二,而是非常二(说笑一下,哈哈)。

还有什么问题,欢迎留言。

附录

一些有用的C语言网络资源:

C语言标准化组织ISO JTC1/SC22/WG14的主页,在这里可以找到ISO C的文档:http://www.open-std.org/jtc1/sc22/wg14/

《The Development of the C Language》作者Dennis Ritchie,极为经典的论文。 http://cm.bell-labs.com/cm/cs/who/dmr/chist.html

“C语言全景”这个网站内容很全面:http://www.softpanorama.org/Lang/c.shtml

Dan Saks在embedded.com上的专栏Programming Pointer ,里面文章很有深度,值得一读。

http://www.lysator.liu.se/c/c-www.html 这也是一个C语言资源汇总页面。

http://www.ioccc.org/index.html 混乱C语言代码大赛,很著名。

http://en.wikipedia.org/wiki/Underhanded_C_Contest 另外一个C语言编程大赛,主要面向黑客。

comp.lang.c以及c.moderated这两个讨论组推荐订阅,相当于互联网最大的C相关编程问题论坛:

http://groups.google.com/group/comp.lang.c

http://groups.google.com/group/comp.lang.c.moderated

这里对C语言的各种bit操作做了收集整理,不少题目在面试时候经常出现。http://graphics.stanford.edu/~seander/bithacks.html

台湾的惯C达人Jserv博客,建议大家订阅:http://blog.linux.org.tw/~jserv/

一些值得关注及研究的C语言相关项目:

TinyCC,被很多项目用作动态编译C语言的编译器引擎:http://bellard.org/tcc/

GCC的标准库实现:http://en.wikipedia.org/wiki/GNU_C_Library

Glib是GTK的底层辅助编程库,与C标准库是不一样的,在C语言上实现了面向对象机制:http://en.wikipedia.org/wiki/GLib

dietlibc在前面博客文章介绍过,C标准库的另一种实现:http://www.fefe.de/dietlibc/

一些C语言编程时可以使用的工具软件,帮你提高代码质量:

http://www.splint.org/

http://valgrind.org/

http://www.dwheeler.com/flawfinder/

PMD可用于检测重复代码 http://pmd.sourceforge.net/cpd.html

llvm的静态分析项目 http://clang-analyzer.llvm.org/

C语言编程规范编程标准:

http://en.wikipedia.org/wiki/MISRA_C

http://www.eecs.harvard.edu/~ellard/CS50-96/programming-style.html

http://developers.sun.com/solaris/articles/secure.html

cert这个文档国内有中文翻译版本:https://www.securecoding.cert.org/confluence/display/seccode/CERT+C+Secure+Coding+Standard

http://www.cs.utah.edu/dept/old/texinfo/standards/standards_toc.html

C语言编程电子书及教程:

http://publications.gbdirect.co.uk/c_book/ 这一本写的非常详细,你可以把它看成是类似谭浩强版的教科书。

http://www.knosof.co.uk/cbook/cbook.html 这一本云风曾经推荐过,相当深入的介绍了C99标准,深入细节时候需要读读。

http://www.duckware.com/bugfreec/index.html 这本书在网上流传一个中文版本,《编写优化、高效、无错地代码》,另外也有英文影印版《编程精粹》。

http://wangcong.org/blog/?page_id=196 作者王聪,也是相当hard geek,从两个样章看,包含了相当多的内容。

《C语言深度解剖》这本可以在百度文库或google搜到,可以读读,有些参考性。

《C标准和实现》作者姚新颜,他的《深度探索C、C++》算是当年比较有深度的书籍,可惜已经绝版了。这本书也可以在百度文库搜到。这本书也比较值得读。

良葛格C语言学习笔记 http://caterpillar.onlyfun.net/Gossip/CGossip/CGossip.html

C与C++的兼容性问题 http://en.wikipedia.org/wiki/Compatibility_of_C_and_C%2B%2B

另一个文档关于C与C++标准兼容性问题:http://david.tribble.com/text/cdiffs.htm

C Elements of Stylehttp://www.oualline.com/books.free/style/index.html

《Linux安全编程》http://www.dwheeler.com/secure-programs/

《C Craft》电子版 http://crypto.stanford.edu/~blynn/c/

《The function pointer tutorials》函数指针教程。http://www.newty.de/fpt/index.html

C语言编程及Unix系统调用,想用C在Unix或者Linux编程的朋友可以参考。http://www.cs.cf.ac.uk/Dave/C/

优化C、C++代码 http://www.eventhelix.com/RealtimeMantra/Basics/OptimizingCAndCPPCode.htm

图文并茂介绍C语言的指针 http://boredzo.org/pointers/

另外一篇介绍C语言优化的文章 http://www.prism.uvsq.fr/~cedb/local_copies/lee.html

一个C语言教学ppt http://www.slideshare.net/petdance/just-enough-c-for-open-source-programmers

一些Unix下C语言编程相关的文章 http://users.actcom.co.il/~choo/lupg/tutorials/index.html

Unix下如何建立静态、动态C语言函数库 http://users.actcom.co.il/~choo/lupg/tutorials/libraries/unix-c-libraries.html

如何使用GDB http://users.actcom.co.il/~choo/lupg/tutorials/debugging/debugging-with-gdb.html

一些C语言编程技巧 http://users.bestweb.net/~ctips/

Advanced C programming,高级C语言编程,可以提高水平,非常有帮助 http://www.mpi-inf.mpg.de/departments/rg1/teaching/advancedc-ws08/literature.html

C语言问答,这些题目也可用于面试 http://www.gowrikumar.com/c/

汇编入门笔记(二)

通常我们用loop指令来实现循环功能,CX寄存器中存放循环次数

在汇编源程序中,数据不能以字母开头

dos中,0:200~0:2ff之间的256字节一般没有其他程序的代码或数据

一般来说,在需要暂存数据的时候,我们都应该 使用栈

汇编入门笔记(一)

Err,为了学习《Linux c一站式编程》要学点汇编

 

 

地址总线的宽度决定了CPU的寻址能力
如:80386地址总线宽度为32根,寻址能力为2^32,4GB (8086 20根,1MB)
数据总线的宽度决定了CPU与其他器件进行数据传送时的一次数据传达量
如:8086数据总线宽度16根,一次可传输的数据为2B,16bit.
    80386为32根,一次为4B,32bit
控制总线的宽度决定了CPU对系统中其他器件的控制能力
 
8086 cpu中所有寄存器都是16位的,可以存放两个字节。(386为4B)
AX、BX、CX、DX这四个寄存器通常用于存放一般性的数据,被称为通用寄存器。
为保证兼容,使原来基于上代CPU编写的程序稍加修改就可以运行在8086之上,8086CPU以上四个通用寄存器可分为两个可独立使用的8位寄存器来使用xH和xL
 
8086 CPU给出物理地址的方法
如上,8086CPU 20位地址总线,可达到1MB寻址能力
但从CPU内部来看8086又是16位结构,如果将地址从内部简单地发出,那它只能送出16位地址,寻址能力只有64KB。所以它采用一种在内部用两个16位地址合成的方法来形成一个20位的物理地址。
地址加法器采用 物理地址=段地址x16+偏移地址的方法用段地址和偏移地址合成物理地址.段地址x16有一个更常用的说法是左移4位。进一步思考,一个数据的十六(x)进制形式左移1位,相当于乘以16(x).
 
段地址必然为16的倍数,所以一个段的起始地址也一定是16的倍数。
偏移地址为16位,16位地址的寻址能力为64KB,所以一个段的最大长度为64KB。
如:给定段地址1000H,仅!用偏移地址寻址,CPU的寻址范围为“1000H-1FFFFH”,64KB
CPU可以用不同的段地址和偏移值形成同一个地址。
 
8086CPU有4个段寄存器,CS、DS、SS、ES。CS存放指令的地址,DS存放要访问数据的段地址。
IP为指令指针寄存器。在8080CPU中,这是两个最关键的寄存器。
任意时刻,设CS中的内容为M,IP中的内容为N,8086CPU 将从内存Mx16+N(CS:IP)单元开始,读取一条指令并执行。
其工作流程:
(1)从CS:IP指向的内存单元读取指令,读取的指令进入指令缓冲器
(2)IP=IP+所读取指令的长度,从而指向下一条指令
(3)执行指令。转到步骤1,重复这个过程。
 
在8086CPU加电启动或复位后,CS和IP被设置为CS=FFFFH,IP=0000H。即在刚启动时,CPU从内存FFFF0H单元中读取指令执行。是开机后执行的第一条指令。
 
mov指令不能用于设置CS IP的值。能够改变CS、IP内容的指令被统称为转移指令。
最简单的 jmp CS:IP
 
栈顶的地址存放在SS寄存器中,偏移地址放在SP中。
 
PUSH时 SP-2 然后再进数据
POP时  先出数据 然后SP+2
 
“segment” ends标记一个段的结束
end标志整个程序的结束
 
CX寄存器中存放的是程序机器码的长度
 
DOS中exe的加载过程:
找到一段起始地址为SA:0的容量足够的空闲内存区域
前256字节,存放一个256字节程序段前缀的数据区PSP
程序的地址被设为 SA+10H:0
将该内存区的段地址存入 DS中( DS=SA)
将CS:IP指向(SA+10H:0)
 
PSP的物理地址为 SAx16
该程序的物理地址为
SAx16+256(psp)=SAx16+16x16=(SA+16)x16
可用段地址和偏移地址表示为 SA+10H:0

合理的有理数实现 代码

 

/*
 * ==========================================================================
 *
 *       Filename:  prac.c
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  2010年10月20日 16时50分14秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 ==========================================================================
 */
#include <stdio.h>
#include <math.h>

int euclid(int a, int b)
{
    if (a % b == 0)
        return abs(b);
    else
        return euclid(b, a % b);
}

struct rational {
    int x,y
} ;

struct rational add_rational (struct rational z1,struct rational z2)
{
    struct rational z;
    z.x = z1.x + z2.x;
    z.y = z1.y + z2.y;
    return z;
}
struct rational sub_rational (struct rational z1,struct rational z2)
{
    struct rational z;
    z.x = z1.x - z2.x;
    z.y = z1.y - z2.y;
    return z;
}
struct rational mul_rational (struct rational z1, struct rational z2)
{
    struct rational z;
    z.x = z1.x * z2.x;
    z.y = z1.y * z2.y;
    return z;
}
struct rational div_rational (struct rational z1, struct rational z2)
{
    struct rational z;
    z.x = z1.x / z2.x ;
    z.y = z1.y / z2.y ;
    return z;
}

struct rational make_rational (int a,int b)
{
    struct rational z;
    z.x = a;
    z.y = b;
    return z;
}

int print_rational (struct rational z)
{
    if (z.y < 0) {
        z.x = -z.x;
        z.y = -z.y;
    }
    if (z.y == 0)
        printf ("0 不能做除数\n");
    else if (z.x % z.y == 0) //如果能被整除,则变为最简分数
        printf ("%d\n", z.x/z.y);
    else
    {
        int gcd= euclid( z.x,z.y);
        z.x = z.x/gcd;
        z.y = z.y/gcd;
        printf ("%d/%d\n", z.x, z.y);
    }
    return 0;
}

int main(void)
{
    struct rational a = make_rational(1, 8); 
    struct rational b = make_rational(-1, 8); 
    print_rational(add_rational(a, b));
    print_rational(sub_rational(a, b));
    print_rational(mul_rational(a, b));
    print_rational(div_rational(a, b));
    return 0;
}

转贴:projecteuler vs ACM and the path

转自

http://sgxiao.blog.163.com/blog/static/119937386201032211218977/

 

最开始接触projecteuler也就是几个月前看到laiyonghao大大在2008年发表的一篇博文《推荐几个好玩又有难度的编程网站》。projecteuler是其中第一个网站,也是我认为可玩性最高的一个网站。直到目前为止,中国大陆有1098个账号在上面活动,而用户人数最多的国家是美国,有11550个。这样的结果并不符合一个负责任大国所应有的表现,因此很有必要继续赶英超美(单英格兰在这天就有2267人)。

 
即使对于一个ACM弱鸟来说,projecteuler的模式也不会显得陌生,就是给出一问题,然后由你来进行求解。如果 正确,则你的排名就会上升,这样是一个相当有成就感的事情。当然,两者之间仍然是有一些不一样的。
 
  1. 首先,两者的提交内容不一样。ACM类型的网站需要你提交编写好的程序,上传好了代码之后在服务器端编译和进行judge,只有当你AC了之后,这个题目才算通过。而projecteuler则不一样,它只要求你提交答案。对于题目类型比较偏重数学的内容来说,projecteuler的设计自由度更大。
  2. 其次,限制程度不一样。ACM需要提交程序,自然对程序的运行时间和消耗的内存大小也有一定明确的限制,这就要求你对于某些蛮力无法搞笑解决的问题要学会变通,要求更高。而projecteuler允许你不局限于某种具体的编程语言,而是鼓励你用更多的方法来解决同一个问题。有人用C++,Java,python等等流行的程序语言语言。还有用php,perl,ruby,javascript等等流行的脚本语言来解题。更有出于装B或者是其他不可告人的目的而采用汇编来解题的:-)。总之答案是丰富多彩的,解决的途径自然也是丰富多彩的。
  3. 网站排名对人的影响不一样。玩ACM的时候,我总是想方设法的想刷高排名,所以在自己写不出代码的时候,也会想方法找到高手的代码,看懂然后提交来争取排名靠前。projecteuler则不一样,由于很多solution类型的网站(如 http://code.google.com/p/projecteuler-solutions/)的出现,你想刷的话,一天之内大概就能刷到第一名了,这样盲目刷分反而变得没意义了。因此我更喜欢把题目搞明白,代码运行清楚了,才把代码提交上去。
说到要把题目搞明白,除了自身的努力之外,不断的参考和学习很多不同的内容自然是少不了的。学习的途径自然有不少的。这个过程非常强调动手的能力,只有在动手的过程中,你才能学到更多深入的东西。例如,素数(primes)这样的概念,在中学甚至是小学的时候就有接触过。并且做projecteuler的题目的时候也会经常遇到跟素数相关的内容。能够把经常使用的某个范围的素数找出来,就显得很有必要了。

  要解决这个问题,首先就是要动手去搜索。我搜索到了 1000以内的素数表 ,很快自然也搜到了 10000以内的素数表 ,紧接着,我还能找到 列有 1000000以内的素数表 这样的乏味的blog内容。直到1后面出现了7个0,这才开始没有直接的答案可用。

  于是就被迫开始写代码了。我从最基本的暴力穷举的方法开始尝试,编写一个叫做素数生成器的C语言程序,直到感觉性能实在是太慢了的时候,就又开始找其他的方法了。云风在他的著作《我的编程感悟》讨论优化的问题时,也对上述问题进行了一个简单的讨论。其最终采用的方法,叫做埃拉托色尼筛子算法,是以欧几里德同时代的数学家埃拉托色尼命名的方法。这是可知的已经非常高效的方法,至于具体的实现,我会在以后的文章中探讨。

  除了上述搜索进而动手写代码的方法外,多参考别人的材料,学会站在巨人的肩上往往能达到事半功倍的效果。http://dcy.is-programmer.com/ 这个blog比较适合初学者,里面对前40题都有完整的python代码,适合那些希望写出精炼切高效代码的人。而 http://blog.skainet.net/ 是我发现的一个对每个题目都有比较详尽解释并且提供不同代码的blog,这里的题目比上一个更加深入一点,确实非常值得参考。
 
最后,学习自然也还是不能离开书本。《具体数学》(<concrete mathematics>)是我比较推崇的一本,里面有专门的一章讲述素数的各种有趣的特性。唯一不好的地方就是此书门槛较高,适合数学基础比较好而且英语也还不错的朋友,不过目前国内已经有中文的版本,大家上网搜搜就可以知道了。这样的书,最时候找一块特定的时间离开电脑,安心坐下来看看,你会对大师讲述的睿智和精妙赞叹不绝的。