目录
简单版三子棋实现
实现的功能和总体结构概述
- 目标 为了实现三子棋的游戏
- game.h 头文件为了实现函数定义和符号定义
- game.cpp实现程序所有需要的函数
- test.cpp 实现程序的逻辑
- void printCaiDan();//这个函数用来打印菜单
- void Initarr(char arr[ROW][COW],int row,int cow);//这个函数用来初始化数组内容都为空格
- void printQiPan(char arr[ROW][COW], int row, int cow);//打印棋盘
- void PlayerMove(char arr[ROW][COW], int row, int cow);//模拟玩家下棋
- void ComputerMove(char arr[ROW][COW],int row,int cow);//模拟电脑下棋
- char IsWin(char arr[ROW][COW],int row, int cow);//判断玩家赢还是电脑赢还是平局或者是继续游戏
- char IsFull(char arr[ROW][COW], int row, int cow);//判断棋盘是不是已经满了
打印菜单函数
void printCaiDan() { printf("**********************************************\n"); printf("*************玩游戏输入1,退出输入0************\n"); printf("**********************************************\n"); printf("**********************************************\n"); }
初始化二维数组函数
void Initarr(char arr[ROW][COW], int row, int cow) { int i = 0; int j = 0; for (i = 0; i < row; i++) { for (j = 0; j < cow; j++) { arr[i][j] = ' '; } } }
打印棋盘
void printQiPan(char arr[ROW][COW], int row, int cow) { /*int i = 0; for ( i = 0; i <row; i++) { printf(" %c | %c | %c ", arr[i][0], arr[i][1], arr[i][2]); if (i<row-1) { printf("---|---|---"); } 只能实现3字棋盘的打印} */ //可以实现任意大小棋盘的打印 //将效果图的图案先输出 * | * | * // 然后输出 ___|___|___ int i = 0; for (i = 0; i < row; i++) { int j = 0; for (j = 0; j < cow; j++) { printf(" %c ", arr[i][j]); if (j < cow - 1) { printf("|"); } } //这个循环实现输出 * | * | * printf("\n"); if (i<row-1) { int j = 0; for ( j = 0; j < cow; j++) { printf("---"); if (j<cow-1) { printf("|"); } } //这个循环实现输出 ___|___|___ printf("\n"); } } }
效果图
模拟玩家出棋
void PlayerMove(char arr[ROW][COW], int row, int cow) { int i = 0; int j = 0; printf("玩家开始下棋\n"); while (1) { printf("请输入你想下棋的坐标——>\n"); scanf("%d%d", &i, &j); if (i >= 1 && j >= 1 && i <= row && j <= cow)//判断坐标是否合法 { if (arr[i - 1][j - 1] == ' ')//判断这个位置是否已经被使用过 { arr[i - 1][j - 1] = '*'; break; } else { printf("这个坐标已经被占用,请重新输入\n"); } } else { printf("输入坐标非法,请重新输入\n"); } } }
模拟电脑下棋
void ComputerMove(char arr[ROW][COW], int row, int cow) { int i = 0; int j = 0; printf("电脑开始下棋\n"); while (1) { i = rand() % ROW;//利用随机数函数将i控制在0到ROW-1 j = rand() % COW;//利用随机数函数将j控制在0到COW-1 if (arr[i ][j ] == ' ')//判断这个坐标是否被占用 { arr[i ][j ] = '#'; break; } } }
判断游戏输赢
- c表示游戏继续
- p表示游戏平局
- *表示玩家胜利
- #表示电脑胜利
char IsFull(char arr[ROW][COW], int row, int cow) { //判断是否平局 int i = 0; int j = 0; for ( i = 0; i <row; i++) { for ( j = 0; j < cow; j++) { if (arr[i][j] == ' ') { return 'C';//如果存在一个空格,则说明还能继续下棋 } } } return 'P';//表示棋盘已经满了,表示平局 } char IsWin(char arr[ROW][COW], int row, int cow) { int i = 0; int j = 0; for (i = 0; i < row; i++)//判断三行 { if (arr[i][0] == arr[i][1] && arr[i][1] == arr[i][2] && arr[i][0] != ' ') { return arr[i][0]; } } for (i = 0; i < cow; i++)//判断三列 { if (arr[0][i] == arr[1][i] && arr[1][i] == arr[2][i] && arr[0][i] != ' ') { return arr[0][i]; } } if (arr[0][0] == arr[1][1] && arr[2][2] == arr[1][1] && arr[1][1] != ' ')//判断左对角线 { return arr[1][1]; } if (arr[0][2] == arr[1][1] && arr[1][1] == arr[2][0] && arr[1][1] != ' ')//判断右对角线 { return arr[1][1]; } //判断平局 char full = IsFull(arr, cow, row);//判断是否棋盘是否满了 return full; //这个算法非常低级,只能实现简单的三子棋,不能实现更大的五子棋,需要学习算法来完成 }
game.h
#pragma once //这个头文件是用来被引用的,里面定义了需要的符号常量,和相关函数的声明 #include<stdio.h>//在头文件引入这个,在调用这个头文件就不需要再次去调用这个库函数 #include<stdlib.h>//提供随机数的函数 #include<time.h>//提供随机值的 #define ROW 3//定义所需二维数组的列长 #define COW 3//定义所需二维数组的行长 void printCaiDan();//这个函数用来打印菜单 void Initarr(char arr[ROW][COW],int row,int cow);//这个函数用来初始化数组内容都为空格 void printQiPan(char arr[ROW][COW], int row, int cow);//打印棋盘 void PlayerMove(char arr[ROW][COW], int row, int cow);//模拟玩家下棋 void ComputerMove(char arr[ROW][COW],int row,int cow);//模拟电脑下棋 char IsWin(char arr[ROW][COW],int row, int cow);//判断玩家赢还是电脑赢还是平局或者是继续游戏 char IsFull(char arr[ROW][COW], int row, int cow);//判断棋盘是不是已经满了
test.cpp
#define _CRT_SECURE_NO_WARNINGS 1 #include"game.h" void game() { char arr[ROW][COW];//定义所需要存储棋盘数据的空间 Initarr(arr,ROW,COW);//将这个数组的内容都初始化为空格 printQiPan(arr, ROW, COW);//将棋盘打印出来 char ret = 0; while (1) { PlayerMove(arr, ROW, COW);//这个函数模拟玩家下棋 printQiPan(arr, ROW, COW);//打印棋盘 ret=IsWin(arr, ROW, COW); if (ret!='C') { break; } ComputerMove(arr, ROW, COW);//模拟电脑下棋 printQiPan(arr, ROW, COW);//打印棋盘 ret = IsWin(arr, ROW, COW); if (ret != 'C') { break; } } if (ret== '*') { printf("玩家胜利\n"); printQiPan(arr, ROW, COW);//将棋盘打印出来 } if (ret == '#') { printf("电脑胜利\n"); printQiPan(arr, ROW, COW);//将棋盘打印出来 } if (ret=='P') { printf("平局\n"); printQiPan(arr, ROW, COW);//将棋盘打印出来 } } int main() { int input=0; srand((unsigned int)time(NULL)); do { printCaiDan(); printf("请输入——》"); scanf("%d", &input); switch (input) { case 1: game(); break; case 0: printf("结束游戏\n"); break; default: printf("输入非法字符,请重新输入\n"); break; } } while (input); return 0; }
简单的扫雷的实现
实现的功能和总体结构
- 功能:实现简单的扫雷,只能一个一个排除雷,不能一片展开
- game.h 头文件为了实现函数定义和符号定义
- game.cpp实现程序所有需要的函数
- test.cpp 实现程序的逻辑
- void printmeun();输出菜单
- void Initarr(char arr[ROWS][COLS], int rows, int cols, char set);//初始化棋盘的
- void Displayarr(char arr[ROWS][COLS], int row, int col);//打印棋盘
- void Setarr(char arr[ROWS][COLS], int row, int col);//布置雷
- void Findarr(char arr[ROWS][COLS], char arr1[ROWS][COLS], int row, int col);//排查雷
game.h
#include<time.h>//提供time的函数 #include<stdlib.h>//提供随机数函数 #define ROW 9//定义行 #define COL 9//定义列 #define ROWS ROW+2//定义整体的行 因为这样定义好给旁边的点计算有多少个雷 #define COLS COL+2//定义整体的列 #define COUNT 10//定义有多少个雷 void printmeun(); //初始化棋盘的 void Initarr(char arr[ROWS][COLS], int rows, int cols, char set); //打印棋盘 void Displayarr(char arr[ROWS][COLS], int row, int col); //布置雷 void Setarr(char arr[ROWS][COLS], int row, int col); //排查雷 void Findarr(char arr[ROWS][COLS], char arr1[ROWS][COLS], int row, int col);
test.cpp
#define _CRT_SECURE_NO_WARNINGS 1 #include"game.h" void game() { char arr[ROWS][COLS] = { 0 };//存放布置好的雷的信息 char arr1[ROWS][COLS] = { 0 };//存放好排除的雷的信息 //初始化棋盘 Initarr(arr, ROWS, COLS, '0');//'0' Initarr(arr1, ROWS, COLS, '*');//'*' //打印一下棋盘 Displayarr(arr, ROW, COL); Displayarr(arr1, ROW, COL); //布置雷 Setarr(arr, ROW,COL); /*Displayarr(arr, ROW, COL);*/ 排查雷 Findarr(arr, arr1, ROW, COL); } int main() { int input = 0; srand((unsigned int)time(NULL)); do { printmeun(); printf("请选择-》"); scanf("%d" ,&input); switch (input) { case 1: printf("开始扫雷游戏\n"); game(); break; case 0: printf("退出游戏\n"); break; default: printf("输出非法字符,请重新输入\n"); break; } } while (input); return 0; }
打印菜单
void printmeun() { printf("**************************\n"); printf("**************************\n"); printf("*** 退出选0, 玩游戏选1 ***\n"); printf("**************************\n"); printf("**************************\n"); }
初始化棋盘
//初始化棋盘的 void Initarr(char arr[ROWS][COLS], int rows, int cols, char set) { int i = 0; int j = 0; for ( i = 0; i < rows; i++) { for (j = 0; j < cols; j++) { arr[i][j] = set; } } }
打印棋盘
void Displayarr(char arr[ROWS][COLS], int row, int col) { int i = 0; int j = 0; printf("---扫雷游戏开始了---\n"); for ( i = 0; i <=col; i++) { printf("%d ", i);//打印出0 1 2.。。。。。9能知道属于那一列 } printf("\n"); for ( i = 1; i <= row; i++) { printf("%d ", i);//能知道属于那一行 for (j = 1; j <= col; j++) { printf("%c ", arr[i][j]); } printf("\n"); } }
布置雷
void Setarr(char arr[ROWS][COLS], int row, int col) { int i; int j; int count =COUNT;//一共布置count个雷 while (count) { i = rand() % 9 + 1; j = rand() % 9 + 1; if (arr[i][j]=='0')//如果这个地方不是雷,就可以设置为雷 { arr[i][j] = '1'; count--; } } }
排查雷
static int get_arr_num(char arr[ROWS][COLS], char arr1[ROWS][COLS], int x, int y) { int num=0; for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { num +=( arr[x+i][y+j] - '0'); } } //将arr[x][y]周围排除一遍 如果是'1'-0就是整型1 //将'0'-'0'为整数0 //不用查arr[x][y]因为arr[x][y]进这个函数肯定是‘0’ return num; } //排查雷 void Findarr(char arr[ROWS][COLS], char arr1[ROWS][COLS], int row, int col) { int x = 0; int y = 0; int win = 0; while (win < row * col - COUNT) { printf("请输入你想查的点的坐标\n"); scanf("%d%d", &x, &y); if (x >= 1 && x <= row && y >= 1 && y <= col) //判断坐标是否合法 { if (arr[x][y] == '1') { printf("你踩到雷了,游戏结束"); Displayarr(arr, ROW, COL); break; } else { arr1[x][y] = (get_arr_num(arr, arr1, x, y) + '0');//8+'0'就变成了'8'的ASCII码 win++; Displayarr(arr1, ROW, COL); } } else { printf("输入的坐标非法,请重新输入\n"); } } if (win== row * col - COUNT) //一个count个雷 一共row*col,所以只要玩row * col - COUNT次就说明游戏胜利 { printf("恭喜你,排雷成功\n"); Displayarr(arr, row, col); } }
简单的通讯录实现
实现的功能和总体概述
- 实现简单的通讯录信息存储功能
- 三个版本 静态版本 动态版本 文件版本
- 静态版本 1通讯录能存放1000个人的信息 2每个人的信息是学号+姓名+性别+年龄+电话+地址 3增加人的信息 4删除人的信息 5修改指定人信息 6查找指定人 7将通讯录按学号排序
- 动态版本 由于静态版本每次都开辟1000个空间,可能用不掉,所以会导致内存浪费在动态内存区开辟空间,一开始只开辟3个大小的空间当空间满了,增加2个信息
- 文件版本 当通讯录退出的时候,将信息写入文件 当通讯录初始化的时候,加载文件的信息进通讯录中
- Concst.h 头文件为了实现函数定义和符号定义
- Concst.cpp实现程序所有需要的函数
- test.cpp 实现程序的逻辑
- void menu() 打印菜单函数
- void Initcon(Concst* con) 初始化通讯录的函数 三个版本的功能都不一样
- void AddInformation(Concst *con) 添加信息的函数 动态和静态的版本不一样
- void PrintInformation(Concst* con) 打印通讯录的内容
- int FindInformation_NUM(Concst* con, char* p) 寻找num为*p的信息
- void DelteInformation(Concst* con)删除信息的函数
- void SearchInformation_num(Concst* con) 查找信息的函数并输出
- void ModifyInformation_num(Concst* con )修改指定num的数据
- void SORTInformation_num(Concst* con) 将通讯录以num排序
- void DestoryCon(Concst* con)释放通讯录的空间,是动态和文件版本的专属
- SaveCon(Concst* con)将通讯录的内容放入文件中存储
Concst.h
#pragma once //版本1静态版本 //1通讯录能存放1000个人的信息 //2每个人的信息是学号+姓名+性别+年龄+电话+地址 //3增加人的信息 //4删除人的信息 //5修改指定人信息 //6查找指定人 //7将通讯录按学号排序 //版本二 动态版本 //由于静态版本每次都开辟1000个空间,可能用不掉,所以会导致内存浪费 //在动态内存区开辟空间,一开始只开辟3个大小的空间 //当空间满了,增加2个信息 //版本三 文件版本 //当通讯录退出的时候,将信息写入文件 //当通讯录初始化的时候,加载文件的信息进通讯录中 #include<stdio.h>//引入标志输入输出库 #include<stdlib.h>//用malloc开辟动态空间 #include<string.h>//用memest来初始化通讯录内存 #define MAX_NAME 10//名字的最大长度 #define MAX_NUM 10//学号的最大长度 #define MAX_SEX 5//性别的最大长度 #define MAX_TELE 12//电话的最大长度 #define MAX_ADD 20//地址的最大长度 #define MAX 1000//静态通讯录的最大存储人数 #define DEFAULT_SIZE 3//动态刚开始初始化的通讯录能存储的人数 #define INC_SZ 2//动态内存不够时,每次增加的通讯录存储人数的大小 typedef struct PeoInfo { char num[MAX_NUM];//学号 唯一标识的 char name[MAX_NAME];//姓名 char sex[MAX_SEX];//性别 int age;//年龄 char tele[MAX_TELE];//电话 char add[MAX_ADD];//地址 }PeoInfo;//定义存储一个人信息的结构体类型 typedef struct Concst { //静态版本 // int sz;//表示现在通讯录里有多少个人的信息 // PeoInfo date[MAX];//存放放进来人的信息 //动态版本 int sz;//表示现在通讯录有多少人的信息 PeoInfo* date;//定义一个指针,指向存储人的信息的首地址 int capacity;//表示现在的存储空间有多大 };//定义通讯录的结构体类型 void menu(); void Initcon(Concst* con); void AddInformation(Concst *con); void PrintInformation(Concst* con); void DelteInformation(Concst* con); int FindInformation_NUM(Concst* con, char* p); void SearchInformation_num(Concst* con); void ModifyInformation_num(Concst *con); void SORTInformation_num(Concst* con); void DestoryCon(Concst* con); void SaveCon(Concst* con); void Load
test.h
#define _CRT_SECURE_NO_WARNINGS 1 #include"Concst.h" enum OPtion//定义一个枚举变量来表示对应的操作 { EXIT, ADD, DEL, SEARCH, MODIFY, SORT, PRINT }; int main() { int input; Concst con; Initcon(&con);//初始化通讯录 do { menu(); printf("请输入你需要的功能"); scanf("%d", &input); switch (input) { case EXIT: //动态版本要销毁通讯录 /* DestoryCon(&con);*/ //文件版应该先保存信息进文件,然后再销毁 SaveCon(&con);//保存信息 DestoryCon(&con); break; case ADD: //添加人的信息 AddInformation(&con); break; case DEL: //删除人的信息 DelteInformation(&con); break; case SEARCH: //用学号来查找一个人的信息 SearchInformation_num(&con); break; case MODIFY: //修改学号指定的人的信息 ModifyInformation_num(&con); break; case SORT: //按照学号来排序 SORTInformation_num(&con); break; case PRINT: PrintInformation(&con); break; default: break; } } while (input); }
实现打印菜单的函数
void menu() { printf("************************************\n"); printf("****1 添加 2删除*******************\n"); printf("****3 查询 4修改*******************\n"); printf("****5 排序 6打印*******************\n"); printf("****0 退出 ************************\n"); printf("************************************\n"); }
实现初始化通讯录的函数
void Initcon(Concst* con) { //静态版本 //con->sz = 0; //memset(con->date, 0, sizeof(con->date));//完成通讯录的存储数据的初始化 //动态版本 con->date= (PeoInfo*)malloc(DEFAULT_SIZE * sizeof(PeoInfo)); if (con->date==NULL) { perror("Initcon"); return; } con->sz = 0; con->capacity = DEFAULT_SIZE; //加载文件 LoadCon(con); }
void LoadCon(Concst* con)//加载文件信息进通讯录 { FILE* pf = fopen("contact.dat", "r"); if (pf==NULL) { perror("LoadCon"); return; } //读文件 fread每次最多读count个,如果可以读到count个就返回count, // 如果读不到,就返回一个比count小的值,表示读取结束 PeoInfo tmp = { 0 }; while (fread(&tmp, sizeof(PeoInfo), 1, pf)) { if (con->sz == con->capacity) { printf("空间不够,增加容量\n"); PeoInfo* ptr = (PeoInfo*)realloc(con->date, (con->capacity + INC_SZ) * sizeof(PeoInfo)); if (ptr != NULL) { con->date = ptr; con->capacity += INC_SZ; printf("增容成功\n"); } else { perror("AddInformation"); printf("增加类型失败"); return; } } con->date[con->sz] = tmp; con->sz++; } printf("文件导入成功\n"); //关闭文件 fclose(pf); pf = NULL; }
实现通讯录增加人的信息的函数
/ //静态版本的增加联系人 void AddInformation(Concst* con) { if (con->sz==MAX) { printf("通讯录已经满了,添加失败\n"); return; } else { printf("请输入学号->"); scanf("%s", con->date[con->sz].num); printf("请输入名字->"); scanf("%s", con->date[con->sz].name); printf("请输入性别->"); scanf("%s", con->date[con->sz].sex); printf("请输入年龄->"); scanf("%d",&( con->date[con->sz].age)); printf("请输入电话->"); scanf("%s", con->date[con->sz].tele); printf("请输入地址->"); scanf("%s", con->date[con->sz].add); con->sz++; printf("信息输入成功\n"); } }
//动态版本的增加联系人 void AddInformation(Concst* con) { if (con->sz==con->capacity) { printf("空间不够,增加容量\n"); PeoInfo*ptr=(PeoInfo*) realloc(con->date, (con->capacity + INC_SZ) * sizeof(PeoInfo)); if (ptr!=NULL) { con->date = ptr; con->capacity += INC_SZ; printf("增容成功\n"); } else { perror("AddInformation"); printf("增加类型失败"); return; } } //增加一个人的信息 printf("请输入学号->"); scanf("%s", con->date[con->sz].num); printf("请输入名字->"); scanf("%s", con->date[con->sz].name); printf("请输入性别->"); scanf("%s", con->date[con->sz].sex); printf("请输入年龄->"); scanf("%d",&( con->date[con->sz].age)); printf("请输入电话->"); scanf("%s", con->date[con->sz].tele); printf("请输入地址->"); scanf("%s", con->date[con->sz].add); con->sz++; printf("信息输入成功\n"); }
打印通讯录的函数
void PrintInformation(Concst* con) { printf("%-10s\t%-10s\t%-5s\t%-5s\t%-12s\t%-20s\n", "学号", "姓名", "性别", "年龄", "电话", "地址"); for (int i = 0; i < con->sz; i++) { printf("%-10s\t%-10s\t%-5s\t%-5d\t%-12s\t%-20s\n", con->date[i].num, con->date[i].name, con->date[i].sex, con->date[i].age, con->date[i].tele, con->date[i].add); } }
实现查找学号为num的函数
int FindInformation_NUM(Concst* con, char* p) { int i = 0; for ( i = 0; i < con->sz; i++) { if (strcmp(con->date[i].num, p)==0) { return i; } } return -1; } void SearchInformation_num(Concst* con) { printf("请输入你要查找的人的学号"); char p[10]; scanf("%s", p); int ret = FindInformation_NUM(con, p); if (ret==-1) { printf("查找的人不存在\n"); return; } else { printf("%-10s\t%-10s\t%-5s\t%-5s\t%-12s\t%-20s\n", "学号", "姓名", "性别", "年龄", "电话", "地址"); printf("%-10s\t%-10s\t%-5s\t%-5d\t%-12s\t%-20s\n", con->date[ret].num, con->date[ret].name, con->date[ret].sex, con->date[ret].age, con->date[ret].tele, con->date[ret].add); return; } }
删除信息的函数
int FindInformation_NUM(Concst* con, char* p) { int i = 0; for ( i = 0; i < con->sz; i++) { if (strcmp(con->date[i].num, p)==0) { return i; } } return -1; } void DelteInformation(Concst* con) { if (con->sz==0) { printf("通讯录为空,删除失败"); } else { char numfind[10]; printf("请输入你要查找学生的学号->"); scanf("%s", numfind); int ret=FindInformation_NUM(con, numfind); if (ret == -1) { printf("通讯录没有这个人,删除失败"); return; } else { for (int i = ret; i < con->sz-1; i++) { con->date[i] = con->date[i + 1]; } printf("删除成功\n"); con->sz--; } } }
改变特定num的信息的函数
int FindInformation_NUM(Concst* con, char* p) { int i = 0; for ( i = 0; i < con->sz; i++) { if (strcmp(con->date[i].num, p)==0) { return i; } } return -1; } void ModifyInformation_num(Concst* con) { printf("请输入你要修改的人的学号"); char p[10]; scanf("%s", p); int ret = FindInformation_NUM(con, p); if (ret == -1) { printf("要修改的人不存在\n"); return; } else { printf("请输入要修改的学号->"); scanf("%s", con->date[ret].num); printf("请输入要修改的名字->"); scanf("%s", con->date[ret].name); printf("请输入要修改的性别->"); scanf("%s", con->date[ret].sex); printf("请输入要修改的年龄->"); scanf("%d", con->date[ret].age); printf("请输入要修改的电话->"); scanf("%s", con->date[ret].tele); printf("请输入要修改的地址->"); scanf("%s", con->date[ret].add); return; } }
以num将通讯录排序
int sort_num(const void* e1, const void* e2) { return strcmp(((PeoInfo*)e1)->num, ((PeoInfo*)e2)->num); } void SORTInformation_num(Concst* con) { int sz = con->sz; qsort(con->date, sz, sizeof(con->date[0]), sort_num); printf("排序成功\n"); }
将动态空间释放的函数,动态版和文件版专属
void DestoryCon(Concst* con) { free(con->date); con->date = NULL; con->capacity = 0; con->sz = 0; }
将通讯录的内容导入文件,永久存储
//这样写可以显示我们能看懂的数据,自己写的 //void SaveCon(Concst* con) //{ // FILE* pf = fopen("contact.dat", "w"); // if (pf == NULL) // { // perror("SaveCon"); // return; // } // //写文件 // fprintf(pf, "%-10s\t%-10s\t%-5s\t%-5s\t%-12s\t%-20s\n", "学号", "姓名", "性别", "年龄", "电话", "地址"); // for (int i = 0; i < con->sz; i++) // { // fprintf(pf, "%-10s\t%-10s\t%-5s\t%-5d\t%-12s\t%-20s\n", con->date[i].num, // con->date[i].name, // con->date[i].sex, // con->date[i].age, // con->date[i].tele, // con->date[i].add); // } // //关文件 // fclose(pf); // pf = NULL; //} void SaveCon(Concst* con)//保存文件 { FILE* pf = fopen("contact.dat", "w"); if (pf == NULL) { perror("SaveCon"); } //写文件 int i = 0; for (int i = 0; i < con->sz; i++) { fwrite(con->date + i, sizeof(PeoInfo), 1, pf); } //关文件 fclose(pf); pf = NULL; }
最大公约数----辗转相除法
求两个数的最大公约数-------辗转相除法
最小公倍数=m*n/最大公约数
#incldue<stdio.h>int main() { //辗转相除法 int m = 0,n = 0; scanf("%d%d", &m, &n); int t = 0; while (t=m%n) { m = n; n = t; } printf("最大公约数是 %d",n); return 0; }
判断一个数是否是素数
#include<stdio.h> #include<math.h> //判断一个数是是不是素数 int ifprime(int x) { int ret = 1; for (int i = 2; i <=sqrt(x); i++) { if (x%i==0) { ret = 0; } } return ret; }
二分查找----有序数组查找
折半查找法,每次都是去找最中间的数,前提是这个数组必须是有序的,从小到大
#include<stdio.h> #define N 100 int main()//二分法前提查找的数据是有序的 { int arr[N] = { 0 }; for (int i = 0; i < N; i++) { arr[i] = i; } int n=0; scanf("%d", &n); int right = 99; int left = 0; while (left<=right) { int mid = (right + left) / 2; if (arr[mid] == n) { printf("找到了,下标是%d", mid); break; } if (arr[mid]>n) { right = mid-1; } if (arr[mid]<n) { left = mid+1; } } if (left>right){printf("该数字不存在");} return 0; }
递归实现字符串反转
#include<stdio.h> //用递归实现strlen int my_strlen1(char* str) { if (*str ) { return 1 + my_strlen1(++str); } else { return 0; } } //字符串逆序(递归实现) void reverse_string(char* arr) { int len = my_strlen1(arr); char tmp = *arr; *arr = *(arr + len - 1); *(arr + len - 1) = '\0'; if (strlen(arr + 1) >= 2) reverse_string(arr + 1); *(arr + len - 1) = tmp; } int main() { char arr[] = "wwwdwdbnscnab"; reverse_string1(arr); printf("%s", arr); return 0; }
递归实现汉诺塔问题
问题描述,有三个柱子分别是A,B,C,A柱子上套着n个圆盘,按照盘子大小从大到小自上而下的套着n个盘子,现在我们需要遵守
1每次只能移动最上面的盘子
2小盘子上不能放大盘子
那我们把n个盘子从A移到B需要多少步呢,该怎么移动呢?
先从一个简单的3个盘子开始分析
我们从上面的三个盘子移动的步骤中可以分析出来
前三步是A借助B将A除了最下面一个盘子其余盘子都按大到小移动到了C柱子,
中间一步 是将A上的盘子放到B上
后三步 是将C上的盘子借助A全放在B上
借助上面的思想,我们可以看看四层的怎么解决
1将上面三个盘子由A移到C(就是三层盘子的解法,上面是从A到B,这是从A到C解法是一样的,只是借助的柱子不一样)
2将最大的盘子移动到B
3将C的三个盘子借助A移到B(就是三层盘子的解法,上面是从A到B,这是从C到B,解法是一样的,只是借助的柱子不一样)
解法
解决n层汉诺塔的步骤,即:利用z柱将n个圆盘从x柱转移至y柱。
将n个圆盘从x柱,经由z柱中转,移到y柱时:
- 当n=0时:
- * 不做任何操作
- 当n>0时:
- * 首先,将n-1个圆盘从A柱移到C柱(解出n-1层)
- * 然后,将(n个中)最大的圆盘从A柱移到B柱
- * 最后,将n-1个圆盘从C柱移到B柱(解出n-1层)
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> int count = 0; void move(int num,char x,char y, char z) { printf("将%c最上面的%d个盘子移动到%c\n",x, num, z); } //汉诺塔模拟 x为起始柱子 y为中间柱子,z为目标柱子,num为要移动盘子的数量 void haoni(int num,char x, char y, char z) { if (num == 0) { } else { haoni(num - 1, x, z, y);//将x起始柱上的n-1个盘子从x借助目标柱子z移动到z中间柱子y上 move(1,x,y, z);//将x起始柱子上的最下面一个大盘子移到目标柱子上 count++; haoni(num - 1, y, x, z);//将y的目标柱子上的n-1个盘子借助起始柱x移到到目标柱子z上 } } int main() { int num=0; char x, y, z; scanf("%d %c %c %c",&num,&x, &y, &z); haoni(num, x, y, z); printf("%d ", count); return 0; }
青蛙跳台阶问题
问题描述
有一只青蛙,一次最多可以跳2个台阶,请问青蛙跳n个台阶有多少种跳法呢?
问题分析
- n=1时,只有一种跳法
- n=2时,有两种跳法(1,1)或者(2)
- n=3时,可以先跳到1,然后剩下2层就是2层的跳法,也可以先跳到2,然后剩下的就是1层的跳法
- n=4时,可以先跳到1,然后剩下的就是三层的跳法,也可以先跳到2,然后剩下的就是2层的跳法
- n=k时,就是(k-1)+(k-2)这两个跳法之和
代码实现
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> int tioatai1(int n) { if (n == 1) { return 1; } else if (n == 2) { return 2; } else { return tioatai1(n - 1) + tioatai1(n - 2); } } int main() { int n = 0; scanf("%d", &n); int sum = tioatai1(n); printf("%d ", sum); }
青蛙一次能跳k个台阶的解法
int frog(int n, int k) { if(n == 1) { return 1; } if(n == 2) { return 2; } ....... ....... if(n == k) { return ?//跳 k 层台阶时的方法 } return frog(n-1) + frog(n-2)+ ........+frog(n-k); }
存在的问题
我们发现这个递归存在着大量的重复运算,所以效率非常低,数据稍微大一点,就会跑死,怎么改进呢,我们可以定义两个全局数组来记录这个数据是否已经算过
优化的代码
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #define MAX 1000 int arr[MAX] = { 0,1,1 }; int arr1[MAX] = {0,1,2}; int tioatai(int n) { if (arr[n]==1) { return arr1[n]; } else { arr1[n] = tioatai(n - 1) + tioatai(n - 2); arr[n] = 1; return arr1[n]; } } int main() { int n = 0; scanf("%d", &n); int sum = tioatai(n); printf("%d ", sum); }
几个字符串库函数的实现
//strlen实现 //计数器版本 int my_strlen(const char* p) { assert(p); int count = 0; while (*p++) { count++; } return count; } //指针版本 int my_strlen1(const char* p) { assert(p); const char *start = p; while (*p++) { ; } return p - start-1; } //递归版本 int my_strlen2(const char* str) { assert(str); if (*str == '\0')//不能使用计数器版本 return 0; else return 1 + my_strlen1(str + 1); }
//strcpy char* my_strcpy(char* p, const char* str) { char* ret = p; assert(p && str); while ((*p++=*str++)) { ; } return ret; }
//strcat实现 char* my_strcat(char* p, const char* str) { assert(p && str); char* start = p; while (*p) { p++; } //while (*str) //{ // *p = *str; // p++; // str++; //} //*p = '\0'; while ((*p++=*str++)) { ; } return start; }
int my_strcmp(const char* arr, const char* arr1) { assert(arr && arr1); while (*arr==*arr1) { if (*arr==0) { return 0; } arr++; arr1++; } return *arr - *arr1; }
char* my_strstr(const char* str1, const char* str2) { assert(str1 && str2); const char* s1 = NULL; const char* s2 = NULL; const char* sr = str1; while (*sr) { s1 = sr; s2 = str2; while (*s1 && *s2 && !(*s1-*s2) ) { s1++; s2++; } if (*s2=='\0') { return (char*)sr; } sr++; } return NULL; }
//模拟实现strncpy char* my_strncpy(char* str2, const char* str1, size_t num) { assert(str1 && str2); char* start = str2; while ((num--)&&(*str2++=*str1++)) { ; } *str2= '\0'; return start; }
//模拟实现strncat char* my_strncat(char* str1, const char* str2, size_t num) { assert(str1&&str2); char* start = str1; while (*str1) { str1++; } while ( (num--) &&(*str1++=*str2++)) { ; } *str1 = '\0'; return start; }
几个内存函数的实现
memmove可以实现重复空间的替换
#define _CRT_SECURE_NO_WARNINGS 1 //memmove #include<stdio.h> #include<assert.h> void* my_memmove(void* dest, void* str, size_t num) { assert(dest); assert(str); void* sr = dest; char* dest1 = (char*)dest; char* str1 = (char*)str; int n = num; if (str > dest) { while (n--) { *dest1 = *str1; dest1++; str1++; } } else { while (n--) { *(dest1 + n) = *(str1 + n); } } return sr; } int main() { int arr[5] = { 1,2,3,4,5 }; my_memmove(arr+1, arr , 2 * sizeof(arr[0])); for (int i = 0; i < 5; i++) { printf("%d ", arr[i]); } return 0; }
实现memcpy
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<assert.h> void* my_memcpy(void* dest, void* str, size_t num) { assert(dest); assert(str); char* dest1 = (char*)dest; char* str1 = (char*)str; void* sr = dest; int n = num; while (n--) { *dest1 = *str1; dest1++; str1++; } return sr; } int main() { int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; int arr1[10] = { 0 }; my_memcpy(arr1, arr, sizeof(arr)); for (int i = 0; i < 10; i++) { printf("%d ", arr1[i]); } return 0; }
qsort的冒泡实现版本
qsort的使用
//实现以整数的大小来排序 int int_cmp1(const void* p, const void* p1) { return(*(int*)p - *(int*)p1); } typedef struct people1 { char name[20]; int age; double socre; }People1; //以名字排序 int name_cmp1(const void* p, const void* p1) { return strcmp((*(People1*)p).name, (*(People1*)p1).name); } //按年龄从小到大排序 int age_cmp1(const void* p, const void* p1) { return (*(People1*)p).age-(*(People1*)p1).age; } int age_cmp2(const void* p, const void* p1) { return (*(People1*)p1).age - (*(People1*)p).age; } int score_cmp1(const void* p, const void* p1) { if ((*(People1*)p1).socre - (*(People1*)p).socre > 0) { return -1; } else { return 1; } } int main() { int arr[10] = { 1,3523,3,2423,52,41,2,12,312,3 }; int sz = sizeof(arr) / sizeof(arr[0]); qsort(arr, sz, sizeof(arr[0]), int_cmp1); printarr(arr, sz); People1 p[3] = { {"zhangsan",19,89.5},{"lisi",22,60.0},{"wangwu",16,98.4} }; int sz1 = sizeof(p) / sizeof(People1); qsort(p, sz1, sizeof(p[0]), name_cmp1); printf("按名字从小到大排序\n"); for (int i = 0; i < sz1; i++) { printf("名字%-5s\t年龄%-5d\t成绩%-5.1lf\n", p[i].name, p[i].age,p[i].socre); } qsort(p, sz1, sizeof(p[0]), age_cmp1); printf("按年龄从小到大排序\n"); for (int i = 0; i < sz1; i++) { printf("名字%-5s\t年龄%-5d\t成绩%-5.1lf\n", p[i].name, p[i].age, p[i].socre); } qsort(p, sz1, sizeof(p[0]), age_cmp2); printf("按年龄从大到小排序\n"); for (int i = 0; i < sz1; i++) { printf("名字%-5s\t年龄%-5d\t成绩%-5.1lf\n", p[i].name, p[i].age, p[i].socre); } qsort(p, sz1, sizeof(p[0]), score_cmp1); printf("按成绩从小到大排序\n"); for (int i = 0; i < sz1; i++) { printf("名字%-5s\t年龄%-5d\t成绩%-5.1lf\n", p[i].name, p[i].age, p[i].socre); } return 0; }
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<string.h> typedef struct people { char name[20]; int age; }People; //冒泡排序实现qsort //以一个整数来决定顺序 int int_cmp(const void* p, const void* p1) { return(*(int*)p - *(int*)p1); } //以名字排序 int name_cmp(const void* p, const void* p1) { return strcmp((*(People*)p).name, (*(People*)p1).name); } void swap(const void* p, const void* p1,int size) { char* e1 = (char*)p; char* e2 = (char*)p1; for (int i = 0; i < size; i++) { char tmp = *(e1 + i); *(e1 + i) = *(e2 + i); *(e2 + i) = tmp; } } void my_qsort(void* str, int count, int size, int (*cmp)(const void*, const void*)) { int i = 0; for ( i = 0; i < count-1; i++) { int j = 0; for ( j = 0; j < count-1-i; j++) { if (cmp( (char*)str + j * size, (char*) str + (j + 1) * size) >0) { swap((char*)str + j * size, ((char*)str + (j + 1) * size),size); } } } } void printarr(int* arr,int sz) { for (int i = 0; i < sz; i++) { printf("%d ", arr[i]); } } int main() { int arr[10] = { 12,134,2,14,54,2,1,5,13,4 }; int sz = sizeof(arr) / sizeof(arr[0]); my_qsort(arr, sz, sizeof(arr[0]), int_cmp); printarr(arr, sz); People p[3] = { {"zhangsan",19},{"lisi",22},{"wangwu",16} }; int sz1 = sizeof(p) / sizeof(People); my_qsort(p, sz1, sizeof(p[0]), name_cmp); for (int i = 0; i < sz1; i++) { printf("%s %d", p[i].name, p[i].age); } return 0; }
杨式矩阵
有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵从上到下是递增的,
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<string.h> #include<assert.h> int find_num(int arr[3][3], int* px, int* py, int k) { int x = 0; int y = *py - 1; while (x<*px&&y>=0) { if (arr[x][y] < k) { x++; } else if(arr[x][y]>k) { y--; } else { *px = x; *py = y; return 1; } } return 0; } int main() { int arr[3][3] = { 1,2,3,2,3,4,4,5,6 }; int k; scanf("%d", &k); int x = 3; int y = 3; int ret = find_num(arr, &x, &y, k); if (ret==1) { printf("找到了%d %d\n",x,y); } else { printf("没有找到"); } return 0; }
字符串左旋
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<string.h> #include<assert.h> char* rolatr_left_string1(char* p, int num) { char* start = p; int i = 0; int length = strlen(p); for (i = 0; i < num; i++)//循环一次,左移一次 { //将元素的第一位数据储存下来 char tmp = *p; //将后面的元素都前移动一位 for (int j = 0; j < length - 1; j++) { *(p + j) = *(p + j + 1); } //将tmp储存到字符串的最后一个空间 *(p + length - 1) = tmp; } return start; } int main() { char p[100] = "AABCD"; rolatr_left_string2(p, 2); printf("%s", p); return 0; }
三步逆序法
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<string.h> #include<assert.h> char* reserve(char* left,char*right) { assert(left); assert(right); char* start = left; while (left<right) { char tmp = *left; *left = *right; *right = tmp; left++; right--; } return left; } //三步逆序法 char* rolatr_left_string2(char* p, int num) { assert(p); char* start = p; int n = strlen(p); reserve(p, p + num - 1); reserve(p+num,p+n-1); reserve(p, p + n - 1); return start; } int main() { char p[100] = "AABCD"; rolatr_left_string2(p, 2); printf("%s", p); return 0; }
如何判断一个字符串是不是由一个字符串左旋或者右旋得来的
第一种
#include<stdio.h> #include<string.h> #include<assert.h> //遍历所有可能的字符串进行比较 int if_string_rolate(char* s1, char* s2) { int length = strlen(s1); char arr[100]; for (int i = 0; i < length; i++) { strcpy(arr, s1); if ((strcmp(s2, rolatr_left_string1(arr, i)) == 0)) { return 1; } } return 0; } int main() { char s11[] = "AABCD"; char s21[] = "BCDAA"; int ret = if_string_rolate(s11, s21); printf("%d", ret); return 0; }
第二种
int if_string_rolate1(char* str1, char* str2) { int length = strlen(str1); if (length!=strlen(str2)) { return 0; } char* p = strncat(str1, str1, length); char*ret = strstr(str1, str2); /*if (ret==NULL) { return 0; } else { return 1; }*/ return ret!=NULL; } int main() { char arr[20] = "abcdef"; /*rolatr_left_string1(arr, 2); printf("%s", arr);*/ char arr1[20] = "bcdefa"; int ret = if_string_rolate1(arr, arr1); if (ret == 1) { printf("是他的旋转字符串"); } else { printf("不是他的旋转字符串"); } return 0; }
找单身狗游戏
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> void find(int arr[], int sz,int *x,int *y) { //将所以数据异或,得到两个单独存在的数字的异或结果 int i = 0; int ret = 0; for ( i = 0; i <sz; i++) { ret ^= arr[i]; } //计算出ret哪一位为1 int pos = 0; for ( i = 0; i <32; i++) { if ((ret >> i & 1) == 1) { pos = i; break; } } //把ret位为1的放在一个组,为0的放在另外一个组 for ( i = 0; i < sz; i++) { if ((arr[i] >> pos & 1) == 1) { *x ^= arr[i]; } else { *y ^= arr[i]; } } } int main() { int arr[] = { 1,2,2,1,3,4,4,5 }; int sz = sizeof(arr) / sizeof(arr[0]); int x = 0; int y = 0; find(arr, sz,&x,&y); printf("%d %d", x, y); }