【C语言基本知识——数组和三子棋小游戏】

本文详细介绍了数组的概念,包括一维数组和二维数组的创建、初始化、内存存储方式以及作为函数参数的使用。还通过示例展示了如何用数组实现三子棋游戏,强调了数组在内存中是连续存储的特性,并探讨了数组作为函数参数时的实际传递情况。最后,给出了一个完整的三子棋游戏的实现代码,包括玩家和电脑的移动逻辑以及胜负判断。
摘要由CSDN通过智能技术生成

数组

  1. 一维数组的创建和初始化

  2. 一维数组的使用

  3. 一维数组在内存中的存储

  4. 二维数组的创建和初始化

  5. 二维数组的使用

  6. 二维数组在内存中的存储

  7. 数组作为函数的参数

  8. 数组的使用例子:三子棋

  9. 数组的应用例子:扫雷游戏

一维数组的创建和初始化

数组的创建:

数组是一组相同类型元素的集合 ,数组的创建的方式:


//创建一个数组—存放整型—10个
//[10]框框里面是数字也好,是宏定义的数字也好,一定要是一个常量,不能是程序里面初始化的一个新的变量。

int main()
{
  int arr[10];
  char arr2[5];
  return 0;
}

数组的初始化

数组的初始化是指,在创建数组的同时给数组的内容一些合理初始值(初始化)


int arr1[10] = {1,2,3};
int arr2[] = {1,2,3,4};
int arr3[5] = {1,2,3,4,5};
char arr4[3] = {'a',98,,'c'};
char arr5[] = {'a','b','c'};
char arr6[] = "abcdef"

char arr5[] = “abcdef”
用 sizeof 和 strlen 求该数组时,,结果为7,6. 因为 sizeof 是求数组所占内存空间的大小,而 strlen 是求字符串的长度,并且在计算字符串的长度的时候是不考虑"\0",因为"\0"不是字符串的内容!

注意:

  1. strlen 和 sizeof 没有任何什么关联
  2. strlen 是求字符串的长度的—只能针对字符串的长度—使用的时候必须引用库函数(使用头文件)
  3. sizeof 计算变量,数组,类型的大小(计算所占的内存空间大小,也就是还要考虑类型单个所占的字节大小)—单位是字节—是一种操作符。
//小练习:答案是 4 3  3 随机数
#include <stdio.h>
#include <string.h>
int main()
{
  char arr1[] = "abc";
  char arr2[] = {'a','b','c'};
  printf("%d\n",sizeof(arr1));
  printf("%d\n",sizeof(arr2));
  printf("%d\n",strlen(arr1));
  printf("%d\n",strlen(arr2));
  return 0;
}

为什么是随机数?因为arr2这个数组后面没有"\0",不知道在系统里面什么时候会遇到结束符,所以最后一个数字是随机的

数组的使用

对于数组的使用,下标引用操作符[],他其实就是数组访问的操作符


#include <stdio.h>
int main()
{
  int arr[10] = {0};
  //定义一个不完全初始化的数组
  int sz = sizeof(arr)/sizeof(arr[0]); //对数组的内存赋值,数组是使用下标来访问的
  //求数组的元素个数
  int i = 0;
  //做下标
  for(i = 0;i<10;i++)
  {
    arr[i] = i;
  }
  //输出数组的内容
  for(i = 0;i<10;i++)
  {
    printf("%d\n",arr[i]);
  }
  return 0;
}
//数组是使用下标来进行访问的,下标从0开始,数组的大小可以通过计算得到,sizeof(arr)/sizeof(arr[0]);

一维数组在内存中的存储

#include <stdio.h>
int main()
{
  int arr[] = {1,2,3,4,5,6,7,8,9,10};
  int sz = sizeof(arr)/sizeof(arr[0]);
  int i = 0;
  for(i = 0;i < sz ;i++)
  {
    printf("&arr[%d] = %p",i,&arr[i]);
  }
  return 0;
}

数组在内存中是连续开辟的一个空间,连续存放,随着数组下标的增长,元素的地址,也在有规律的递增,由此可以得出结论:数组在内存中是连续存放的

二维数组的创建和初始化

二维数组的创建:(几行几列)

int arr[3][4];
char arr[3][5];
double [2][4];

二维数组的初始化:

int arr[3][4] = {1,2,3,4};
int arr[3][4] = {{1,2},{4,5}};
int arr[][4] = {{2,4},{4,5}};

二维数组的使用
//二维数组的输入以及输出
#include <stdio.h>
int main()
{
  int i = 0;
  int j = 0;
  int arr[10][10];
  for(i = 0;i < 10;i++)
  {
    for(j = 0;j < 10;j++)
    {
      scanf("%d",&arr[i][j]);
    }
  }
  for(i = 0;i < 10;i++)
  {
    for(j = 0;j < 10;j++)
    {
      printf("%d\t",arr[i][j]);
    }
    printf("\n");
  }
  return 0;
}

二维数组的在内存中的存储
#include <stdio.h>
int main()
{
  int arr[3][4]= {{1,2,3,4},{5,6,7}};
  int i = 0;
  for(i = 0;i < 3 ;i++)
  {
    for(j = 0;j <4;j++)
    {
      printf("&arr[%d][%d] = %p",i,j,&arr[i][j]);
    }
  }
  return 0;
}


二维数组在内存空间当中,不是像我们所想的一样二维数组是一个矩阵,二维数组也是连续的,就是一个数组接着一个数组。

数组作为函数的参数

往往我们在写代码的时候,会将数组作为参数传给函数,比如:我要实现一个冒泡排序(这里要讲算法思想)函数将一个整形数组排序,那我们将会这样使用该函数:


#include <stdio.h>

void bubble_sort(int arr[],int sz)
{
  int i = 0;
  for(i = 0;i < sz-1;i++)
  {
    //每一趟冒泡排序
    int j = 0;
    for(j = 0;j < sz-1-i;j++)
    {
      if(arr[j]>arr[j+1])
      {
        int temp = arr[j];
        arr[j] = arr[j+1];
        arr[j+1] = temp;
      }
    }
  }
}


int main()
{
  int arr[] = {9,8,7,6,5,4,3,2,1,0}
  int sz = sizeof(arr)/sizeof(arr[0]);
  int i = 0;
  //arr是数组,我们进行数组传参的时候实际传过去的是数组arr首元素的地址 &arr[0];
  bubble_sort(arr,sz);
  for(i = 0;i < sz;i++)
  {
    printf("%d\t",arr[i]);
  }
  return 0;
}


优化代码


#include <stdio.h>

void bubble_sort(int arr[],int sz)
{
  int i = 0;
  int flag = 1;
  for(i = 0;i < sz-1;i++)
  {
    //每一趟冒泡排序
    int j = 0;
    for(j = 0;j < sz-1-i;j++)
    {
      if(arr[j]>arr[j+1])
      {
        int temp = arr[j];
        arr[j] = arr[j+1];
        arr[j+1] = temp;
        flag = 0;
      }
    }
  if(flag == 1)
    {
      break;
    }
  }
}


int main()
{
  int arr[] = {9,8,7,6,5,4,3,2,1,0}
  int sz = sizeof(arr)/sizeof(arr[0]);
  int i = 0;
  //arr是数组,我们进行数组传参的时候实际传过去的是数组arr首元素的地址 &arr[0];
  bubble_sort(arr,sz);
  for(i = 0;i < sz;i++)
  {
    printf("%d\t",arr[i]);
  }
  return 0;
}

break 语句只能用于for和switch,在if语句中不能使用,因为if语句不是循环语句,但是在这里因为if语句在for循环里面,是可以使用的,不能使用是 单单纯纯的if语句的时候才不能使用!

数组名是数组首元素的地址(有两个例外)

  1. sizeof(数组名),数组名表示整个数组,sizeof数组名,计算的是整个数组的大小,单位是字节
  2. &数组名,数组名代表的就是整个数组,&数组名,取出的就是整个数组的地址
#include <stdio.h>
int main()
{
  int arr[10] = {1,2,3,4,5}
  printf("%p\n",arr);
  printf("%p\n",&arr[0]);
  printf("%d\n",*arr);
  return 0;
}

这个时候三个值是一样的,但是前两个指的就是数组首元素的地址,但是第三个就是整个数组的地址,只是从哪个地址开始!

#include <stdio.h>
int main()
{
  int arr[10] = {1,2,3,4,5}
  printf("%p\n",arr);
  printf("%p\n",&arr[0]);
  printf("%p\n",&arr);
  return 0;
}

这个时候就可以看出来地址的变化!

#include <stdio.h>
int main()
{
  int arr[10] = {1,2,3,4,5}
  printf("%p\n",arr);
  printf("%p\n",arr+1);
  printf("%p\n",&arr[0]);
  printf("%p\n",&arr[0]+1);
  printf("%p\n",&arr);
  printf("%p\n",&arr+1);
  return 0;
}
数组实现三子棋游戏

在VS里面建立一个空的项目,然后建立两个.c文件(test.c用来测试这个游戏,game.c用来实现这个项目)还有一个.h头文件

test.c

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>
#include "game.h"
void menu()
{
  printf("**************************");
  printf("**** 1. play 0. exit *****");
  printf("**************************");
}
//游戏的整个算法实现
void game()
{
  char ret = '';
  //利用数组来存放走出棋盘的信息
  char board[ROW][COL] = {0};
  //初始化棋盘
  InitBoard(board,row,col);
  //打印棋盘
  Displayboard(board,row,col);
  //下棋
  while(1)
  {
    //玩家下棋
    PlayerMove(board,ROW,COL);
    Displayboard(board,ROW,COL);
    ret = Iswin(board,ROW,COL);
    if(ret != 'C')
    {
      break;
    }
    //电脑下棋
    ComputerMove(board,ROW,COL);
    Displayboard(board,ROW,COL);
    ret = Iswin(board,ROW,COL);
    if(ret != 'C')
    {
      break;
    }
  }
  if(ret == '*')
  {
    printf("玩家赢\n");
  }
  else if(ret == '#')
  {

    printf("电脑赢\n");
  }
  else
  {
    printf("平局\n");
  }

}
void test()
{
  int input = 0;
  srand((unsigned int)time(NULL));
  do
  {
    menu();
    printf("please select:\n");
    scanf("%d",&input);
    switch(input)
    {
      case 1:game();break;
      case 0:printf("cancle game\n");break;
      default:printf("select error!\n");break;
    }
  }
}


int main()
{
  test();
  return 0;
}

game.c

#define _CRT_SECURE_NO_WARNINGS 1

void InitBoard(char board[][],int row,int col)
{
  int i = 0;
  int j = 0;
  for(i = 0;i < row;i++)
  {
    for(j = 0;j < col;j++)
    {
      board[i][j] = ' ';
    }
  }
}


void Displayboard(char board[][],int row,int col)
{
  int i = 0;
  for(i=0;i < row;i++)
  {
    int j = 0;
    for(j = 0;j < col;j++)
    {
    //1.打印一行的数据
      printf(" %c ",board[i][j]);
      if(j < col-1)
        printf("|");
    }
    printf("\n");
    //2.打印分割线
      if(i < row-1)
      {
        for(j = 0;j < col;j++)
        {
          printf("---");
          if(j < col-1)
            printf("|");
        }
        printf("\n");
      }
  }
}

void PlayerMove(char board[ROW][COL],int row,int col)
{
  int x = 0;
  int y = 0;
  printf("玩家走>\n");
  while(1)
  {
    printf("请输入要下的坐标>\n");
    scanf("%d,%d",&x,&y);
    //判断x,y坐标的合法性,这里要注意,玩家不是程序员,他们并不知道数组的下标是从0开始,所以这里不要用程序员的思维来考虑!
    if(x >=1 && x <= row && y >=1 && y<= col)
    {
      if(board[x-1][y-1] = ' ' )
      {
        board[x-1][y-1] = '*';
        break;
      }
      else
      {
        printf("该坐标已经被输入!,请重新输入\n");
      }
    }
    else
    {
      printf("坐标非法,请重新输入!\n");
    }
  }
}

void ComputerMove(char board[ROW][COL],int row,int col)
{
  int x = 0;
  int y = 0;
  printf("电脑走:>\n");
  while(1)
  {
    x = rand()%row; //生成随机的横坐标
    y = rand()%col; //生成随机的列坐标
    if(board[x][y] = ' ')
    {
      board[x][y] = '#';
      break;
    }  
  }
}

//返回1表示棋盘满了,返回0表示棋盘没满
int Isfull(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 IsWin(char board[ROW][COL],int row,int col)
{
  int i = 0;
  //横三行
  for(i = 0;i < row;i++)
  {
    if(board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')
    {
      return board[i][1];
    }
  }
  //竖三列
  for(i = 0;i < col;i++)
  {
    if(board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
    {
      return board[1][i];
    }
  }
  //两个对角线
  if(board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
    return board[1][1];
  if(board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
    return board[1][1];
  //判断是否平局
  if(1 == Isfull(board,ROW,COL))
  {
    return 'Q';
  }
  return 'C';
  
}

game.h


#define ROW 3
#define COL 3
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

//初始化棋盘的函数声明
void InitBoard(char board[ROW][COL],int row,int col);
//打印棋盘的函数的声明
void Displayboard(char board[ROW][COL],int row,int col);
//玩家下棋函数的声明
void PlayerMove(char board[ROW][COL],int row,int col);
//电脑下棋函数的声明
void ComputerMove(char board[ROW][COL],int row,int col);
//判断玩家和电脑输赢的函数的声明
char IsWin(har board[ROW][COL],int row,int col);
//这个判断函数由四种状态,也就是:
//玩家赢——'*'
//电脑赢——'#'
//平局——'Q'
//继续——'C'

//判断棋盘是否下满的函数的声明
int Isfull(char board[ROW][COL],int row,int col);

总结:刚开始写的这个项目不是非常理想,比较简单,如果更改了ROW和COL的棋盘显示出来的样子不是我们所希望的样子,但是当我们将这个棋盘看作,比如有三行三列的时候,将每一行数据加上每一个分割线看作一个组,这样就有三组,然后每一组再细化分为两个方面,上面是由一个空格一个字符一个空格,再来一个|,这样的组合就也有三个,下面是由三个这个—和一个|这个组合,也是三个,并且这个时候他们就可以通过行和列的范围来进行很好的控制。还有就是需要考虑用户不是程序员这个问题,所以在进行判断坐标是否合法的时候就需要站在用户的角度来分析!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值