#define _CRT_SECURE_NO_WARNINGS 1
#include
//写代码将三个数从大到小输出
void exchange(int* x, int* y)
{
int tmp = 0;
tmp = *x;
*x = *y;
*y = tmp;
}
int main() {
int a = 0;
int b = 0;
int c = 0;
scanf("%d %d %d", &a, &b, &c);
if (a < b)
{
exchange(&a, &b);
}
if (a < c)
{
exchange(&a, &c);
}
if (b < c)
{
exchange(&b, &c);
}
printf("%d %d %d", a, b, c);
}
引入第三个变量作为中间变量
int tmp = 0;
tmp = x;
x = y;
y = tmp;
#define _CRT_SECURE_NO_WARNINGS 1
#include
//求10个整数中的最大值
int main()
{
//获取10个数
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int i = 0;
for (i = 0; i <= 9; i++)
{
scanf("%d", &arr[i]);
}
//两两进行比较,较大的赋值给max
int j = 0;
int max = arr[0];
while (j < 10)
{
if (max < arr[j])
{
max = arr[j];
}
j++;
}
printf("%d ", max);
}
常见的求多个数里的最大值,创建max变量(擂台),两两进行比较,较大的赋值给max(打赢的继续站在擂台上),最后输出max即可,俗称打擂台
#define _CRT_SECURE_NO_WARNINGS 1
#include
int main()
{
long long n = 0;
long long m = 0;
while (scanf("%lld %lld", &n, &m) == 2)
{
//方法1:
求最小公倍数
//long long lcd = n;
//int i = 1;
//while (lcd % m)
//{
// lcd = n * i;
// i++;
//}
有了最小公倍数,利用数学公式gcd=n*m/lcd
//long long gcd = n * m / lcd;
//方法2:辗转相除法求最大公约数,效率比第一种方法高
long long i = n;
long long j = m;
long long r = 0;
while (r=i % j)//当余数为0时,j就是最大公约数
{
i = j;
j = r;
}
long long gcd = j;
long long lcd = n * m / gcd;//利用最大公约数和最小公倍数的数学关系公式
printf("%lld %lld", lcd , gcd);//%lld表示以long long类型格式打印
}
return 0;
}
方法1:多个数中任意一个数不停*i++(i从1开始)的结果ret对其他数进行取余,直至余数==0,ret就是最小公倍数
方法2:先用辗转相除法求最大公约数,再根据公式求最小公倍数
#define _CRT_SECURE_NO_WARNINGS 1
//打印乘法口诀表
//1*1=1
//2*1=2 2*2=4
//3*1=3 3*2=6 3*3=9
//......
//9*1=9 ....... 9*9=81
#include
int main()
{
int i = 0;
for (i = 1; i <= 9; i++)
{
int j = 0;
for (j = 1; j <= i; j++)
{
printf("%d*%d=%2d ", i, j, i * j);
}
printf("\n");
}
}
总结:int i = 0;
for (i = 1; i <= 9; i++)
{
int j = 0;
for (j = 1; j <= i; j++)
{
printf("%d*%d=%2d ", i, j, i * j);
}
标黄处j<=i中的i非常关键,因为i是外层循环的调整变量,才能得到正方形的一半,乘法口诀表形状就是正方形的一半,如果写成j<=9,只能得到一个完整的正方形
另外%2d用于2位右对齐,%-2d用于2位左对齐
#define _CRT_SECURE_NO_WARNINGS 1
#include
//练习:求n的阶乘
//方法1:循环
int main(){
int n = 0;
int i = 1;
int ret = 1;
int sum = 0;
scanf("%d", &n);
for (i = 1; i <= n; i++) {
ret = ret * i;
//练习:求1!+2!+3!+......+n!
sum += ret;
}
printf("%d\n", ret);
printf("%d", sum);
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
//用函数的递归求n的阶乘
// 1, n=1
//数学公式:f(n)={
// n*f(n-1), n>1
int f(int n)
{
if (n == 1)
{
return 1;
}
else
{
return n * f(n - 1);
}
}
#include
int main()
{
int n = 1;
while (n >= 1)
{
scanf("%d", &n);
printf("%d\n", f(n));
}
return 0;
}
写函数递归,基本就是按照数学公式在写, 比如f(n)和f(n-i)有某种数学关系,根据公式写就行
要求:多组输入(即循环输入),输入字符串长度不超过10000
#define _CRT_SECURE_NO_WARNINGS 1
//逆序排列字符串,非单纯逆序打印,是要改变字符串的内容
#include
#include
void reverse(char arr[])
{
int left = 0;
int right = strlen(arr) - 1;
while (left < right)
{
//交换首尾元素
int tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
}
//方法1:循环
int main()
{
char arr[10000] ={0};
//多组输入
while( gets(arr) != NULL )//防止输入语句死循环
{
reverse(arr);
printf("%s\n", arr);
}
return 0;
}
//方法2:函数递归
void Reverse(char arr[],int left,int right)
{
//拆成首尾交换和Reverse(char arr[],left+1,right-1)
if (left < right)
{
char tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
Reverse(arr, left + 1, right - 1);//注意不是left++;right--
}
}
int main()
{
char arr[10000] = {0};
while(gets(arr) !=NULL)
{
int left = 0;
int right = strlen(arr) - 1;
Reverse(arr, left, right);
printf("%s\n", arr);
}
return 0;
}
思考函数递归时不要局限于只设置1个参数,设置多参数时,可能思路会更清晰,递归就是每递进一次,参数都在发生改变,所以考虑把递进里改变的变量设置成参数
字符串属于数组里非常特殊的存在,操作字符串时最好使用字符串特有的库函数,比如操作字符串时,gets(arr)函数就比scanf("%s",arr)要好,strlen(arr)就比sizeof(arr)/sizeof(arr[0])要好,
因为scanf遇到空格就停止,所以不能输入有空格的字符串内容,strlen不会把字符串结束标志'\0'
算入长度,而sizeof(arr)/sizeof(arr[0])会,且在此题中arr[10000]默认初始化10000个'\0',会导致right错误,因为我们只逆序我们输入的一堆’\0'前面的n个字符,而不是逆序10000个字符
比如 I like beijing. 经过函数后变为:beijing. like I
思路:先全部字符逆序,再一个一个单词内部逆序。例如:
I like beijing.
.gnijieb ekil i
beijing. like i
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
//将一句话的单词进行倒置,标点不倒置。比如 I like beijing. 经过函数后变为:beijing. like I
//思路:先全部字符逆序,再一个一个单词内部逆序
void reverse(char* left , char* right)
{
while (left < right)
{
char tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
int main()
{
char arr[100] = { 0 };
gets(arr);
//先全部字符逆序
reverse(arr,arr+strlen(arr)-1);
//printf("%s\n", arr);
//单词内部逆序
char* left = arr;
char* right = left;
while (*left!='\0')
{
while (*right != ' '&&*right!='\0')
{
right++;
}
reverse(left, right - 1);
left = right + 1;
right = left;
}
printf("%s", arr);
return 0;
}
总结:
在单个数组内部重复进行某些修改,起修改作用的自定义函数参数最好使用双指针(首尾端指针),这样整个数组就可以重复使用,不用创建很多数组,参数设置为指针比设置为下标更精简
#define _CRT_SECURE_NO_WARNINGS 1
//写一个递归函数digit_sum(n),输入一个非负整数,返回组成他的数字之和
//思考怎样得到比如1729的每一位,并求和
//个位是最好获取的,所以拆成个位:1729%10和digit_sum(172),172就是1729/10的结果
#include
int digit_sum(unsigned int a)
{
if (a > 9) {
int sum = a % 10 + digit_sum(a / 10);
return sum;
}
return a;
}
int main()
{
unsigned int a = 0;
scanf("%u", &a);
int ret=digit_sum(a);
printf("%d\n", ret);
}
个位是最好获取的,所以拆成个位:1729%10和digit_sum(172)的和,172就是1729/10的结果
unsigned int是防止你输入负数,%u是unsigned int的输入和打印形式
数学公式
#define _CRT_SECURE_NO_WARNINGS 1
//写一个函数实现n的k次方,用函数递归实现
#include
double Pow(int n, int k)
{
if (k == 0)
{
return 1.0;
}
else if (k > 0)
{
return n* Pow(n, k - 1);
}
else
{
return 1.0 / Pow(n, -k);
}
}
int main()
{
int n = 0;
int k = 0;
scanf("%d %d", &n, &k);
printf("%lf\n",Pow(n, k));
return 0;
}
小乐乐上课需要走n阶台阶,因为他腿比较长,所以每次可以选择走一阶或者走两阶,那么他一共有多少种走法?
如果只有1个台阶,就只有1种走法,如果有2个台阶,有2种走法,当有n个台阶,
若第一步走1阶,那还剩n-1个台阶,有f(n-1)种走法
若第一步走2阶,还剩n-2个台阶,有f(n-2)种走法
#define _CRT_SECURE_NO_WARNINGS 1
#include
int f(int n)
{
if (n <= 2)
{
return n;
}
else
{
return f(n - 1) + f(n - 2);
}
}
int main()
{
int n = 0;
scanf("%d", &n);
printf("%d\n", f(n));
}
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
//练习1:判断一个数是否是素数(除了本身和1外,没有其他数能整除)
//写一个函数
int is_prime(int n)
{
int j = 0;
for (j = 2; j <= sqrt(n); j++)
{
if (n % j == 0)
{
return 0;
}
}
return 1;
}
int main()
{
int i = 0;
scanf("%d", &i);
if (is_prime(i))
{
printf("这个数是素数");
}
else
{
printf("这个数不是素数");
}
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
//
//输入描述:
//多组输入,每一行输入一个字符。
//输出描述:
//针对每组输入,输出单独占一行,判断输入字符是否为字母,输出内容详见输出样例。
#include
int main()
{
char ch = 0;
// %c前面加个空格表示跳过下一个字符之前的所有字符,不用getchar()清理缓冲区
while (scanf(" %c", &ch) == 1)//防止死循环
{
if (ch >= 'A' && ch <= 'z')
{
printf("%c is an alphabet.\n", ch);
}
else
{
printf("%c is not an alphabet.\n", ch);
}
//getchar();//清理缓冲区,防止换行\n被scanf读取
}
return 0;
}
1.清理缓冲区(常用 getchar() 来清理)
2. %c前面加个空格scanf(" %c", &ch)表示读取时跳过下一个字符之前的所有空白字符
多组输入的意思就是循环输入
通常在判断条件加一句scanf("%c",&ch) !=EOF或scanf("%c",&ch)==1,1表示scanf接收的元素个数,如果输入的是2个数则是2
或getchar() != EOF
例如:while (scanf(" %c", &ch) != EOF)//防止死循环或while(scanf("%c %c" ,&ch1,&ch2)==2)
#define _CRT_SECURE_NO_WARNINGS 1
#include
int is_leap_year(int n) {
if ((n % 4 == 0 && n % 100 != 0) || (n % 400 == 0))
{
return 1;
}
return 0 ;
}
int main() {
//练习2:打印1000-2000年的闰年
// 闰年的判断规则:可以被4整除,但不能被100整除;或可以被400整除
//首先获取1000-2000的数
int i = 0;
for (i = 1000; i <= 2000; i++)
{
if(is_leap_year(i))
printf("%d ",i);
}
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
#include
#include
int main()
{
//创建2个数组
char arr1[] = "welcome to bit!";
char arr2[] = "###############";
//获取下标
int left = 0;
int right = strlen(arr1) - 1;
while (left <= right)
{
arr2[left] = arr1[left];
arr2[right] = arr1[right];
遍历arr2
//int i = 0;
//for (i = 0; i < strlen(arr2); i++)
// {
// printf("%c", arr2[i]);
//}
//printf("\n");
//其实不需要遍历,因为字符串可以直接打印
printf("%s\n", arr2);
left++;
right--;
Sleep(1000);//库函数休眠,单位是毫秒ms
system("cls");//system执行系统命令行库函数,cls清屏命令行
}
printf("%s", arr2);
return 0;
}
只允许输入三次密码,如果密码正确则提示登录成,如果三次均输入错误,则退出程序。
int main()
{
char password[10] = { 0 };
//输入密码
int i = 0;
for (i = 1; i <= 3; i++)
{
scanf("%s", password);
//比较密码
if (strcmp(password, "123456") == 0)
{
printf("密码正确");
break;
}
else
{
printf("密码错误,请重新输入\n");
}
}
if (i > 4)
{
printf("输入错误密码超3次,已强制退出");
}
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
#include
#include
#include
void menu()
{
printf("**********************************\n");
printf("*********** 1.play **********\n");
printf("*********** 0.exit **********\n");
printf("**********************************\n");
}
void game()
{
//电脑产生一个0-100的随机值
srand((unsigned) time(NULL));
int num = rand() % 100 + 1;
//猜一个数字0-100
int guess = 0;
while (1)
{
scanf("%d", &guess);
if (num > guess)
{
printf("猜小了\n");
}
else if (num < guess)
{
printf("猜大了\n");
}
else
{
printf("恭喜你,猜对了\n");
break;
}
}
}
int main()
{
int input = 0;
do
{
menu();
//选择是否玩游戏,请输入1或者0
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
break;
default:
printf("输入有误,请重新输入\n");
break;
}
} while (input);
return 0;
}
总结:为了实现一个变量a的值总是比某个值n小 ,通常用a%n,得到的值就是0至n-1
#define _CRT_SECURE_NO_WARNINGS 1
//用冒泡排序法把键盘输入的10个数逆序排序
#include
//创建冒泡排序函数
void bubble_sort(int arr[],int sz)
{
//算需要几趟冒泡排序
//int sz = sizeof(arr) / sizeof(arr[0]);数组传参,函数内部计算sizeof(arr)其实是算的指针大小
//所以不能这样写,考虑写在函数外部且函数内部可用,所以用参数的方式最合适
int flag=1;//用于判断输入的数组是否本来就是逆序排序的,如果是,就不需要进行第二趟冒泡排序了
int i = 0;
for (i = 0; i < sz-1; i++)
{
//算一趟冒泡排序有几对比较的数
int j = 0;
for (j = 0; j
从左至右两两成对进行比较,不符合想要的顺序则交换2个数字,n个数字需要n-1趟冒泡排序(行i),第1趟冒泡排序需要n-1对比较的数 ,第2趟需要n-2对比较的数.......第n-1趟需要1对比较的数(列j)。列号是在随着行号增加在减小1,所以内层循环发判断语句是j
int main()
{
int arr1[2000] = { 0 };
int arr2[1000] = { 0 };
int n = 0;
int m = 0;
scanf("%d %d", &n, &m);
int i = 0;
for (i = 0; i < n; i++)
{
scanf("%d", &arr1[i]);
}
for (i = 0; i < m; i++)
{
scanf("%d", &arr2[i]);
}
//合并到arr1
for (i = n; i < n + m; i++)
{
arr1[i] = arr2[i - n];
}
//冒泡排序
bubble_sort(arr1, n + m - 1);
for (i = 0; i < n + m; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
int main()
{
int arr1[2000] = { 0 };
int arr2[1000] = { 0 };
int n = 0;
int m = 0;
scanf("%d %d", &n, &m);
int i = 0;
for (i = 0; i < n; i++)
{
scanf("%d", &arr1[i]);
}
for (i = 0; i < m; i++)
{
scanf("%d", &arr2[i]);
}
//方法2:边排序边合并
int arr[3000] = { 0 };
int j = 0;
int k = 0;
for (i = 0,j = 0; i < n && j < m; )
{
if (arr1[i] < arr2[j])
{
arr[k++] = arr1[i++];
}
else
{
arr[k++] = arr2[j++];
}
}
if (i < n)//说明arr1内部还有剩余元素没比较
{
for (; i < n; i++)//遍历剩余元素
{
arr[k++] = arr1[i];
}
}
if (j < m)//说明arr2内部还有剩余元素没比较
{
for (; j < m; j++)//遍历剩余元素
{
arr[k++] = arr2[j];
}
}
for (i = 0; i < n + m; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
总结:方法2仅适用于输入的本来就是有顺序的数组,因为存在剩余元素未比较,即未排序。如果输入的是乱序数组,只能用方法1
#include
#include
void left_rotate(char arr[], int k)
{
k %= strlen(arr);//为了保证k小于字符串长度
//第一步:将a取出来放到临时空间
int i = 0;
for (i=0; i < k; i++)
{
char tmp = arr[0];
//第二步:将a后面所有的字符往前挪一步
int j = 0;
for (j = 0; j < strlen(arr)-1; j++)
{
arr[j] = arr[j + 1];
}
//第三步:将tmp放到最后
arr[j] = tmp;
}
}
int main()
{
char arr[6] = "abcde";
int k = 0;
scanf("%d", &k);
left_rotate(arr, k);
printf("%s\n", arr);
return 0;
}
#include
#include
#include
void reverse(char* left, char* right)
{
assert(left && right);
while (left < right)
{
char tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
void left_rotate(char arr[], int k)
{
k %= strlen(arr);//为了保证k小于字符串长度
reverse(arr, arr + k - 1);//第一步:逆序k个字符
reverse(arr + k, arr + strlen(arr) - 1);//第二步:逆序剩余部分的字符
reverse(arr, arr + strlen(arr) - 1);//第三步:逆序整个字符串
}
int main()
{
char arr[6] = "abcde";
int k = 0;
scanf("%d", &k);
left_rotate(arr, k);
printf("%s\n", arr);
return 0;
}
分析:穷举arr1左转的可能性和arr2一一对比,左旋k个字符和右旋len-k个字符的结果一样,所以左旋的所有可能性就是旋转的所有可能性。
#include
#include
int is_rotate(char arr1[], char arr2[])
{
//穷举arr1旋转的所有可能性和arr2对比
int len = strlen(arr1);
int i = 0;
for (i = 0; i < len - 1; i++)//arr1左旋len-1次
{
char tmp = arr1[0];
int j = 0;
for (j = 0; j < len - 1; j++)
{
arr1[j] = arr1[j + 1];
}
arr1[len - 1] = tmp;
if (strcmp(arr1, arr2) == 0)//有一种旋转后结果和arr2相等则证明arr2可由arr1旋转而来
{
return 1;
}
}
return 0;//穷举完没有一种旋转结果和arr2相等,则arr2不是由arr1旋转而来
}
int main()
{
char arr1[] = "abcdef";
char arr2[] = "defabc";
int ret = is_rotate(arr1, arr2);
if (ret == 1)
{
printf("yes\n");
}
else
{
printf("no\n");
}
return 0;
}
arr1追加一个自己,结果就包含了arr1旋转的所有可能性
#include
#include
int is_rotate(char arr1[], char arr2[])
{
int len1 = strlen(arr1);
int len2 = strlen(arr2);
if (len1 != len2)//如果arr1和arr2长度不同,那一定不可能是旋转得来的
return 0;//return自带分支效果
strncat(arr1, arr1, len1);//arr1追加一个自己,结果就包含了arr1旋转的所有可能性
if (strstr(arr1, arr2) != NULL)//寻找子串
{
return 1;
}
else
{
return 0;
}
}
int main()
{
char arr1[20] = "abcdef";
char arr2[] = "defab";
int ret = is_rotate(arr1, arr2);
if (ret == 1)
{
printf("yes\n");
}
else
{
printf("no\n");
}
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
//写一个三子棋游戏
#include "game.h"
void game(char board[ROW][COL], int row, int col)
{
char ret = 0;
//写个初始化函数,调用初始化数组
init_board(board, ROW, COL);
//打印显示初始棋盘
display_board(board, ROW, COL);
while (1) {
//玩家先出棋,函数
player_move(board, ROW, COL);
//判断输赢函数
ret = is_win(board, ROW, COL);
display_board(board, ROW, COL);
if (ret != 'c')
{
break;
}
//电脑出棋,函数
computer_move(board, ROW, COL);
//判断输赢函数
ret = is_win(board, ROW, COL);
display_board(board, ROW, COL);
if (ret != 'c')
{
break;
}
}
if (ret == '*')
{
printf("玩家赢\n");
}
else if (ret == '#')
{
printf("电脑赢\n");
}
else
{
printf("平局\n");
}
display_board(board, ROW, COL);
}
int main()
{//游戏至少进行一次,所以用do while循环
//三子棋看形状是个正方形,肯定要用到二维数组
//创建二维数组
char board[ROW][COL] = { 0 };
//设置rand随机数起始点
srand((unsigned int) time(NULL));
int input = 0;
do
{
//首先打印游戏菜单
menu();
//键盘输入选择
printf("请输入1或0 :");
scanf("%d", &input);
//判断输入的数是否是1或者0,决定是否进入游戏
if (input == 1)
{
game(board, ROW, COL);
}
else if (input == 0)
{
printf("退出游戏");
}
else
{
printf("输入错误,请输入1或0\n");
}
} while (input);
}
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu()
{
printf("***********************\n");
printf("*****1.play 0.exit*****\n");
printf("***********************\n");
}
void init_board(char board[ROW][COL],int row,int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
void display_board(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
//这样就写的太死了,以后想改成5x5的棋盘或10x10的棋盘之类就很麻烦
// //先打印数据
//printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
//if (i < row - 1)
//{
// //再打印分割线
// printf("---|---|---\n");
//}
//改进
//先打印第一行数据
for (j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)//最后一列不打印
{
printf("|");
}
}
printf("\n");
//再打印行分割线
if (i < row-1)//最后一行不打印
{
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)//最后一列不打印
{
printf("|");
}
}
printf("\n");
}
}
}
void player_move(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
//键盘输入坐标
while (1)
{
printf("玩家下棋,请输入您要下棋的坐标\n");
scanf("%d,%d", &x, &y);
//先判断输入的坐标是否超出棋盘范围
if (x >= 1 && x <= col && y >= 1 && y <= row)
{
//再判断输入的坐标上有无棋子
if (board[x-1][y-1] == ' ')
{
board[x-1][y-1] = '*';
break;
}
else
{
printf("此坐标被占用,请另选坐标\n");
}
}
else
{
printf("输入的坐标超出棋盘范围,请另选坐标\n");
}
}
}
void computer_move(char board[ROW][COL], int row, int col)
{
printf("电脑下棋\n");
while (1)
{
//电脑随机产生1,1到3,3的坐标
int x = rand() % row + 1;
int y = rand() % col + 1;
//再判断输入的坐标上有无棋子
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '#';
break;
}
}
}
//判断棋盘是否满了的函数,满了返回1,没满返回0
int is_full(char board[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
{
return 0;
}
}
}
return 1;
}
char is_win(char board[ROW][COL], int row, int col)
{
//三子棋输赢有4种结果,1玩家赢;2电脑赢;3棋盘下满了,未分胜负,平局;4棋盘还未下满,继续下
// 规定如果玩家赢了则返回*,电脑赢则返回#,平局返回'Q',继续返回'c'
//判断是否有一方赢了
//判断是否有哪行是连续三颗*或#
int i = 0;
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2]&& board[i][0] != ' ')
{
return board[i][0] ;
}
}
//判断是否有哪列是连续三颗*或#
int j = 0;
for (j = 0; j < col; j++)
{
if (board[0][j] == board[1][j] && board[1][j] == board[2][j]&& board[0][j] != ' ')
{
return board[0][j] ;
}
}
//判断是否哪条对角线是连续三颗*或#
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
{
return board[0][0];
}
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')
{
return board[0][2];
}
//判断是否平局,需要遍历数组,没有一个元素是' '就行
if (is_full(board, ROW, COL))
{
return 'Q';
}
return 'c';
}
#pragma once
#include
#include
#include
#define ROW 3
#define COL 3
void menu();
void init_board(char board[ROW][COL], int row, int col);
void display_board(char board[ROW][COL], int row, int col);
void player_move(char board[ROW][COL], int row, int col);
void computer_move(char board[ROW][COL], int row, int col);
char is_win(char board[ROW][COL], int row, int col);
void game(char board[ROW][COL], int row, int col);
#define _CRT_SECURE_NO_WARNINGS 1
//写一个扫雷游戏
#include "game2.h"
void menu()
{
printf("*************************\n");
printf("******* 1.play ********\n");
printf("******* 0.exit ********\n");
printf("*************************\n");
}
void game()
{
//扫雷游戏首先需要2个二维数组分别来存放布雷数据和排雷数据
char mine[ROWS][COLS] = {0};
char show[ROWS][COLS] = {0};
//初始化,未布雷前mine数组全填'0',未排雷前show数组全填'*'表示神秘
init_board(mine,ROWS,COLS,'0');
init_board(show,ROWS,COLS,'*');
//display_board(mine, ROW, COL);//遍历
//开始布雷,随机在mine数组ROW行COL列范围内布雷COUNT个,雷用'1'表示
lay_mines(mine, ROW, COL);
display_board(mine, ROW, COL);//遍历
display_board(show, ROW, COL);//遍历
//排雷,输入坐标
find_mine(mine,show,ROW,COL);
}
int main()
{
//设置随机数生成起点
srand((unsigned int)time(NULL));
int input = 0;
//游戏至少执行一次,所以用do while循环
do
{
//显示游戏菜单
menu();
//请选择是否玩游戏
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;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include "game2.h"
void init_board(char board[ROWS][COLS], int rows, int cols,char ch)
{
int i = 0;
int j = 0;
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
board[i][j] = ch;
}
}
}
void display_board(char board[ROWS][COLS], int row, int col)
{
printf("------扫雷游戏-----\n");
int i = 0;
int j = 0;
for (j = 0; j <= col; j++)
{
//打印列号
printf("%d ", j);
}
printf("\n");
for (i = 1; i <= row; i++)
{
//打印行号
printf("%d ", i);
for (j = 1; j <= col; j++)
{
printf("%c ",board[i][j]);
}
printf("\n");
}
printf("------扫雷游戏-----\n");
}
void lay_mines(char board[ROWS][COLS], int row, int col)
{
int count = COUNT;
while (count)
{
//随机在mine数组ROW行COL列范围内布雷COUNT个,雷用'1'表示
//获取随机坐标,范围(1,1)-(ROW,COL)
int x = rand() % row + 1;
int y = rand() % col + 1;
//防止同一坐标重复布雷
if (board[x][y] == '0')
{
board[x][y] = '1';
count--;
}
}
}
int around_mine_count(char board[ROWS][COLS], int x, int y)
{
return (board[x - 1][y - 1] + board[x - 1][y] + board[x - 1][y + 1] +
board[x][y - 1] + board[x][y + 1] +
board[x + 1][y - 1] + board[x + 1][y] + board[x + 1][y + 1]) - 8 *'0';
}
//写个展开一片功能函数
//void unfold(char mine[ROWS][COLS], char show[ROWS][COLS], int x, int y,int count)
//{
// if (count == 0)
// {
// int i = 0;
// for (i = x - 1; i <= x + 1; i++)
// {
// int j = 0;
// for (j = y - 1; j <= y + 1; j++)
// {
// count = around_mine_count(mine, i, j);
// if (show[i][j] == '*')
// {
// unfold(mine, show, i - 1, j - 1,count);
// }
// }
// }
// }
//
//}
void find_mine(char mine[ROWS][COLS], char show[ROWS][COLS], int row, int col)
{
//输入排查坐标
int x = 0;
int y = 0;
int win = 0;
while (win= 1 && x <= row && y >= 1 && y <= col)
{
//检查是否重复排查相同坐标
if (show[x][y] != '*')
{
printf("请勿重复排查同一坐标\n");
}
else
{
if (mine[x][y] == '1')//如果是雷
{
printf("很遗憾你被炸死了\n");
display_board(mine, ROW, COL);//遍历
break;
}
else//如果不是雷
{
//显示周围8个坐标里有多少个雷'1',写个函数
int count = around_mine_count(mine, x, y);
//显示到show数组对应坐标处,但应该转换成字符类型,比如周围有3个雷,int 3转换成'3','0'和'3'相差3,所以+'0'就行
show[x][y] = count + '0';
//展开一片
//unfold(mine, show, x, y,count);
display_board(show, ROW, COL);//遍历
win++;
}
}
}
else
{
printf("输入坐标非法,请重新输入");
}
}
if (win == row * col - COUNT)
{
printf("恭喜你,排雷成功\n");
display_board(mine, ROW, COL);//遍历
}
}
//标记明确是雷的坐标
//展开一片的功能:该坐标不是雷;该坐标周围没有雷;该坐标没有被排查过,递归实现
#pragma once
#include
#include
#include
#define ROW 9
#define COL 9
#define ROWS ROW+2
#define COLS COL+2
#define COUNT 10
void init_board(char board[ROWS][COLS], int rows, int cols,char ch);
void display_board(char board[ROWS][COLS], int row, int col);
void lay_mines(char board[ROWS][COLS], int row, int col);
void find_mine(char mine[ROWS][COLS],char show[ROWS][COLS],int row, int col);
int tmp = a;
a = b;
b= tmp
此方法容易造成溢出,因为int是有表示范围的,若a,b都非常大,接近int能表示的最大数,那么a+b很可能就超过了int能表示的最大数了,所以不推荐
int a=10;
int b=20;
a=a+b;
b=a-b;
a=a-b;
此方法由于异或不会造成进位,所以a^b不可能超过int的表数范围,所以不会造成溢出,但是可读性不高,且仅仅适用于整数
#include
int main()
{
int a = 10;
int b = 20;
a = a^b;
b = a^b;
a = a^b;
printf("a = %d b = %d\n", a, b);
return 0;
}
三种方法最推荐的还是第一种
#define _CRT_SECURE_NO_WARNINGS 1
#include
#include
//自己实现一个求字符串长度的my_strlen()函数
int my_strlen(const char* str)//const防止str指向的对象在此函数内部被修改
{
int count = 0;
assert(str);//断言,防止传参传空指针
while (*str != '\0')
{
count++;
str++;
}
return count;
}
int main()
{
char arr[] = "abcde";
printf("%d\n",my_strlen(arr));
return 0;
}
int my_strlen(char* str)
{
if (*str == '\0')
{
return 0;
}
else
{
return 1 + my_strlen(str + 1);
}
}
int main()
{
char arr[] = "abcde";
printf("%d\n",my_strlen(arr));
return 0;
}
int my_strlen(char* str)
{
char* start = str;
while (*str != '\0')
{
str++;
}
return str - start;
}
int main()
{
char arr[] = "abcde";
printf("%d\n",my_strlen(arr));
return 0;
}
思考如何获取整数二进制补码中的每一位?
十进制数获取每一位是a%10; a/10%10; a/10/10%10......直至取余前的商为0,余数反转即可
同理二进制数获取每一位是a%2; a/2%2; a/2/2%2......直至取余前的商为0,余数反转即可
int Count1(unsigned int a)
{
int count = 0;
while (a)
{
if ((a % 2) == 1)
{
count++;
}
a = a / 2;
}
return count;
}
int main()
{
int a = -1;
printf("%d\n",Count1(a));
return 0;
}
注意形参必须是unsigned int ,接收负数时会把它看成一个很大的正数,因为无符号整型的二进制位是没有符号位的,最高位不再是符号位,这样才可以统计负数的补码中1的个数,否则无法统计
a|1如果等于a本身,就说明a的二进制最低位是1,再右移1,循环进行比较
或a&1如果等于1,也说明a的二进制最低位是1,再右移1,循环进行比较
a&1获取的是a本身的二进制最低位,配合a>>i,i++.就能获得a的二进制的每一位
int Count1(int a)
{
int count = 0;
int i = 0;
/*while (i < 32)
{
if ((a | 1) == a)
{
count++;
}
a >>= 1;
i++;
}*/
//或
for (i = 0; i < 32; i++)
{
if (((a >> i) & 1) == 1)
{
count++;
}
}
return count;
}
思考a=a&(a-1)会发生什么现象
现象就是每次都会去掉a二进制位中的一个1,直至a为0,执行了几次即有几个1
int Count1(int a)
{
int count = 0;
while (a)
{
a = a & (a - 1);
count++;
}
return count;
}
n=n&(n-1)还有很多用途。比如判断一个数是不是2的n次方
我们观察到,如果一个数是2的n次方,则其二进制位中只有1个1,即上面代码的count=1
方法1:a%2; a/2%2; a/2/2%2......直至取余前的商为0,余数反转即可
方法2:a&1获取的是a本身的二进制最低位,配合a>>i,i++.就能获得a的二进制的每一位
输入描述:
多组输入,一个整数(2~20),表示直角三角形直角边的长度,即“*”的数量,也表示输出行数。
输出描述:
针对每行输入,输出用“*”组成的对应长度的直角三角形,每个“*”后面有一个空格
示例
输入:
4
输出:
* * * * * * * * * *
观察图案发现图案是个正方形," "空格随着行号增加不断减少,"* "随着行号增加不断增加,一行上控制打印" "和"* "的变量是相反变化的,分开打印'' "和"* "
#include
int main()
{
int n = 0;
int i = 0;
int j = 0;
int k = 0;
int p = 0;
while (scanf("%d", &n) == 1)//多组输入
{
for (i = 0, p = n-1 ; i < n; i++, p--)
{
for (k = 0; k < p; k++)
{
printf(" ");
}
for (j = 0; j <= i; j++)
{
printf("* ");
}
printf("\n");
}
}
return 0;
}
观察图案发现规律,一行上(行号+列号) 打印图案的题,基本都是由*和空格组成的正方形,双层for循环嵌套打印 ,i控制行,j控制列 观察i和j之间的关系,找到规律即可。找i和j之间的规律关系时最好在画图工具里写出来i和j每次的取值,更容易找出规律,不要纯靠脑补。 要穷举比赛名次所有的可能性,需要5层循环嵌套使用,如果不嵌套则做不到穷举 ,因为如果分开使用循环,排列组合的元素每次循环是没有关联的 时间复杂度小于O(N)意思是不能通过遍历来查找,遍历查找的时间复杂度就是O(N) 查找杨氏矩阵内某元素k,若找到则返回1及其下标,找不到返回0和(-1,-1) 分析:通过观察杨氏矩阵就是每行元素从左往右都在增大,每列从上往下都在增大,右上角的元素比较特殊,拿要查找的数k和数组右上角的数进行对比,k小,则证明此列中没有k,则到前一列去找,k大,则证明此行中没有k,则到下一行去找。 要想一次性返回下标2个数,有2种方法: 传参时传行列数a,b的地址,通过传址调用改变a,b的值(改成要查找元素k的下标),最后打印a,b即可 创建下标结构体类型,成员变量为下标,返回值类型设置成此结构体类型,创建结构体对象,通过 . 操作符把成员变量赋值成要查找元素k的下标,最后返回即可#include
练习:打印菱形
#include
总结:
练习:打印杨辉三角
#include
练习:根据条件求比赛名次
#include
总结:
穷举排列组合的所有可能的方法:循环嵌套
多条判断语句的结果可相加来判断有其中有几条判断语句为真
练习:根据供词和条件找真凶
方法1:穷举4个嫌疑人的可能性
#include
方法2:穷举凶手的可能性
int main()
{
//方法2:只穷举凶手的可能性
char killer = 'a';
for (killer = 'a'; killer <= 'd'; killer++)
{
if ((killer != 'a') + (killer == 'c') + (killer == 'd') + (killer != 'd') == 3)
{
printf("%c\n", killer);
}
}
return 0;
}
练习:查找杨氏矩阵内某元素
方法1:返回型参数
//查找杨氏矩阵内某元素k,若找到则返回1及其下标,找不到返回0和(-1,-1)
#include
方法2:返回值设置为结构体类型
#include