复习:
1,函数声明 告诉编译器函数的格式,方便编译器检查调用者的参数、返回值
2,隐式声明 函数调用时没有声明就会产生,编辑器就会猜测函数的格式,函数的形参会根据调用者提供的实参来猜测
返回值会猜测为int类型。
3,函数定义 函数定义如果出现在函数调用之前,可以省略函数声明
4,函数传参
值传递:普通变量,局部变量,单项值传递,函数之间的变量无法共享 因为是局部变量
址传递:目前来说只有数组是址传递,导致数组的长度会丢失,需要额外增加一个参数传递数组长度,此时就共享了一个数组
返回值:return语句返回给调用者,并不是把数据直接传递给调用者,而是把返回值放在一个他们都能访问的公共区域,如果
没有return语句就会产生一个垃圾值。
进程映像:
程序:储存在磁盘上的文件,二进制文件或者脚本
进程:系统中正在运行的程序
进程映像:就是进程内存的分布情况!
text 代码段(只读段):二进制指令、常量、如果强制修改则会产生段错误
data 数据段:初全、初静局
bss 静态数据段:未初全、未初静局、该段内存在程序运行时会先被清理为0;
heap 堆 由程序员手动管理,特点大
stack 栈 局部变量、特点小、超过后产生段错误、由系统管理不需要手动申请释放
变量的分类:
储存位置、生命周期、使用范围
全局变量:
取决于是否初始化放在data或者bss
从程序运行开始到结束
程序任何位置使用
局部变量:
定义在函数内的
stack中
从定义的位置开始到函数的结束释放
函数内才能使用
块变量:
定义在循环体内的变量
stack中
从定义的位置开始到函数结束
只能在语句块内使用
全局变量、局部变量、块变量—均可同名,因为在不同的范围内会屏蔽,使用时应该注意关系!
类型限定符:
auto:用于定义自动申请、自动释放的内存,不加代表加,不能用于定义全局变量!也不能与static使用
extern:用于声明外部变量、告诉编译器在别的文件有定义,先行通过。当链接时没有找到还是会报错
static:
改变储存位置:
局部变量的储存位置变化由stack>data或者bss 取决于是否初始化
延迟生命周期:
局部变量、块变量、不会被销毁 它们的初始化语句只是第一次有效
改变作用域:
全局变量、函数 被加了static就会被限制只能在本文件使用
const:保护变量不被显式的修改 初始化过的全局变量和静态局部变量被const修饰后 储存位置就变成text了,就成为了真正的常量
强行修改就会产生段错误、但是通过地址还是可以改的!
volatile:不让取值优化、而不会重新读取。适用于硬件编程,或者其他会隐式修改的程序,随时更新变量的值就需要使用
register:申请把变量从内存到寄存器,快。但是不是每次都能申请成功!!!!!
注意不能取地址
typedef:类型重定义、当定义变量时、前面加上typedef那么变量名就相当于这个类型
typedef
uint8_t time_t size_t 使用typefdef定义的
注意不是替换就是重定义
五子棋:
思路
1、定义棋盘
2、定义变量用于记录下棋的坐标
3、定义一个棋子角色
业务逻辑:
1、是否需要对数据进行初始化
for(;😉
{
1、清理屏幕、显示棋盘
2、落子
判断坐标是否合法、该位置是否有棋子
方向键控制—输入x、y坐标
3、判断是否五子连珠
4、交换角色—三目运算符
}
利用光标来做比较合适!
棋子— @----$ ↑ ↓ ← →移动 回车下子
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <getch.h>
// 定义棋盘
char board[15][15];
// 定义下棋坐标
char key_x = 7,key_y = 7;
// 定义棋子角色
char role = '@';
// 初始化棋盘
void init_board(void)
{
for(int x = 0; x<15; x++)
{
for(int y = 0; y<15; y++)
{
board[x][y] = '*';
}
}
}
// 显示棋盘
void show_board(void)
{
system("clear");
for(int x = 0; x<15; x++)
{
for(int y = 0; y<15; y++)
{
printf(" %c",board[x][y]);
}
printf("\n");
}
}
// 落子
void get_key(void)
{
printf("请%c下棋\n",role);
while(1)
{
printf("\33[%hhd;%hhdH",key_x+1,(key_y+1)*2);
switch(getch())
{
case 183: key_x>0 && key_x--; break;
case 184: key_x<14 && key_x++; break;
case 185: key_y<14 && key_y++; break;
case 186: key_y>0 && key_y--; break;
case 10:
if('*' == board[key_x][key_y])
{
board[key_x][key_y] = role;
return;
}
}
}
}
// 检查某个方向上有几个相同的棋子
int check_key(int ox,int oy)
{
int count = 0;
for(int x=key_x+ox,y=key_y+oy;
x>=0 && x<15 && y>=0 && y<15; x+=ox,y+=oy)
{
if(board[x][y] == board[key_x][key_y])
{
count++;
}
else
{
break;
}
}
return count;
}
// 检查是否五子连珠
bool is_win(void)
{
if(check_key(0,-1)+check_key(0,1) >= 4)
return true;
if(check_key(-1,0)+check_key(1,0) >= 4)
return true;
if(check_key(-1,-1)+check_key(1,1) >= 4)
return true;
if(check_key(-1,1)+check_key(1,-1) >= 4)
return true;
return false;
}
int main(int argc,const char* argv[])
{
init_board();
for(int i=0;i<225;i++)
{
show_board();
get_key();
if(is_win())
{
show_board();
printf("恭喜%c胜利!\n",role);
return 0;
}
// 交换角色
role = role == '@'?'$':'@';
/*
if('@' == role)
r(le = '$';
else
role = '@';
*/
}
printf("平局,你俩真棒!\n");
return 0;
}
小结:
1、用光标的体验会更好!使用方式是(还可以改变它的形状颜色等。。)
int x=0,y=0;
printf("\33[%d;%dH",x,y);
2、判断方向时,利用左右 上下 斜左 斜右 四个大方向来判断八个小方向是否五子连珠,具体方法见上
3、交换角色,由于只有两个角色可以简单if-else替换
4、要考虑平局情况