本帖最后由 blacker 于 2016-7-22 20:00 编辑
曾几何时,我刚学C语言,其实在这之前,也就是高中时候,我还了解过VB。那时候的我,刚刚步入编程的世界,憧憬着自己将来会成为一名出色的IT工程师。
可是,不论是教程书上还是老师在课上讲的,大部分就是“变量、常量、数组等等的定义及使用” “打印hello world” “九九乘法表” “数组排序”等等。于是我就想啊:“难道以后我精通了C语言以后,就天天用这些玩意就能写出一个像样的软件了?比如QQ、浏览器、杀毒软件、桌面便签等”。
再后来,随着学习的不断深入,我终于对编程语言有了宏观的认识:概括起来讲,编程语言由参与运算的量(常量变量等)、参与运算的运算符(加减乘除等)、流程控制语句(如C语言的if、while、goto、for等)、函数调用规范四大块构成。前面三块是很基础的了,当然,第四块也是很基础的,但我为什么要把第四块单独列出来呢?因为它是通往编程世界的一扇窗户。没有了函数调用,你只能定义一些变量,然后做做运算、跳转一下、循环几次,其他的什么也干不了了。
通过调用函数,你可以实现很多很多功能,比如,printf就可以往屏幕上输出一些东西。任何一种编程语言做出来的真正的项目,都是由各种各样的库里的各种各样的函数通过前面三块来堆起来的。拿一个C语言helloworld来举例说明一下:
#include
//上面这句就是一个包含头文件的说明,因为我们要输出helloworld需要调用printf函数,而这个函数在ANSI C标准库中的stdio.h中声明,因此我们要通过该语句来指明printf的出处
int main(void)
//上面这句是helloworld程序的入口点,当我们运行helloworld程序的时候,操作系统就调用这个main函数,以后你学的多了之后,你会知道其实他也是个函数,与程序中其他函数不同的一点是:这个函数由操作系统调用,参数由操作系统命令行传递给main函数,返回值也由操作系统接收。而程序中的函数参数由程序中的语句传递给被调用函数,被调用函数的返回值也由程序中的变量接收。
{
printf("Hello World!\n");
//上面这句完成了我们helloworld最关键的功能:在屏幕上打印输出helloworld字符串。从宏观上讲,这是一个函数,是个函数就有参数以及返回值,在这里,我们传递给printf函数的参数是"Hello World!\n",而我们并不关心这个函数的返回值,所以就没设置变量去接收返回值。
return 0;
//上面这句就是程序的返回值,也就是main函数的返回值,前面我们说了,这个值“0”最终是返回到操作系统中去了,操作系统怎么处理这个值你暂时可以不用关心。
}
看完了helloworld源码解释,你会明白:原来,我要实现XX功能,就要学会XX函数的使用方法。是的,学习一种编程语言,最难的不是学编程语言本身,而是学习能够实现你所需要的功能的函数!任何一种编程语言,无非就是各种量的定义及使用、各种运算符的使用、程序流向控制、函数的调用方法。还是那句话,函数是你通往代码世界的一扇窗。
----------------分割线,以上为helloworld和编程语言宏观讲解-------------------
很久以前,我上班无聊玩win7桌面小游戏——数字拼图时,突然想到自己编写一个数字拼图游戏,于是……
//------------------------------分割线,以下是源码-------------------------------
//编译环境:VC++6.0,(若用Win TC,可能需要把注释去掉,否则有非法注释的提示)
#include "time.h"
#include "stdio.h"
#include "stdlib.h"
#include "conio.h"
//存储按键码,也就是玩游戏时候按下的“上下左右”方向键的码
char key;
//x、y、i用于循环,x0y0指示当前空位"0",rnd存放随机数值,t标记排序是否成功
int x,y,x0,y0,rnd,i,t=0;
//数字存储矩阵
int matrix[4][4];
//以下为函数声明
void show(void); //显示当前排序
void initmatrix(void); //初始化随机矩阵
int sett(void); //判断当前排序是否成功
void up(void); //向下移动空位(空位下方数字上移)
void down(void);
void lft(void);
void rght(void);
void iptkey(void); //接收按键(只接收方向键)
//主函数
int main(void)
{
//显示提示信息并暂停 按任意键后开始游戏
printf("Use arrow key to move the numbers,press anykey to start playing.\n");
getch();
//标号 游戏成功后如果按r重玩则跳转至此
start:
//清成功标志,否则一直为成功状态
t=0;
//取随机数初始化
srand((unsigned int)time(0));
initmatrix();
//如果游戏没结束,也就是不满足1-15按顺序排列,则循环等待按下方向键并操作矩阵数字交换
while(!t)
{
iptkey();
t=sett();
//清屏
system("CLS");
show();
}
printf("Congratulations,you win!\n");
printf("Press R to Restart,anykey to Quit,thank you for playing the Game!\n");
key=getch();
system("CLS");
if(key=='R' || key=='r')
goto start;
else
;
getch();
return 0;
}
void initmatrix(void)
{
x0=3;
y0=3;
i=0;
for(y=0;y<4;y++) //嵌套循环先按成功序列排序1234567891011121314150
for(x=0;x<4;x++)
{
if(y==3 && x==3)
matrix[y][x]=0;
else
matrix[y][x]=1+i++;
}
for(i=0;i<1000;i++) //一千次循环,每次循环都按随即方向移动
{
rnd=rand()%(4); //取0-3随机数,分别代表上下左右四个方向
switch(rnd)
{
case 0:
{
up();
break;
}
case 1:
{
down();
break;
}
case 2:
{
lft();
break;
}
case 3:
{
rght();
break;
}
}
}
show();
}
int sett(void)
{
i=0;
for(y=0;y<4;y++)
for(x=0;x<4;x++)
{
if (matrix[y][x]!=1+i++)
return (i==16)?1:0;
}
}
void iptkey(void)
{
key=getch();
switch(key)
{
case 72:
{
up();
break;
}
case 80:
{
down();
break;
}
case 75:
{
lft();
break;
}
case 77:
{
rght();
break;
}
}
}
void up(void)
{
if(y0!=3) //移动时要考虑空位"0"是否已经在边界,上下左右各边界各有一个方向不能移动
{
matrix[y0][x0]=matrix[y0+1][x0];
y0++;
matrix[y0][x0]=0;
}
}
void down(void)
{
if(y0!=0)
{
matrix[y0][x0]=matrix[y0-1][x0];
y0--;
matrix[y0][x0]=0;
}
}
void lft(void)
{
if(x0!=3)
{
matrix[y0][x0]=matrix[y0][x0+1];
x0++;
matrix[y0][x0]=0;
}
}
void rght(void)
{
if(x0!=0)
{
matrix[y0][x0]=matrix[y0][x0-1];
x0--;
matrix[y0][x0]=0;
}
}
void show(void)
{
for(y=0;y<4;y++)
for(x=0;x<4;x++)
{
if(x==3)
printf("%d\n",matrix[y][x]); //“\n"保证每行只有四个数显示 满四个数就换行
else
printf("%d\t",matrix[y][x]);
}
}
//-------------------------------分割线,以上是源码-------------------------
程序很简陋,注释也不多,好在都玩过这个游戏,一看代码结构就知道怎样实现的了。
ps:其实这是第二版,第一版的时候,没考虑到数字拼图无解的情况。第一版和第二版的区别在于游戏初始化的时候,各数字位置的随机确定上。第一版的实现方法大概为:从0-15中随机取值,每取出一个值就把它按顺序放到4*4矩阵中,然后从0-15中剔除这个值,防止再次取到它,这样直到16个值全部取完。由于这种方法是“真正”的随机,并没有遵循“保证数字拼图有解”的规则,因此,每次初始化有1/2的概率出现无解的情况。第一版出生后,我自己玩了几次,发现了无解的情况之后,改进了拼图初始化的随机方法:从正确答案(也就是1-15按顺序在矩阵中排列,最后为空位0)开始,随机移动空位0一定次数(我设定的是1000次,空位随机移动1000次,得到的初始化排列足够随机的了)。由于最终初始化结果是由正确答案逆向移动得出来的,那么这个初始化的排列一定是有解的。
pps:关于初始化,你有其他方法吗?欢迎讨论。