只要你愿意 开始总比放弃好。 Roman.
愿我们都有自己的目标并正在为其不懈努力。
---------------------------------------------------------------------------------------
数组:是一组相同类型的元素的集合。
---------------------------------------------------------------------------------------
一、一维数组
一)一维数组的创建和初始化
1、一维数组的创建
1)数组的创建方式:
type_t arr_name [const_n]
//type_t 是指数组的元素类型
//const_t 是一个常量表达式,用来指定数组的大小
2)type_t arr_name [const_n] 中, [const_n] 注意是常量表达式!!
即使在定义变量时加了 const 也不可以使用 ,因为加了 const 是常变量,常变量依旧属于变量。
3)C99 标准中引入了变长数组的概念, [const_n] 允许数组的大小用变量来指定;
但是如果编译器不支持 C99 标准中的变长数组,那就不能使用变量
(注:VS2019是不支持C99标准的)
4)注意:
C语言中 const 修饰的变量叫变常量,实质是变量; C++下 const 修饰的变量就是常量
2、一维数组的初始化
1)若整型数组不完全初始化,则未完全初始化部分默认初始化为 0
2)若初始化数目超出数组指定的大小,会报错
3)C99标准下的变长数组不能初始化
4)数组初始化后,数组大小可以省略不写,其大小根据初始化内容来确定大小
5)局部变量 or 数组若未初始化,其内存储的是随机值(根据编译器不同被赋予不同的随机值),有的编译器会存在不可打印的情况
全局变量 or 静态变量(static修饰变量)未初始化,则其内默认存储是0
6)C语言从上到下有三个区:
栈区:局部变量、形式参数:未初始化则默认初始化为随机值
堆区
静态区:静态变量、全局变量:未初始化则默认初始化为0
7)字符数组初始化:
① 若初始化是 双引号“ ” 形式,则在字符后面会存在 ‘\0’ ,所以计算该形式数组大小时注意 加1
② 若初始化是 大括号{ } 形式,计算数组大小就是大括号内字符的个数
③ 为完全初始化则默认初始化为 '\0' (注意:整型和字符默认初始化是不同的)
二)一维数组的使用
下标引用操作符[ ] ,即:数组访问的操作符
1、数组下标从 0 开始
2、 [ ] 的两个操作数是 arr_name 和 const_n
3、suzeof( )计算大小时,单位是 字节
4、计算数组元素个数的写法:
若初始化是 { } 形式: sizeof (arr) / sizeof (arr[0]);
若初始化是 " " 形式:strlen (arr);
三)一维数组在内存中的存储
1、一维数组在1内存中是连续存放的
2、随着数组下标的增长,地址是由低到高变化的
3、
int * p = & arr[0];
p + i; //表示首元素跳过 i 个元素后的地址
* (p+i); //表示首元素跳过i个元素后的元素
4、补充:
- %p :打印地址 (十六进制)
- %d : 打印整数 (十进制)
-------------------------------------------------------------------------------------------------------
二、二维数组
一)二维数组的创建和初始化
1、二维数组的创建
创建方式:type_t arr_name[行][列]
2、二维数组的初始化
1)初始化只能是 大括号{ } 的形式
2)可以把每一行看成一个一维数组
3)不完全初始化且在已初始化内容中没有大括号{ } 进行限制,则按顺序进行初始化,未初始化部分默认初始化为 0
4)可以省略行数,根据初始化内容确定行,但是不能省略列数
二)二维数组的使用
1、行列下标均从 0 开始
2、计算行数:sizeof (arr) / sizeof (arr[0]);
计算列数:sizeof (arr[0]) / sizeof (arr[0][0]);
三)二维数组在内存中的存储
1、二维数组在内存中也是连续存在的:各行之间也是连续的,可以看作该二维数组就是在同一行上进行存储,所以必须要知道一行有几列才可以最终确定行数
2、拓展:三维数组 arr[n1][n2][n3] 可以理解为: n1个二维数组 arr[n2][n3]
-------------------------------------------------------------------------------------------------------
三、数组越界
1、
- 数组的下标是从 0 到 (n-1)
- 若数组下标小于0 or 大于(n-1) ,就是数组越界访问了,超出了数组合法空间的访问
- 注意:此处所说的是访问越界,定义不存在越界情况
2、C语言本身不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错并不意味着程序正确
3、二维数组的行和列也可能存在越界
---------------------------------------------------------------------------------------------------------
四、数组作为函数参数
使用冒泡排序排序数组内容:bubble_sort(数组名)
1、冒泡排序:数组中两个相邻元素进行比较,并按照最终所要求的顺序进行排列
2、思路:
搞定一个数字的排序需要一趟冒泡排序:若该数组有n个数字,则需要进行(n-1)趟冒泡排序
每趟冒泡排序需要比较未排列好的相邻对数:若有n个数字且为第i(i从0开始),则该趟需要对 (n-1-i)对数字进行排列
3、注意计算元素个数不能在函数内进行计算
- 数组名一般是指首元素的地址,但是有两个例外:
1) sizeof( 数组名),数组名不是首元素地址
2)& 数组名,数组名不表示首元素地址,而是表示整个数组,取出的是整个数组的地址
- 区别:
1) & 数组名 打印结果是首元素地址, (&数组名+1) 表示跳过一整个数组大小
2)&数组名[0] or 数组名 打印结果是首元素地址, (数组名+1)or (&数组名[0]+1)跳过的是一个元素大小
- 在函数传参后的函数中计算其大小,相当于计算 sizeof(元素类型*),即:计算的是指针大小,指针大小为4(32位)or 8(64位)
4、优化:设置一个标志flag,假设一趟排序是发现存在无序则置0,若该趟排序均为有序,则保持1,并在该趟结束后直接break;
5、代码:
//冒泡排序:假设该题是从大到小排列
#include<stdio.h>
#define max 100
//冒泡排序
void bubble_sort(int* num, int n)
{
int i = 0;
//趟数:n-1
for (i = 0; i < (n - 1); i++)
{
int flag = 1;//标记
//每一趟的对数:(n-1-i)
int j = 0;
for (j = 0; j < (n - 1 - i); j++)
{
//从大到小
if (num[j] < num[j + 1])
{
int tmp = num[j];
num[j] = num[j + 1];
num[j + 1] = tmp;
flag = 0;
}
}
if (1 == flag)
{
break;
}
}
}
int main()
{
int num[max] = { 0 };
int n = 0;
int i = 0;
printf("请输入你想输入的数字个数n:\n");
scanf("%d", &n);
printf("请任意输入%d个整数:\n", n);
for (i = 0; i < n; i++)
{
scanf("%d", &num[i]);
}
//冒泡排序
bubble_sort(num, n);
printf("冒泡排序结果为:\n");
for (i = 0; i < n; i++)
{
printf("%d ", num[i]);
}
return 0;
}
---------------------------------------------------------------------------------------------------------
五、实例(小游戏)
1、三子棋
2、扫雷
(具体代码见下一篇博客)
-----------------------一个人所有的愤怒都来源于对自己无能的痛苦。-----------------------------