一维数组
数组,即为一组相同类型的元素的集合;
1.1 一维数组的创建
数组的创建
① type_t:数组的元素类型;
② arr_name:数组名;
③ const_n:常量表达式,用于指定数组大小;

注意事项
① 数组创建,[ ] 中要给定常量,不能使用变量;
② 数组 [ ] 中的内容如果不指定大小(不填),则需要初始化;
一维数组创建方法演示

const_n中要给定一个常量,不能使用变量
int main()
{
int count = 10;
int arr[count]; // error
return 0;
}
#define N 10
int main()
{
int arr2[N]; // yes
return 0;
}
1.2 一维数组的初始化
初始化:在创建数组的同时给数组的内容置一些合理的初始值;

int main()
{
int arr1[10]; // 创建一个大小为10的int类型数组
char arr2[20]; // 创建一个大小为20的char类型数组
float arr3[1]; // 创建一个大小为1的float类型数组
double arr4[] = { 0 }; // 创建一个不指定大小的double类型数组(需要初始化)
return 0;
}
1.3 字符数组初始化
int main()
{
char ch1[5] = {'b', 'i', 't'};
char ch2[] = {'b', 'i', 't'};
char ch3[5] = "bit"; // 'b', 'i', 't', '\0', '0'
char ch4[] = "bit"; // 'b', 'i', ''t, '\0'
return 0;
}
字符数组初始化的两种写法
双引号写法自带斜杠0,花括号写法不自带斜杠0(需要手动添加)
int main()
{
char ch5[] = "bit"; // b, i, t, \0
char ch6[] = {'b', 'i', 't'}; // b i t
printf("%s\n", ch5);
printf("%s\n", ch6);
return 0;
}
没有 \0 时,strlen读取时并不会知道什么时候结束(继续往后面读,直到遇到斜杠0),
strlen:遇到斜杠0就停止
int main()
{
char ch5[] = "bit"; // b, i, t, \0 【自带斜杠0】
char ch6[] = {'b', 'i', 't'}; // b i t 【不自带斜杠0】
printf("%d\n", strlen(ch5));//3
printf("%d\n", strlen(ch6));//随机值
return 0;
}
当然,你可以给他手动加上一个斜杠0,这样就不会是随机值了;
int main()
{
char ch5[] = "bit"; // b, i, t, \0
char ch6[] = {'b', 'i', 't', '\0'}; // b, i, t, + '\0'
printf("%d\n", strlen(ch5));//3
printf("%d\n", strlen(ch6));//3
return 0;
}
1.4 一维数组的使用
下标引用操作符: [ ] ,即数组访问操作符;

数组的大小计算方法:整个数组的大小除以一个字母的大小

可以利用 for 循环,逐一打印数组
#include<stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
总结:
① 数组是使用下标来访问的,下标从0开始;
② 可以通过计算得到数组的大小;
1.5 一维数组在内存中的存储
按地址的格式打印:%p (十六进制的打印)

#include<stdio.h>
int main()
{
int arr[10] = { 0 };
int sz = sizeof(arr) / sizeof(arr[0]);
for (int i = 0; i < sz; i++)
{
printf("&arr[%d] = %p\n", i, &arr[i]);
}
return 0;
}

仔细检视输出结果可知:随着数组下标的增长,元素的地址也在有规律的递增;
结论:数组在内存中时连续存放的;

2. 二维数组
2.1 二维数组的创建

① const_n1:行
② const_n2: 列
#include<stdio.h>
int main()
{
int arr1[3][4] = { 1 };//创建一个3行4列的int型二维数组;并给第一个元素赋值1,
/* //只要赋值一个,后面的都是0,不赋值的话就是随机值
0 0 0 0
0 0 0 0
0 0 0 0
*/
printf("%d\n", arr1[0][0]);//1
printf("%d\n", arr1[0][1]);//0
char arr2[3][5]; // 创建一个3行5列的char型二维数组;
double arr3[2][4]; // 创建一个2行4列的double型二维数组;
return 0;
}
2.2 二维数组的初始化
初始化:在创建数组的同时给数组的内容置一些合理的初始值;
注意事项:
① 二维数组初始化时,行可以省略,但是列不可以省略;
② 二维数组在内存中也是连续存放的;
初始化演示
#include<stdio.h>
int main()
{
int arr[3][4] = { 1,2,3,4,5 };
/*
1 2 3 4
5 0 0 0
0 0 0 0
*/
int arr[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 }; // 完全初始化
int arr2[3][4] = { 1,2,3,4,5,6,7 }; // 不完全初始化 - 后面补0;
int arr3[3][4] = { {1,2}, {3,4}, {4,5} }; // 指定;
/*
1 2 0 0
3 4 0 0
4 5 0 0
*/
return 0;
}
关于 " 行可以省略,列不可以省略 "
int main()
{
int arr1[][] = {{2,3}, {4,5}}; // error
int arr2[3][] = {{2,3}, {4,5}}; // error
int arr2[][4] = {{2,3}, {4,5}}; // √
return 0;
}
2.3 二维数组的使用
同样是通过下标的方式,利用两个 for 循环打印
#include<stdio.h>
int main()
{
int arr[3][4] = { 0 };
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
printf("arr[%d][%d] = %d\n", i, j, arr[i][j]);
}
}
return 0;
}
二维数组在内存中的存储
#include<stdio.h>
int main()
{
int arr[3][4] = { 0 };
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
printf("&arr[%d][%d] = %p\n", i, j, &arr[i][j]);
}
}
return 0;
}
运行结果如下:

仔细检视运行结果,我们可以分析到其实二维数组在内存中也是连续存存放的;
(并且可以理解是横着存放的,而不是像图一样竖着)
2.4 数组作为函数参数
数组名是首元素的地址(有两个例外)
例外1:
sizeof(数组名) 计算的是整个数组的大小
#include<stdio.h>
int main()
{
int arr[10] = { 0 };
printf("%d\n", sizeof(arr));//40
return 0;
}
例外2:
& 数组名 表示整个数组,取出的是整个数组的地址
(这时+1跳过的就是整个数组)
下面的练习至少冒泡排序看看(三子棋能看的话就看看,下一篇会实现一个扫雷的游戏)
课后练习:
冒泡排序(重点)
写一个bubble_sort函数,使其可以升序排序输入的10个整数。
冒泡排序核心思想:两两相邻元素进行比较,满足条件则交换;
① 先确认趟数;
② 写下一趟冒泡排序的过程;
③ 最后进行交换;
动图:

注意事项:
① int arr [ ] 本质上是指针,int * arr ;
② 数组传参时,实际上传递的是数组的首元素地址;
③ sz 变量不能在 bubble_sort内部计算,需要在外部计算好再传递进去;
#include<stdio.h>
void bubble_sort(int arr[], int sz)
{
for (int i = 0;i < sz - 1;i++)// size-1表示:最后一趟区间中只剩余1个元素,该趟冒泡可以省略
{
int flag = 1;
for (int j = 0;j < sz - i - 1;j++)
{
if (arr[j] > arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
flag = 0;
// 如果本次冒泡中,元素没有交换,则本次开始冒泡时,数据已经有序了
//后面的冒泡可以不用进行了(此时flag为1,跳出循环)
}
}
if (flag)
{
break;
}
}
}
int main()
{
int arr[10] = { 0 };
int sz = sizeof(arr) / sizeof(arr[0]);
for (int i = 0;i < sz;i++)
{
scanf("%d", &arr[i]);
}
bubble_sort(arr, sz);
printf("排序后:\n");
for (int i = 0;i < sz;i++)
{
printf("%d ", arr[i]);
}
return 0;
}
2. 数组操作
【题目内容】
创建一个整形数组,完成对数组的操作
实现函数init() 初始化数组为全0
实现print() 打印数组的每个元素
实现reverse() 函数完成数组元素的逆置。
要求:自己设计以上函数的参数,返回值。
#include<stdio.h>
void init(int arr[], int sz)
{
for (int i = 0;i < sz;i++)
{
arr[i] = 0;
}
}
void print(int arr[], int sz)
{
for (int i = 0;i < sz;i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
void reverse(int arr[], int sz)
{
int left = 0, right = sz - 1;
while(left < right)
{
int tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
printf("逆序和初始化前:");
print(arr, sz);
printf("逆序后:");
reverse(arr, sz);
print(arr, sz);
init(arr, sz);
printf("初始化后:");
print(arr, sz);
return 0;
}
3. 交换数组
【题目内容】
将数组A中的内容和数组B中的内容进行交换。(数组一样大)
#include<stdio.h>
void print(int arr[], int sz)
{
for (int i = 0;i < sz;i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
int main()
{
int arr1[] = { 0,1,2,3,4 };
int arr2[] = { 5,6,7,8,9 };
int sz = sizeof(arr1) / sizeof(arr1[0]);
printf("交换前:\n");
print(arr1, sz);
print(arr2, sz);
for(int i=0;i<sz;i++)
{
int tmp = arr1[i];
arr1[i] = arr2[i];
arr2[i] = tmp;
}
printf("交换后:\n");
print(arr1, sz);
print(arr2, sz);
return 0;
}
4. 三子棋
先把菜单和大纲列出来,后面在实现三子棋游戏的函数。
#include<stdio.h>
void menu()
{
printf("*****************************************\n");
printf("************** 1. paly **************\n");
printf("************** 0. exit **************\n");
printf("*****************************************\n");
}
int main()
{
int input = 0;
do
{
menu();
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
printf("三子棋游戏\n");
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误;重新输入:\n");
break;
}
} while (input);
}
然后就看着game里面的函数一个个实现了,想说的都放在代码注释了
test.c(游戏的测试)
#include"game.h"
void menu()
{
printf("*****************************************\n");
printf("************** 1. paly **************\n");
printf("************** 0. exit **************\n");
printf("*****************************************\n");
}
void game()
{
//数据存储,二维数组
char board[ROW][COL] = { 0 };
//棋盘:chessboard 行:row,列:column,defind定义的符号通常大写用来区分
//符号和函数的定义放在game.h
//初始化棋盘成空格
init_board(board, ROW, COL);
//打印棋盘
print_board(board, ROW, COL);
//ret==什么,游戏就结束了
//玩家赢 - '*'
//电脑赢 - '#'
//平局 - 'g'
//继续 - 'r'
//落子和判断输赢
char ret = 0;
while(1)
{
//玩家下棋:
player_move(board, ROW, COL);
print_board(board, ROW, COL);
ret=is_win(board, ROW, COL);
if (ret != 'r')
{
break;
}
//电脑下棋:
computer_move(board, ROW, COL);
print_board(board, ROW, COL);
ret = is_win(board, ROW, COL);
if (ret != 'r')
{
break;
}
}
if (ret == '*')
{
printf("恭喜你赢了!\n");
}
else if (ret == '#')
{
printf("恭喜电脑赢了emm\n");
}
else
{
printf("平局 gg!\n");
}
}
int main()
{
//随机数种子
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
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(放置函数的声明)
#include<stdio.h>//头文件的包含
#include<time.h>//time()
#include<stdlib.h>//rand()
#define ROW 3 //可以把两个3换成任意数字
#define COL 3 //能下,但是判断输赢写死了,只能判断3*3的
//初始化成空格棋盘函数
void init_board(char board[ROW][COL],int row,int col);
//打印棋盘函数
void print_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);
//判断棋盘是否满函数(平局)(在判断输赢函数内使用)
int is_full(char board[ROW][COL], int row, int col);
//判断输赢函数
char is_win(char board[ROW][COL], int row, int col);
game.c(放置函数的实现)
#include"game.h"
//初始化成空格棋盘函数
void init_board(char board[ROW][COL], int row, int col)
{
for (int i = 0;i < ROW;i++)
{
for (int j = 0;j < COL;j++)
{
board[i][j] = ' ';
}
}
}
//打印棋盘函数
void print_board(char board[ROW][COL], int row, int col)
{
for (int i = 0;i < row;i++)
{
//打印数据和竖线
for (int j = 0;j < col;j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
printf("|");
}
printf("\n");
//打印横线
if (i < row - 1)//比行少一段
{
for (int 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 = 1, y = 1;
printf("请输入你下的坐标(行 列,空格分开):\n");
while(1)
{
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
printf("玩家下:\n");
break;
}
else
{
printf("坐标已被占用,请重新输入:\n");
}
}
else
{
printf("坐标非法,重新输入:\n");
}
}
}
//电脑随机下棋函数
void computer_move(char board[ROW][COL], int row, int col)
{
printf("电脑下:\n");
int x = 1, y = 1;
while(1)
{
x = rand() % row;
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
//判断棋盘是否满函数(平局)(在判断输赢函数内使用)
int is_full(char board[ROW][COL], int row, int col)
{
for (int i = 0;i < row;i++)
{
for (int j = 0;j < col;j++)
{
if (board[i][j] == ' ')
{
return 0;
}
}
}
return 1;
}
//判断输赢/平局函数
char is_win(char board[ROW][COL], int row, int col)
{
//判断行
for (int 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 (int 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 (is_full(board, row, col) == 1)//判断棋盘是否满函数
{
return 'g';
}
//继续
return 'r';
}
本篇完。
下一篇:扫雷游戏的实现
(穿越回来贴个链接:)