目前为止跟着学校进度学习C语言大概半年左右,基础学习只学到了指针,学得非常浅。说实话,起初对C语言的印象———只是一个学习计算机语言的敲门砖,对具体C语言如何应用等,非常迷茫。直到大一下半学期的高级语言设计课程之后,试过dos运行的图形化界面的完整小程序,才发现C语言的魅力。
ok,废话不多说了,下面是我第一节课研究的程序————C语言的五子棋。一个简单的小程序。并非纯原创,是基于网络搜索到的“Etsnarl制作”的改编而成的。初次直接阅读这样的一个程序对于我来说有些难,但是通过直接浏览、修改一个完整的代码,我的收获颇丰。我认为这样比枯燥的学习代码更加高效、易懂、易记。以下是几个我在修改程序时学到的对于我来说比较有用的几点:
1.头文件
#include <stdio.h>
这个就不多说了,必备的。在普及一下stdio 就是指 “standard input & output"(标准输入输出)
所以,源代码中如用到标准输入输出函数时,就要包含这个头文件!
#include <stdlib.h>
stdlib 头文件里包含了C语言的一些函数。stdlib.h里面定义了五种类型、一些宏和通用工具函数。类型例如size_t、wchar_t、div_t、ldiv_t和lldiv_t;宏例如EXIT_FAILURE、EXIT_SUCCESS、RAND_MAX和MB_CUR_MAX等等;常用的函数如malloc()、calloc()、realloc()、free()、system()、atoi()、atol()、rand()、 srand()、exit()等等。
#include <conio.h>
con就是console,控制台。io就是输入输出。连起来就是用来声明控制台输入输出所需函数的头文件,如果用到像:
getch()
getchar()
cprintf()
cputs()
kbhit()
那么就调用,简单说就是“通用输入输出库”,主要是文件和标准控制台的输入输出。里面有一个很常用的清屏函数clrsr()可以清屏,非常实用。
#include <string.h>
string.h是一个和字符串处理相关的头文件,里面有很多字符串处理的函数,如果你写程序时要用到里面提供的函数的话,就应该加。一般来说,只要有字符串处理,最好都加上。
2.char*的作用
与char[]作对比的区别如下:
① char[] p表示p是一个数组指针,相当于const pointer,不允许对该指针进行修改。但该指针所指向的数组内容,是分配在栈上面的,是可以修改的。
② char * pp表示pp是一个可变指针,允许对其进行修改,即可以指向其他地方,如pp = p也是可以的。对于*pp = "abc";这样的情况,由于编译器优化,一般都会将abc存放在常量区域内,然后pp指针是局部变量,存放在栈中,因此,在函数返回中,允许返回该地址(实际上指向一个常量地址,字符串常量区);而,char[] p是局部变量,当函数结束,存在栈中的数组内容均被销毁,因此返回p地址是不允许的。
3.接收键盘按键
例: input==0x20(判断输入是否为空格)
input==0xE0(判断输入是是否为方向键)
input==27(Esc)
这是一种整型常量的表示方式。以0x开头的整型常量,代表后续字符为16进制表达。于是0x20也就是16进制的20,即10进制的32。
另外,0x20作为单字节表示,可以用于字符型变量的赋值,用于char时,其代表ascii码值0x20,即字符空格' '。
这个是标识一次按键将会返回两个16位整数的特殊值。一旦你扫描键盘按键,返回值(比如_getch()的返回值)是0xE0的话,那么预示着后面还有一个整数等待返回,你需要再调用一次_getch()获得那个返回值,前后两个返回值合并构成一个32位的整数值,才是那个按键的完整代码。通常是按下控制键时会出现这个现象,比如Ctrl+键、PgUp/PgDn等,都会这样。也就是说,键盘按键,有些键是返回16位整数的,有些是返回32位整数的,后者的高位必定是0xE0。这跟汉字的编码与ASCII编码有区别,是同一个道理。在C语言编程中,如果使用_getch()函数接收键盘按键,那么就要分析其返回值是否0xE0,如果是,则必须再调用一次_getch(),否则缓冲区中会残留数据,也影响程序的正常运作。现代编程,已经提倡使用Unicode编码方式,用_getwch()函数来接收键盘按键,一次返回完整的32位整数,不需再调用一次。
K_SPACE = 0x0020,
K_UP = 0xE048,
K_LEFT = 0xE04B,
K_RIGHT = 0xE04D,
K_HOME = 0xE047,
K_END = 0xE04F,
K_PGUP = 0xE049,
K_PGDN = 0xE051,
K_INS = 0xE052,
K_DOWN = 0xE050,
K_DEL = 0xE053,
K_F2 = 0x003C,
K_F3 = 0x003D,
K_F4 = 0x003E.
4.判断方向键方向并移动光标位置
- switch(input)
- {
- case 0x4B:
- Cx--;
- break;
- case 0x48:
- Cy--;
- break;
- case 0x4D:
- Cx++;
- break;
- case 0x50:
- Cy++;
- break;
- }
以下是完整的主程序代码:
- #include <stdlib.h>
- #include <stdio.h>
- #include <conio.h>
- #include <string.h>
-
-
- #define MAXIMUS 15 //定义棋盘大小
-
-
- int p[MAXIMUS][MAXIMUS];
- char buff[MAXIMUS*2+1][MAXIMUS*4+3];
- int Cx,Cy;
- int Now;
- int wl,wp;
- char* showText;
- int count;
-
-
- char* Copy(char* strDest,const char* strSrc)
- {
- char* strDestCopy = strDest;
- while (*strSrc!='\0')
- {
- *strDest++=*strSrc++;
- }
- return strDestCopy;
- }
- void Initialize()
- {
- int i,j;
- showText="";
- count=0;
- for(i=0;i<MAXIMUS;i++)
- {
- for(j=0;j<MAXIMUS;j++)
- {
- p[i][j]=0;
- }
- }
- Cx=Cy=MAXIMUS/2;
- Now=1;
- }
- char* getStyle(int i,int j)
- {
- if(p[i][j]==1)
- return "●";
- else if(p[i][j]==2)
- return "○";
- else if(i==0&&j==0)
- return "┏";
- else if(i==MAXIMUS-1&&j==0)
- return "┓";
- else if(i==MAXIMUS-1&&j==MAXIMUS-1)
- return "┛";
- else if(i==0&&j==MAXIMUS-1)
- return "┗";
- else if(i==0)
- return "┠";
- else if(i==MAXIMUS-1)
- return "┨";
- else if(j==0)
- return "┯";
- else if(j==MAXIMUS-1)
- return "┷";
- return "┼";
- }
- char* getCurse(int i,int j){
- if(i==Cx){
- if(j==Cy)
- return "┏";
- else if (j==Cy+1)
- return "┗";
- }
- else if(i==Cx+1)
- {
- if(j==Cy)
- return "┓";
- else if (j==Cy+1)
- return "┛";
- }
- return " ";
- }
- void write(char* c)
- {
- Copy(buff[wl]+wp,c);
- wp+=strlen(c);
- }
- void ln()
- {
- wl+=1;
- wp=0;
- }
- void Display()
- {
- int i,l=strlen(showText);
- int Offset=MAXIMUS*2+2-l/2;
- if(Offset%2==1)
- {
- Offset--;
- }
- Copy(buff[MAXIMUS]+Offset,showText);
- if(l%2==1)
- {
- *(buff[MAXIMUS]+Offset+l)=0x20;
- }
- system("cls");
- for(i=0;i<MAXIMUS*2+1;i++){
- printf("%s",buff[i]);
- if(i<MAXIMUS*2)
- printf("\n");
- }
- }
- void Print()
- {
- int i,j;
- wl=0;
- wp=0;
- for(j=0;j<=MAXIMUS;j++)
- {
- for(i=0;i<=MAXIMUS;i++)
- {
- write(getCurse(i,j));
- if(j==0||j==MAXIMUS)
- {
- if(i!=MAXIMUS)
- write(" ");
- }
- else
- {
- if(i==0||i==MAXIMUS-1)
- write("┃");
- else if(i!=MAXIMUS)
- write("│");
- }
- }
- if(j==MAXIMUS)
- {
- break;
- }
- ln();
- write(" ");
- for(i=0;i<MAXIMUS;i++)
- {
- write(getStyle(i,j));
- if(i!=MAXIMUS-1)
- {
- if(j==0||j==MAXIMUS-1)
- {
- write("━");
- }
- else
- {
- write("―");
- }
- }
- }
- ln();
- }
- Display();
- }
- int Put(){
- if(p[Cx][Cy]==0)
- {
- p[Cx][Cy]=Now;
- return 1;
- }
- else
- {
- return 0;
- }
- }
- int Check()
- {
- int w=1,x=1,y=1,z=1,i;
- for(i=1;i<5;i++)if(Cy+i<MAXIMUS&&p[Cx][Cy+i]==Now)w++;else break;
- for(i=1;i<5;i++)if(Cy-i>0&&p[Cx][Cy-i]==Now)w++;else break;
- if(w>=5)return Now;
- for(i=1;i<5;i++)if(Cx+i<MAXIMUS&&p[Cx+i][Cy]==Now)x++;else break;
- for(i=1;i<5;i++)if(Cx-i>0&&p[Cx-i][Cy]==Now)x++;else break;
- if(x>=5)return Now;
- for(i=1;i<5;i++)if(Cx+i<MAXIMUS&&Cy+i<MAXIMUS&&p[Cx+i][Cy+i]==Now)y++;else break;
- for(i=1;i<5;i++)if(Cx-i>0&&Cy-i>0&&p[Cx-i][Cy-i]==Now)y++;else break;
- if(y>=5)return Now;
- for(i=1;i<5;i++)if(Cx+i<MAXIMUS&&Cy-i>0&&p[Cx+i][Cy-i]==Now)z++;else break;
- for(i=1;i<5;i++)if(Cx-i>0&&Cy+i<MAXIMUS&&p[Cx-i][Cy+i]==Now)z++;else break;
- if(z>=5)return Now;
- return 0;
- }
- int RunGame()
- {
- int input;
- int victor;
- Initialize();
- while(1){
- Print();
- input=getch();
- if(input==27)
- {
- exit(0);
- }
- else if(input==0x20)
- {
- if(Put())
- {
- victor=Check();
- Now=3-Now;
- count++;
- if(victor==1)
- {
- showText="黑方获得了胜利!";
- Print();
- if(getch()==0xE0)
- {
- getch();
- }
- return Now;
- }
- else if(victor==2)
- {
- showText="白方获得了胜利!";
- Display();
- if(getch()==0xE0)
- {
- getch();
- }
- return Now;
- }else if(count==MAXIMUS*MAXIMUS)
- {
- showText="平局!";
- Display();
- if(getch()==0xE0)
- {
- getch();
- }
- return 0;
- }
- }
- }
- else if(input==0xE0)
- {
- input=getch();
- switch(input)
- {
- case 0x4B:
- Cx--;
- break;
- case 0x48:
- Cy--;
- break;
- case 0x4D:
- Cx++;
- break;
- case 0x50:
- Cy++;
- break;
- }
- if(Cx<0)Cx=MAXIMUS-1;
- if(Cy<0)Cy=MAXIMUS-1;
- if(Cx>MAXIMUS-1)Cx=0;
- if(Cy>MAXIMUS-1)Cy=0;
- }
- }
- }
- int main()
- {
- system("title 简易五子棋 ――ZYC改编");
- system("mode con cols=63 lines=32");
- system("color E0");
- while(1){
- RunGame();
- }
- }