how to learn c programming language

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

C语言学习方法

C语言学习顺序:阅读参考书,阅读代码,编写调试实际程序,上网参与讨论,研究高级话题。

1,参考书籍

The C Programming Language

clip_image001如果你只想买一本书学习C语言,只需要买这一本就够了。用三个词语来形容它就是:经典!经典!经典!这本薄薄的只有二百多页的小书涵盖了C语言的方方面面,前无古人而且后无来者,任何溢美之词都不足以形容它。

C程序设计语言(第2·新版)》这是K&R的中文译本,可以先从中文译本看起,然后再读一遍英文原版,既可以学习英文,又可以体会原文那种简约优美的风格。

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的内容,紧跟时代潮流。

C和指针》

http://book.douban.com/subject/1229973/

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

C标准库》

http://book.douban.com/subject/3775842/

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

《你必须知道的495C语言问题》

 http://book.douban.com/subject/3422332/

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

Linux C编程一站式学习》

http://book.douban.com/subject/4141733/

这本书是基于特定操作系统Linux来介绍C语言编程,可作为计算机相关专业的教科书或入门参考书,也是书单里面唯一一本国人原创的编程书籍,非常难得。书中几乎所有内容都在网上直接公开,针对读者的意见进行修改,这也是非常难得的一种开放态度。非常推荐大家买一本。

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

2,开发环境

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

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

clip_image002

另外推荐codelite,相比codeblock,这个更新的更频繁一些。也支持各种比较有用的插件、调试特性、WX等等。

clip_image003

主页 http://codelite.org/

如果需要做Windows操作系统的开发,可以下载Visual C++ 2010 Express

clip_image004

因为Code::Blocks不包含Windows编程头文件(实际是因为没有Windows SDK),无法编写Windows操作系统相关的界面应用程序或者服务类程序。而VC++Express自带了这些头文件以及编程库,虽然功能稍微简陋,但对于练习使用基本够用。

主页:http://www.microsoft.com/express/windows/

对于计算机专业的学生朋友,建议大家使用Linux操作系统,或者更详细一点是使用Xubuntu操作系统作为桌面,使用NetbeansGCC这个组合(当然也可以选择Code::Blocks)。在Xubuntu下可以通过apt-get install build-essential这个命令安装gcc相关程序,已经可以在Terminal下编译C语言程序了,但为了使用方便,大家可以选择NetbeansC++支持包,在Netbeans网站上就能下载。

clip_image005

主页:http://netbeans.org/features/cpp/index.html

如果使用苹果Mac系统,毫无疑问XCode就是编程的绝佳选择,XCode可以在苹果开发者网站上免费下载,在IPhone SDK中也包含了XCode

clip_image006

主页:http://developer.apple.com/technologies/tools/xcode.html

如果手头没有合适的编程环境,还需要实验一些简单的代码,可以用http://codepad.org/提供的服务,在线编写运行代码。

clip_image007

另外建议大家申请一个github.com的账号,在gist.github.com可以保存自己的练习代码,就不需要随身带着U盘了。

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

良葛格C语言学习笔记

 http://caterpillar.onlyfun.net/Gossip/CGossip/CGossip.html

CC++的兼容性问题

 http://en.wikipedia.org/wiki/Compatibility_of_C_and_C%2B%2B

另一个文档关于CC++标准兼容性问题: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系统调用,想用CUnix或者Linux编程的朋友可以参考。http://www.cs.cf.ac.uk/Dave/C/

优化CC++代码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

一些UnixC语言编程相关的文章

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/

函数再探

函数再探

       指针对于操作数据和含有数据的变量时一个非常有用的工具。只要有一个指针就可以处理所有的数据。同样,使用指针也可以操作函数,函数的内存地址存储了函数开始执行的位置,存储在函数指针中的内容就是这个地址。

声明函数指针

       函数指针的声明看起来有点奇怪,容易混淆,比如,模式为:

int (*pfunction) (int);

       注意pfunction*的括号不能去掉,不然就不是一样的含义了,就编程了pfunction函数的声明了。

通过函数指针调用函数

       比如有如下函数原型:

int sum(int a, int b);

可以通过int (*pfun)(int,int)=sum;来将sum的地址存储在指针pfun中,然后我们就可以使用pfun了,比如:

int result = pfun(45,55);

       所以,我们看到其实函数的用法非常类似于数组,如果需要的是数组的地址,只要使用数组名即可,同样,如果需要的是函数的地址,也是只使用函数名即可。

函数指针数组

       函数指针和一般的变量是一样的,所以可创建函数指针的数组。要声明函数之后在呢数组,只需将数组的大小放在函数指针数组名之后即可,例如:

       int (*pfunctions[10]) (int);

使用:

int sum(int a, int b);

int (*pfunctions[10]) (int,int);

pfunctions[0] = sum;

就可以使用pfunctions[0](xy);来计算xy的和。

也可以这样初始化指针数组的所有元素:

int (*pfunctions[3]) (int,int) = {sum,product,difference};

作为变元的函数指针

       函数指针也可以作为变元来传递,这样就可以根据指针所指向的函数,而调用不同的函数了。比如:

       int any_function(int (*pfun)(int,int),int x,int y);

 

int any_function(int (*pfun)(int,int),int x,int y)

{

       return pfun(x,y);

}

 

       将程序分解为函数,不仅简化了开发程序的过程,还增强了程序语言解决问题的能力。设计优良的函数常常可以重用,使新应用程序的开发变得更快、更简单。标准库就证明了可重用函数的威力。

静态常量:函数内部的追踪

       C语言中的一个关键字static声明的为静态常量,特点为:

l  虽然static在函数的作用域内定义,但是当执行退出该函数后,这个静态变量不会删除;

l  自动变量每次进入作用域时,都会初始化一次,但是声明为static的变量只在程序开始时初始化一次;

l  静态变量只能在包含其声明的函数中可见,但是它是一个全局变量,因此可以用全局变量的方式使用它;

l  只要程序开始执行,静态变量就一直存在,但是它只能在声明它的范围内可见,不能再该作用域的外部引用。

 

对于全局变量,虽然很有好处,比如可以简化并缩短某些程序,但是过度使用会使程序容易出错,主要原因是很容易修改全局变量,而忘记它对整个程序带来的后果。所以,最好不要给本地变量和全局变量使用相同的名字,这不但没有好处,反而有坏处。

变元个数可变的函数

       标准库stdarg.h提供了编写这种函数的例程。

比如,一个求均值的函数:

double average(double v1,double v2,…)

{

       va_list parg;

       double sum = v1 + v2;

       double value = 0;

       int count = 2;

 

       va_start(parg,v2);

       while((value = va_arg(parg,double)) != 0.0 )//这里要求最后一个值为0

{

              sum += value;

              count ++;

}

       va_end(parg);

       return sum/count;

}

长度可变的变元列表的基本规则

l  在变元数目可变的函数中,至少要有一个固定变元;

l  必须调用va_start初始化函数中可变变元列表指针的值,变元指针的类型必须声明为va_list类型;

l  必须有确定每个变元类型的机制;

l  必须有确定何时终止变元列表的方法;

l  va_arg的第二个变元指定了变元值的类型,这个指针类型可以在类型名的后面加上*来指定;

l  在退出变元数目可变的函数前,必须调用va_end,否则,函数将不能正常工作。

结束程序

结束程序由三种方式:

l  return

l  abort  这种表示是非正常结束;

l  exit –通常0表示正常结束,其他值以某种方式代表程序的状态。

提高性能

       有两个工具可以使编译器生成性能更高的代码。其中一个与短函数调用的编译方式相关,另一个涉及指针的使用。

内联声明函数

       C语言的功能结构要求将程序分解为许多函数,函数有时可以非常短,短函数的每次调用可以用实现该函数功能的内联代码替代,提高执行性能。要采用这种技术,可以使用内联指定短函数。

       inline double sumdouble x, double y

{

       return x+y;

}

 

一、inline 关键字用来定义一个类的内联函数,引入它的主要原因是用它替代C中表达式形式的宏定义。

表达式形式的宏定义一例:

#define ExpressionName(Var1,Var2) ((Var1)+(Var2))*((Var1)-(Var2))为什么要取代这种形式呢,且听我道来:

1.        首先谈一下在C中使用这种形式宏定义的原因,C语言是一个效率很高的语言,这种宏定义在形式及使用上像一个函数,但它使用预处理器实现,没有了参数压栈,代码生成等一系列的操作,因此,效率很高,这是它在C中被使用的一个主要原因。

2.        这种宏定义在形式上类似于一个函数,但在使用它时,仅仅只是做预处理器符号表中的简单替换,因此它不能进行参数有效性的检测,也就不能享受C++编译器严格类型检查的好处,另外它的返回值也不能被强制转换为可转换的合适的类型,这样,它的使用就存在着一系列的隐患和局限性。

3.        C++中引入了类及类的访问控制,这样,如果一个操作或者说一个表达式涉及到类的保护成员或私有成员,你就不可能使用这种宏定义来实现(因为无法将this指针放在合适的位置)

4.        inline 推出的目的,也正是为了取代这种表达式形式的宏定义,它消除了它的缺点,同时又很好地继承了它的优点。

为什么inline能很好地取代预定义呢?

对应于上面的1-3点,阐述如下:

1.        inline 定义的类的内联函数,函数的代码被放入符号表中,在使用时直接进行替换,(像宏一样展开),没有了调用的开销,效率也很高。

2.        很明显,类的内联函数也是一个真正的函数,编译器在调用一个内联函数时,会首先检查它的参数的类型,保证调用正确。然后进行一系列的相关检查,就像对待任何一个真正的函数一样。这样就消除了它的隐患和局限性。

3.        inline 可以作为某个类的成员函数,当然就可以在其中使用所在类的保护成员及私有成员。

在何时使用inline函数:

首先,你可以使用inline函数完全取代表达式形式的宏定义。

另外要注意,内联函数一般只会用在函数内容非常简单的时候,这是因为,内联函数的代码会在任何调用它的地方展开,如果函数太复杂,代码膨胀带来的恶果很可能会大于效率的提高带来的益处。内联函数最重要的使用地方是用于类的存取函数。

使用restrict关键字

       为了优化设计指针的代码,编译器必须能肯定指针没有别名的换言之,每个指针引用的数据项都没有在给定范围内以其他方式引用。关键字restrict就可以告诉编译器,合适出现这种情况,并允许应用代码优化功能。

       在大多数情况下,不需要使用关键字restrict,只有代码进行大量计算,进行代码优化才有显著的效果,而这还取决于编译器。

游戏

//Program reversi an otherlo type game

#include <stdio.h>

#include <stdbool.h>

#include <ctype.h>

#include <string.h>



//const int SIZE = 6; //board size, must be even

#define SIZE 6

const char comp_c = '@'; //computer's counter

const char player_c = 'O'; //player's counter



//functional prototypes

void display(char board[][SIZE]);

int valid_moves(char board[][SIZE],bool moves[][SIZE],char player);

void make_move(char board[][SIZE],int row,int col, char player);

void computer_move(char board[][SIZE],bool moves[][SIZE],char player);

int best_move(char board[][SIZE],bool moves[][SIZE],char player);

int get_score(char board[][SIZE],char player);



int main(void)

{

char board[SIZE][SIZE] = { 0 }; //the board

bool moves[SIZE][SIZE] = {false}; //valid moves

int row = 0; //board row index

int col = 0; //board column index

int no_of_games =0;//number of games

int no_of_moves = 0;//count of moves

int invalid_moves = 0;//invalid move count

int comp_score = 0;//computer score

int user_score = 0;//player score

char y = 0;//column letter

int x = 0;//row number

char again = 0;//replay choice input



//player indicator : true for player and false for computer

bool next_player = true;



printf("\nREVERSI\n\n");

printf("You can go first on the first game, then we will take turns.\n");

printf(" You will be while - (%c)\n I will be black - (%c).\n",

player_c,comp_c);

printf("Select a square for your move by typing a digit for the row\n "

"and a letter for the column with no spaces between.\n");

printf("\nGood luck ! Press Enter to start.\n");

scanf("%c",&again);



//the main game loop

do

{//on even games the player starts;

//on odd games the computer starts;

next_player = !next_player;

no_of_moves = 4;//starts with four counters



//blank all the board squares

for(row = 0; row < SIZE; row ++)

for (col = 0 ; col < SIZE; col ++)

board[row][col] = ' ';



//place the initial four counters in the center

int mid = SIZE/2;

board[mid - 1][mid - 1] = board[mid][mid] = player_c;

board[mid - 1][mid] = board[mid][mid - 1] = comp_c;



//the game play loop

do

{

display(board); //display the board

if(next_player = !next_player)

{

//it is the player's turn

//code to get the player's move and execute it

if(valid_moves(board,moves,player_c))

{

//read player moves until a valid move is entered

for(;;)

{

printf("Please enter your move (row column): ");

scanf("%d%c",&x,&y);//read input

y = tolower(y) - 'a';//convert to column index

x --;//convert to row index

if(x >= 0 && y >= 0 && x < SIZE && y < SIZE && moves[x][y])

{

make_move(board,x,y,player_c);

no_of_moves++;//increment move count

break;

}

else

printf("Not a valid move , try again\n");

}

}

else//no valid moves

if(++invalid_moves < 2)

{

printf("\nYou have to pass, press return");

scanf("%c",&again);

}

else

printf("\nNeither of us can go, so the game is oves. \n");

}

else

{

//it is the computer's turn

//code to make the computer's move

if(valid_moves(board,moves,'@'))//check for valid moves

{

invalid_moves = 0;//reset invalid count

computer_move(board,moves,'@');

no_of_moves++;//increment move count

}

else

{

if(++invalid_moves < 2)

printf("\nI have to pass, your go\n");//no valid move

else

printf("\nNeither of us can go, so the game is over.\n");

}

}

}while(no_of_moves < SIZE*SIZE && invalid_moves < 2);



//game is over

display(board); //show final board



//get final scores and display them

comp_score = user_score = 0;

for(row = 0; row < SIZE; row ++)

for(col = 0 ;col < SIZE; col++)

{

comp_score += board[row][col] == comp_c;

user_score += board[row][col] == player_c;

}

printf("The final score is: \n");

printf("Computer %d\nUser %d\n",comp_score,user_score);



printf("Do you want to play again (y/n):");

scanf("%c",&again);//get y or n

}while(tolower(again) == 'y');

printf("\nGoodby\n");

return 0;

}



//Function to display the board in its

//current state with row numbers and column

//letters to identify squares

//parameter is the board array

void display(char board[][SIZE])

{

//display the column labels

char col_label = 'a';//column label

printf("\n "); //start top line

int col;

for(col = 0; col < SIZE; col++)

printf(" %c ",col_label+col);///display the top line

printf("\n");//end the top line



//display the rows...

int row;

for (row = 0; row < SIZE; row ++)

{

//display the top line for the current row

printf(" +");



for(col = 0; col < SIZE; col++)

printf("---+");

printf("\n%2d|",row + 1);



//display the counters in current row

for(col = 0 ; col < SIZE; col ++)

printf(" %c|",board[row][col]);//display counters in row

printf("\n");

}

//finally display the bottom line of the board

printf(" +");//start the bottom line

for(col = 0; col < SIZE; col ++)

printf("---+");

printf("\n");



}



//calculates which squares are valid moves

//for player, Valid moves are recorded in the

//moves array - true indicates a valid move ,

//false indicates an invalide move

//first parameter is the board array

//second parameter is the moves array

//third parameters identifies the palyer

//to make the move

//Return valid move count



int valid_moves(char board[][SIZE],bool moves[][SIZE],char player)

{

int rowdelta = 0 ;//row increment aroud a square

int coldelta = 0;//column increment around a square

int x = 0;//row index when searching

int y = 0;//column index when searching

int no_of_moves = 0;//number of valid moves

int row,col;

//set the oppoonent

char opponent = (player == player_c) ? comp_c : player_c;



//initialize moves array to false

for(row = 0; row < SIZE; row ++)

for(col = 0; col < SIZE;col++)

moves[row][col] = false;





//find squares for valid moves

//a valid mvoe must be on a blank square and must enclose

//at least one opponent between two player squares

for(row = 0;row < SIZE;row++)

for(col = 0; col < SIZE; col++)

{

if(board[row][col] != ' ')//is it a blank sqare?

continue;



//check all the sqares aroud the blank square

//for the opponents counter

for(rowdelta = -1; rowdelta <= 1; rowdelta++)

for(coldelta = -1; coldelta <= 1; coldelta++)

{

//do not check outside the array or the current square

if(row + rowdelta < 0 || row + rowdelta >= SIZE ||

col + coldelta <0 || col + coldelta >= SIZE ||

(rowdelta == 0 && coldelta == 0))

continue;

//now check the square

if(board[row + rowdelta][col + coldelta] == opponent)

{

//if we find the opponent , move in the delta direction

//over opponent counters searching for a player counter

x = row + rowdelta;//move to

y = col + coldelta;//opponet square



//look for a player sqare in the delta directioin

for(;;)

{

x += rowdelta;//go to next square

y += coldelta;//in delta direction



//if we move outside the array, give up

if(x < 0 || x >= SIZE || y < 0 || y >=SIZE)

break;



//if we find a blank squaer , give up

if(board[x][y] == ' ')

break;





//if the square has a player counter

//then we have a valid move

if(board[x][y] == player)

{

moves[row][col] = true;//mark as valid

no_of_moves++;//increase valid moves count

break;//go check another sqares

}

}

}

}

}

return no_of_moves;

}



//make a move , this places the counter on a sqare and reverses

//all the oppnent's counters affected by the move.

//first parameter is the board array

//second and third parameters are the row and column indices.

//fourth paramter identified the player



void make_move(char board[][SIZE],int row,int col, char player)

{

int rowdelta = 0;//row increment

int coldelta = 0;//column increment

int x = 0;//row index for searching

int y = 0;//column index for searching



//identify opponent

char opponent = (player == player_c) ? comp_c : player_c;

board[row][col]=player;//place the palyer counter



//check all the squares aroud this square

//for the opponents counter

for(rowdelta = -1; rowdelta <= 1; rowdelta++)

for(coldelta = -1; coldelta <= 1; coldelta++)

{

//do no check off the board, or the current square

if(row + rowdelta < 0 || row + rowdelta >= SIZE ||

col + coldelta <0 || col + coldelta >= SIZE ||

(rowdelta == 0 && coldelta == 0))

continue;



//now check the square

if(board[row+rowdelta][col+coldelta] == opponent)

{

//if we find the opponet , search in the same direction

//for a player counter

x = row + rowdelta;//move to opponent

y = col + coldelta;//square

}



for(;;)

{

x += rowdelta;//move to the next square

y += coldelta;



//if we are off the board give up

if(x < 0 || x >= SIZE || y < 0 || y >= SIZE)

break;

//if the square is blank give up

if(board[x][y] == ' ')

break;



//if we find the player counter, go backward from here

//changing all the opponents counters to player

if(board[x][y] == player)

{

while(board[x -= rowdelta][y -= coldelta] == opponent)

//opponent

board[x][y] = player;//yes change it ,

break; //we are done

}

}

}

}



//find the best move for the computer, this is the move for

//which the opponent's best possible move score is a minimu

//first parameter is teh board array

//second parameter is the moves array containing valid moves

//third parameter identified the computer

void computer_move(char board[][SIZE],bool moves[][SIZE],char player)

{

int best_row = 0;//best row index

int best_col = 0;//best column index

int new_score = 0;//score for current move

int score = 100;//minimum opponent score

char temp_board[SIZE][SIZE];//local copy of board

bool temp_moves[SIZE][SIZE];//local valid moves array

int row,col;

//identify opponent

char opponent = (player == player_c) ? comp_c : player_c;



//go through all valid moves

for(row = 0; row < SIZE; row ++)

for(col = 0; col < SIZE; col ++)

{

if(!moves[row][col])

continue;



//first make copies of the board array

memcpy(temp_board,board,sizeof(temp_board));



//now make this move on the temporary board

make_move(temp_board,row,col,player);



//find valid moves for the opponent after this move

valid_moves(temp_board,temp_moves,opponent);



//now find the score for the opponent's best move

new_score = best_move(temp_board,temp_moves,opponent);



if(new_score < score)//is it worse

{//yes, so save this move

score = new_score;//record new lowest opponent score

best_row = row;//record best move row

best_col = col;//and column

}

}

make_move(board,best_row,best_col,player);



}



//calculates the score for the current board position for the

//player, player counters score +1, opponent counters score -1

//first parameter is the board array

//second parameter identified the player

//return value is the score

int get_score(char board[][SIZE],char player)

{

int score = 0; //score for current position

int row,col;

//identify opponent

char opponent = (player == player_c) ? comp_c : player_c;



//check all board squares

for(row = 0 ; row < SIZE; row ++)

for(col = 0; col < SIZE; col++)

{

score -= board[row][col] == opponent;//decrement for opponent

score += board[row][col] == player;//increment for player

}

return score;

}



//calculates the score for the best move out of the valid moves

//for player in the current position

//first parameter is the board array

//second parameter is the moves array defining valid moves

//third parameter identifies the player

//the score for the best move is returned

int best_move(char board[][SIZE],bool moves[][SIZE],char player)

{

//identify opponent

char opponent = (player == player_c) ? comp_c : player_c;

int row,col;

char new_board[SIZE][SIZE] = {0};//local copy of board

int score = 0;//best score

int new_score = 0;//score for current move



//check all valid moves to find the best

for(row = 0; row < SIZE; row++)

for(col = 0; col < SIZE; col++)

{

if(!moves[row][col])

continue;//not a valid move? go to the next



//copy the board

memcpy(new_board,board,sizeof(new_board));



//make move on the board copy

make_move(new_board,row,col,player);



//get score for move

new_score = get_score(new_board,player);



if(score < new_score)//is it better,

score = new_score;//yes save it as best score

}

return score;//return best score

}

basic knowledge note of core python programming

Python核心编程之基础知识笔记

列表和元组

       可以将列表和元组当成普通的数组,它能保存任意数量任意类型的Python对象,和数组一样,通过从0开始的数字索引访问元素,但是列表和元组可以存储不同类型的对象。

       列表和元组有几处重要的区别:

l  列表元素用中括号[ ]包裹,元素的个数及值可以改变;

l  元组元素用小括号( )包裹,不可以更改;

l  元组可以看成是只读的列表

错误和异常

       要给你的代码添加错误检测及异常处理,只要将它们封装在try-except语句当中,try之后的代码就是你打算管理的代码,except之后的代码就是你处理错误的代码。

       比如下面一个很简单的文件操作程序:

try:

    filename = raw_input(‘Enter file name:’)

    fobj = open(filename,’r’)

    for eachLine in fobj:

        print eachLine,

    fobj.close()

except IOError,e:

    print ‘file open error:’,e

 

class FooClass(object):#

    ”’my very first class : FooClass”’

    version = 1.0

   

    def __init__(self,nm=’John Doe’):#

        ”’constructor”’

        self.name = nm

        print ‘created a class instance for’,nm

   

    def showname(self):#

        ”’display instance attribute and class name”’

        print ‘your name is’,self.name

        print ‘my name is’,self.__class__.__name__

       

    def showver(self):#

        ”’display class attribute”’

        print self.version

       

    def addMe2Me(self,x):#

        ”’apply + operation to argument”’

        return x + x

   

fool = FooClass()

 

fool.showname()

fool.showver()

print fool.addMe2Me(10.3)

 

fool1 = FooClass(‘leo’)

       在上面的这个类中,我们定义了一个静态变量version,它将被所有实例以及四个方法共享,其中__init__方法有个特殊的名字,所有名字开始以及结束都有两个下划线的方法都是特殊方法

       当一个类实例被创建时,__init__方法会自动执行,在类实例创建完毕后执行,类似构建函数,__init__可以被当成构建函数,不过不像其他语言中的构建函数,它并不创建实例仅仅是你的对象创建后执行的第一个方法。它的目的是执行一些该对象的必要的初始化工作

       类中的self是类实例自身的引用。

 

python:目录与文件操作

os.listdir(dirname):列出dirname下的目录和文件
os.getcwd()
:获得当前工作目录
os.curdir:
返回但前目录(‘.’)
os.chdir(dirname):#
改变工作目录到
dirname

os.path.isdir(name):#判断name是不是一个目录,name不是目录就返回false
os.path.isfile(name):#
判断name是不是一个文件,不存在name也返回
false
os.path.exists(name):#
判断是否存在文件或目录
name
os.path.getsize(name):#
获得文件大小,如果name是目录返回
0L
os.path.abspath(name):#
获得绝对路径

os.path.normpath(path):#
规范path字符串形式
os.path.split(name):#
分割文件名与目录(事实上,如果你完全使用目录,它也会将最后一个目录作为文件名而分离,同时它不会判断文件或目录是否存在)
os.path.splitext():#
分离文件名与扩展名
os.path.join(path,name):#
连接目录与文件名或目录
os.path.basename(path):#
返回文件名
os.path.dirname(path):#
返回文件路径

>>> import os
>>> os.getcwd()
‘C:\\Python25’

>>> os.chdir(r’C:\temp’)
>>> os.getcwd()
‘C:\\temp’

>>> os.listdir(‘.’)
[‘temp.txt’, ‘test.py’, ‘testdir’, ‘tt’]
>>> os.listdir(os.curdir)
[‘temp.txt’, ‘test.py’, ‘testdir’, ‘tt’]

>>> os.path.getsize(‘test.py’)
38L
>>> os.path.isdir(‘tt’)
True
>>> os.path.getsize(‘tt’)
0L

>>> os.path.abspath(‘tt’)
‘c:\\temp\\tt’
>>> os.path.abspath(‘test.py’)
‘c:\\temp\\test.py’
>>> os.path.abspath(‘.’)
‘c:\\temp’
>>>
>>> os.path.split(r’.\tt’)
(‘.’, ‘tt’)
>>> os.path.split(r’c:\temp\test.py’)
(‘c:\\temp’, ‘test.py’)
>>> os.path.split(r’c:\temp\test.dpy’)
(‘c:\\temp’, ‘test.dpy’


>>> os.path.splitext(r’c:\temp\test.py’)
(‘c:\\temp\\test’, ‘.py’)
>>> os.path.splitext(r’c:\temp\tst.py’)
(‘c:\\temp\\tst’, ‘.py’)
>>>
>>> os.path.basename(r’c:\temp\tst.py’)
‘tst.py’
>>> os.path.dirname(r’c:\temp\tst.py’)
‘c:\\temp’

打开文件和进行写操作

f=open(‘test.txt’,’w’)
f.write(‘hello’)
f.writelines([‘hi’,’haha’])#
多行输入
f.close()
#append data
f=open(‘test.txt’,’a’)
f.write(‘hello’)
f.writelines([‘hi’,’haha’])
f.close()
#
连续写入后会自动关闭
open(‘test.txt’,’a’).write(‘11111\r\n’)
#
result里的元素依次填到open函数里去
result={‘hello’,’u’}
exec open(‘test.txt’) in result
#
selected = []                  # temp list to hold matches
fp = open(‘test.txt’)
for line in fp.readlines():#    # Py2.2 -> “for line in fp:”
     selected.append(line)
del line                       # Cleanup transient variable
#
open(‘test.txt’).readlines()
file
python是一个特殊的类型,它用于在python程序中对外部的文件进行操作。在python中一切都是对象,file也不例外,filefile的方法和属性。下面先来看如何创建一个file对象:

     * file(name[, mode[, buffering]])

file()函数用于创建一个file对象,它有一个别名叫open(),可能更形象一些,它们是内置函数。来看看它的参数。它参数都是以字符串的形式传递的。name是文件的名字。
mode
是打开的模式,可选的值为r w a U,分别代表读(默认) 添加支持各种换行符的模式。用wa模式打开文件的话,如果文件不存在,那么就自动创建。此外,用w模式打开一个已经存在的文件时,原有文件的内容会被清 空,因为一开始文件的操作的标记是在文件的开头的,这时候进行写操作,无疑会把原有的内容给抹掉。由于历史的原因,换行符在不同的系统中有不同模式,比如 unix中是一个\n,而在windows中是‘\r\n’,用U模式打开文件,就是支持所有的换行模式,也就说‘\r’ ‘\n’ ‘\r\n’都可表示换行,会有一个tuple用来存贮这个文件中用到过的换行符。不过,虽说换行有多种模式,读到python中统一用\n代替。在模式 字符的后面,还可以加上+ b t这两种标识,分别表示可以对文件同时进行读写操作和用二进制模式、文本模式(默认)打开文件。
buffering
如果为0表示不进行缓冲;如果为1表示进行行缓冲“;如果是一个大于1的数表示缓冲区的大小,应该是以字节为单位的。

file对象有自己的属性和方法。先来看看file的属性。

     * closed #标记文件是否已经关闭,由close()改写
     * encoding #
文件编码
     * mode #
打开模式
     * name #
文件名
     * newlines #
文件中用到的换行模式,是一个tuple
     * softspace #boolean
型,一般为0,据说用于
print

file的读写方法:

     * F.read([size]) #size为读取的长度,以byte为单位
     * F.readline([size])
       #
读一行,如果定义了size,有可能返回的只是一行的一部分
     * F.readlines([size])
       #
把文件每一行作为一个list的一个成员,并返回这个list。其实它的内部是通过循环调用readline()来实现的。如果提供size参数,size是表示读取内容的总长,也就是说可能只读到文件的一部分。
     * F.write(str)
       #
str写到文件中,write()并不会在str后加上一个换行符
     * F.writelines(seq)
       #
seq的内容全部写到文件中。这个函数也只是忠实地写入,不会在每行后面加上任何东西。

file的其他方法:

     * F.close() 
       #
关闭文件。python会在一个文件不用后自动关闭文件,不过这一功能没有保证,最好还是养成自己关闭的习惯。如果一个文件在关闭后还对其进行操作会产生ValueError
     * F.flush() 
       #
把缓冲区的内容写入硬盘

     * F.fileno()
       #
返回一个长整型的文件标签
     * F.isatty()
       #
文件是否是一个终端设备文件(unix系统中的)

     * F.tell() 
       #
返回文件操作标记的当前位置,以文件的开头为原点
     * F.next()
       #
返回下一行,并将文件操作标记位移到下一行。把一个file用于for … in file这样的语句时,就是调用next()函数来实现遍历的。
     * F.seek(offset[,whence])
       #
将文件打操作标记移到offset的位置。这个offset一般是相对于文件的开头来计算的,一般为正数。但如果提供了whence参数就不一定了, whence可以为0表示从头开始计算,1表示以当前位置为原点计算。2表示以文件末尾为原点进行计算。需要注意,如果文件以aa+的模式打开,每次进 行写操作时,文件操作标记会自动返回到文件末尾。
     * F.truncate([size])
       #
把文件裁成规定的大小,默认的是裁到当前文件操作标记的位置。如果size比文件的大小还要大,依据系统的不同可能是不改变文件,也可能是用0
把文件补到相应的大小,也可能是以一些随机的内容加上去

变量赋值

python 中的变量名有些类似于C++中的指针的概念.

python 中的赋值操作改变的并不是内存中变量的值, 而是变量名指向的变量.

>>> var = 3
>>> tmp = var
>>> var
3
>>> tmp
3
>>> id(var)
10417272
>>> id(tmp)
10417272
>>> id(3)
10417272

 

>>> var = 4
>>> id(var)
10417260
>>> id(4)
10417260
>>> id(tmp)
10417272

>>> tmp
3

>>> var
4
>>>

上边的例子指出, 当执行 “var = 3” , python会在内存中分配一块空间, “3”赋值给这块空间.

然后, 将变量名 “var” 关联到分配的内存.

当执行 “var = 4” , python 会再分配一块内存并存入“4”, 然后将变量名 “var” 关联到“4” 所在内存.

此时“3”所在的内存并没有变化.

 

对应的操作是:

>>> var = 3

分配内存编号10417272, 存入“3”

“var” 关联到 10417272

>>> var = 4

分配内存编号10417260, 存入“4”

“var” 关联到 10417260

>>> tmp
3

>>> id(tmp)
10417272

此时10417272中的内容没有破坏, 仍然是“3”, 并且“tmp”仍然指向10417272

 

事实上,当没有任何变量名指向一个内存中的变量市, python将释放该内存变量 

python之模块结构和布局

python编码的合理布局

1)起始行

2)模块文档

3)模块导入

4)变量定义

5)类定义

6)函数定义

7)主程序

 

#!/usr/bin/env python

 

”’ this is a test module”’

 

import sys

import os

 

debug = True

 

class FooClass(object):

    ”’Foo class”’

    pass

 

def test():

    ”’test function”’

    foo = FooClass()

   

    if debug:

        print ‘ran test()’

   

if __name__ == ‘__main__’:

    test()

clip_image001

 

python中的__name__在运行时检测该模块是被导入还是被直接执行。

如果模块是被导入,__name__的值为模块名字

如果模块是被直接执行,__name__的值为‘__main__’

 

20 of the Best Free Python Books

学习Python20本好书

内容覆盖了Python的一般介绍,游戏开发,编程技巧,儿童编程学习等类别

l  Think Python

l  Invent Your Own Computer Games with Python

l  Snake Wrangling for Kids

l  Learn Python the Hard Way, 2nd Edition

l  Natural Language Processing with Python

l  Building Skills in Python

l  Dive into Python

l  Text Processing in Python

l  The Standard Python Library

l  The Definitive Guide to Pylons

l  Making Games with Python & Pygame

l  Python Module of the Week

l  A Byte of Python

l  Think Complexity

l  Data Structures and Algorithms with Object-Oriented Design Patterns in Python

l  Programming Computer Vision with Python

l  Python for you and me 0.2

l  Problem Solving with Algorithms and Data Structures using Python

l  The Art and Craft of Programming Python Edition

l  Python Programming

Linux网址大全

Linux网址大全

国外
  http://lwn.net/
  http://www.tldp.org/
  https://rhn.redhat.com/
  http://www.justlinux.com/
  http://www.linuxtoday.com/
  http://www.linuxquestions.org/
  http://www.fokus.gmd.de/linux/
  http://www.linux-tutorial.info/
  http://www.freebsdforums.org/forums/
  http://www.netfilter.org/documentation/
  http://www-106.ibm.com/developerworks/linux/
  http://www.redhat.com/docs/ redhat官方文档,redhat用户必看
  http://www.redhat.com/apps/support/errata/ redhat安全性警告、软件更新和增强,建议每周至少查阅一次

redhat linux下载地址
  ftp://ftp.redhat.com/pub/redhat/linux
  http://redhat.com/download/mirror.html

redhat 发行版全球官方镜像站
  http://freesoft.online.sh.cn/ 国内高速下载
  http://www.linuxeden.com/
  http://www.freshrpms.net/
  http://www.linux.cz/apt-rpm/ – Red Hat linux 7.x repositories (with all freshrpms included too!)
  http://apt-rpm.tuxfamily.org/ – Red Hat linux 6.2, 7.x and 8.0 repositories
  http://apt.nlc.no/apt/ – Red Hat linux 6.2, 7.x and Rawhide repositories
  http://ftp.uninett.no/pub/linux/apt/ – Red Hat linux 6.2, 7.x, 8.0 and Rawhide repositories
  http://redhat.usu.edu/ – Red Hat linux 7.2, 7.3 and 8.0 repositories
  ftp://mirror.pa.msu.edu/apt/ – Red Hat linux 7.2, 7.3 and 8.0 repositories
  http://apt-rpm.codefactory.se/ – Red Hat linux 7.2, 7.3 and 8.0 and gnomehide repositories http://apt.42h.de/ – Red Hat Linux 7.2, 7.3 and 8.0 repositories
  http://apt.toggletext.com.au/ – A few Red Hat linux 7.2 custom packages http://people.ecsc.co.uk/~matt/repository.html – Lots of custom Red Hat Linux 8.0 GNOME 2 and related packages
  http://ftp-stud.fht-esslingen.de/apt/ – Red Hat linux 7.x, 8.x and rawhide
  http://apt.unl.edu/ – Red Hat linux 7.3 and 8.0
  http://kde-redhat.sourceforge.net/ – KDE for Red Hat project

linux 常用软件搜索
  http://bingle.pku.edu.cn/ 北大天网ftp搜索,教育网和国内用户查找软件应首先访问,软件特别丰富
  http://www.linuxforum.net/ 有很多国外软件的官方镜像,应首先访问  http://rpmfind.net/
  http://freshmeat.net/
  http://sourceforge.net/
  http://www.gnu.org/ GNU的大本营,gccbash之类的软件源码可以到这里得到 linux 文档和FAQs
  
http://www.tldp.org/ 强烈推荐! The linux document project: linux HOWTO and guides
  
http://www.linux.org.tw/CLDP/ 强烈推荐! TLDP中文版,繁体
  http://www.linuxgazette.com/ linux在线杂志
  http://linux.tcpip.com.cn/download/ linux中文版文档和软件下载
  http://cosoft.org.cn/html/documents/ 很多中文版手册
  http://www.google.com/ 强烈推荐!本站的讨论内容也可以通过google搜索得到,遇到疑难问题到google搜索会得到比绝大多数论坛更快的回答

linux 桌面主站一览表
  GNOME: http://www.gnome.org/
  KDE: http://www.kde.org/
  XFce: http://www.xfce.org/
  Window Maker http://www.windowmaker.org/
  BlackBox: http://sourceforge.net/projects/blackboxwm
  XPde: http://www.xpde.com/
  ROX: http://sourceforge.net/projects/rox
  5dwm: http://5dwm.org/
  foXdesktop: http://sourceforge.net/projects/foxdesktop
  EDE: http://sourceforge.net/projects/ede
  UDE: http://sourceforge.net/projects/udeproject

其它OS
  Ubuntu linux http://www.ubuntu.com/
  CentOS linux http://www.centos.org/
  Mandrake linux http://www.mandrakelinux.com/
  debian linux http://www.debian.org/
  slackware linux http://www.slackware.com/
  suse linux http://www.suse.com/
  FreeBSD http://www.freebsd.org/
  netbsd http://www.netbsd.org/
  openbsd http://www.openbsd.org/
  Solaris http://www.sun.com/solaris 硬件和安装专业站点
  linux Kernel内核: http://www.kernel.org/
  USB安装问题: http://www.linux-usb.org/
  笔记本计算机安装: http://www.linux-laptop.net/
  打印机驱动 http://www.linuxprinting.org/

主要服务器软件主站
1. WWW server:
  Apache http://www.apache.org/ Apache
  SSL模块Mod_ssl http://www.modssl.org/
  aol server http://www.aolserver.com/
  lighttpd http://www.lighttpd.net/
  Nginx http://nginx.net/

2. Servlets/JSP引擎:
  
Tomcat: http://jakarta.apache.org/
  Resin: http://www.caucho.com/
  开源应用服务器AS–Jboss: http://www.jboss.org/

3. 服务器语言:
  
PHP http://www.php.net/
  Zend http://www.zend.com/
  Java http://www.javasoft.com/
  Python http://www.python.org/
  Zope http://www.zope.org/
  Perl http://www.perl.org/
  Ruby http://www.ruby-lang.org/en

4. 数据库:
  
mysql http://www.Mysql.com/
  PostgreSQL http://www.postgresql.org/
  Oracle http://www.oracle.com/
  sap db http://www.sapdb.org/
  PHPMyAdmin — http://www.phpmyadmin.org/
  PHPPgAdmin: http://sourceforge.net/projects/phppgadmin

5. FTP服务器
  wu-ftpd http://www.wu-ftpd.org/
  Proftpd http://www.proftpd.org/
  Pure-ftpd http://www.pureftpd.org/
  ncftpd http://www.ncftpd.com/
  vsftpd http://vsftpd.beasts.org/

6. SMTP服务器
  Sendmail http://www.sendmail.org/
  qmail http://www.qmail.org/
  Postfix http://www.postfix.org/
  Exim http://www.exim.org/
  POP3–qpopper http://www.qpopper.org/

7. IMAP服务器
  Cyrus-IMAPD http://asg.web.cmu.edu/cyrus/imapd
  UW IMAP http://www.washington.edu/imap
  courierimap http://www.inter7.com/courierimap

8. 基本安全工具
  firewall Iptables: http://www.iptables.org/
  shorewall: http://www.shorewall.net/
  inetd Xinetd: http://www.xinetd.org/
  Openssl: http://www.openssl.org/
  OpenSSH: http://www.openssh.org/
  nmap: http://www.insecure.org/nmap
  Tripwire: http://www.tripwire.org/
  snort: http://www.snort.org/
  nessus: http://www.nessus.org/
  GnuPG: http://www.gnupg.org/
  chkrootkit: http://www.chkrootkit.org/
  安全顾问: http://www.cert.org/

9. 其它服务器软件
  CVS–CVS http://www.cvshome.org/
  DNS域名解析BIND http://www.isc.org/products/BIND/
  DHCP–DHCP http://www.isc.org/products/DHCP/
  INN新闻组INN: http://www.isc.org/products/INN/
  Proxy代理缓存: Squid http://www.squid-cache.org/
  Socks代理:http://www.socks.nec.com/
  Samba Server: http://www.samba.org/
  Print CUPS: http://www.cups.org/
  LDAP OpenLDAP: http://www.openldap.org/
  流量分析 MRTG http://www.mrtg.org/
  日志分析 webalizer http://www.mrunix.net/webalizer/
  Ipsec/VPN http://www.freeswan.org/
  路由 Zebra http://www.zebra.org/
  集群 LVS http://www.linuxvirtualserver.org/
  MPICH http://www-unix.mcs.anl.gov/mpi/mpich/
  PVMhttp://www.netlib.org/pvm3/
  Rsync: http://rsync.samba.org/
  linuxconf: http://www.solucorp.qc.ca/linuxconf/
  
Webmin: http://www.webmin.com/