为了更好地学习和理解数组,我们先来认识一下内存中的"地址"。
一、地址
1.计算机中的内存是以字节为单位的存储空间。内存的每一个字节都有一个唯一的编号,这个编号就称为地址。凡存放在内存中的程序和数据都有一个地址,也就是说,一个函数也有自己的内存地址。
2.当定义一个变量时,系统就分配一个带有唯一地址的存储单元来存储这个变量。
char a = 'A'; // A的ASCII值为65
int b = 66;
假设是在16bit环境下,系统为a、b分别分配1个字节、2个字节的存储单元。变量存储单元的第一个字节的地址就是该变量的地址。
可以看出,变量a的地址是ffc3;变量b的地址是ffc1。内存中存储的都是2进制数据。
3.在调试过程中,我们采取打印的方式查看变量的地址:
int c = 10;
// 以16进制形式输出地址
printf("16进制:%x\n", &c);
// 以10进制形式输出地址
printf("10进制:%d", &c);
二、一维数组
1.基本定义
数组定义:在程序设计中,为了处理方便,把具有相同类型的若干变量按有序的形式组织起来。这些按序排列的同类数据元素的集合称为数组
元素定义:一个数组里集合了多个数据对象,这些数据对象被称为数组中的元素。数组中的每一个元素都属于同一种数据类型
元素类型:数组中的元素可以是简单数据类型,也可以是构造数据类型。(上一章说的数据类型)
简单数据类型:int 、float、short、double、long。。。
构造数据类型:数组、结构体。。。
2、数组的声明
声明声明的语法:
类型说明符 数组名[常量表达式];
比如: int exampleArr[10];
类型说明符可以是简单的数据类型和构造数据类型,数组名是标识符
常量表达式表示数组集合里面元素的个数。
【注】
1、类型说明符表示数组元素的取值类型;
2、数组名的定义,必须遵守标识符的约定,不能和同一个{}里面其他的
变量名相同;
3、常量表达式—确定数组元素的个数,不能够包含变量,一般应该
是整数。
3.一维数组的存储
定义数组时,系统将按照数组类型和个数分配一段连续的存储空间来存储数组元素,如int a[3]占据了连续的6字节存储空间(在16位环境下,一个int类型占用2个字节)。要注意的是,数组名代表着整个数组的地址,也就是数组的起始地址。
注意:其实a不算是变量,是个常量,它代表着数组的地址。上图把a放到变量一栏是为了方便大家理解数组结构。
数组a的地址是ffc1,a[0]的地址是ffc1,a[1]的地址是ffc3,a[2]的地址是ffc5。因此a == &a[0],即第一个元素的地址就是整个数组的地址
4、一维数组的初始化
给数组赋值的方法除了用赋值语句对数组元素逐个赋值外, 还可采用
初始化赋值的方法。数组初始化赋值是指在数组定义时给数组元素赋予初值。数组初始化是
在编译阶段进行的。这样将减少运行时间,提高效率。初始化赋值的一般
形式为:类型说明符 数组名[常量表达式] = {值,值,值,值,…};
比如:int a[5] = {1,2,3,4,5};
值与值之间用, 隔开。
【注】
1.全部初始化;
数组有多长,{}里面就有多少个值。
比如:int a[5] = {1,2.,3,4,5};
2.部分初始化;
{}里面值得个数 < 数组的长度,没有初始化值的元素,默认为0.
比如:int a[5] = {1, 2};//a[0] = 1, a[1] = 2,其他三个为0
3.在全部初始化的情况下,可以省略数组的长度;
比如:int a[] = {1, 2, 3, 4, 5}; //5个元素
4.数组元素全部初始化为0;
比如:int a[5] = {}; //全部初始化为 0
5.数组元素的引用
数组元素是组成数组的基本单元。数组元素也是一种变量, 其标识方法为数组名后跟一个下标。下标表示了元素在数组中的顺序号。
数组元素的一般形式为:数组名[下标];
比如:int a[5];//数组元素为 a[0],a[1],a[2],a[3],a[4],
三、数组常用编程
1.数组元素的查找最大值(最小值)
使用max变量与数组里面的每一个元素进行比较,让max保存每次比较的较大值
#include <stdio.h>
int main(int argc, const char * argv[]) {
//数组元素的查找最大值和最大值的下标
int score[6] = {80, 30, 20, 0, 100, 89};
int max = score[0];
int index = 0;
for (int i = 1; i < 6; i ++)
{
if (max < score[i])
{
max = score[i];
index = i;
}
}
printf("max = %d\n", max);
printf("index = %d\n", index);
return 0;
}
2.数组逆序
定义一个中间变量,数组首尾元素进行交换。
#include <stdio.h>
int main(int argc, const char * argv[]) {
//数组逆序
int arr[] = {1,2,3,4,5,6,7,8};
int temp;
int len;
len = sizeof(arr)/sizeof(arr[0]);
for (int i = 0; i < len / 2; i ++)
{
temp = arr[i];
arr[i] = arr[len - 1 - i];
arr[len - 1 - i] = temp;
}
for (int i = 0; i < len; i ++)
printf("%d ", arr[i]);
printf("\n");
return 0;
}
3.数组元素的增加;
数组元素插入( 三步取,找位置,挪位置,插入元素。注意公式是i>index.)
#include <stdio.h>
int main(int argc, const char * argv[]) {
int a[5] = {1,2,3,4};
int i, len, index;
//1.找位置
index = 2;
//2.挪位置
len = 4;
for (int i = len; i > index; i --)
{
a[i] = a[i - 1];
}
//3.写入元素
a[index] = 0;
for (i = 0; i < 5; i ++)
printf("%d ", a[i]);
printf("\n");
return 0;
}
4.数组元素的删除
【数组删除元素的步骤】1.找位置 2.挪位置—左移 3.将数组的有效长度 - 1.
#include <stdio.h>
int main(int argc, const char * argv[]) {
int a[5] = {1,2,3,4,5};
int i, len, index;
//1.找位置
index = 2;
//2.挪位置
len = 5;
for (int i = index; i < len - 1; i ++)
{ //左移
a[i] = a[i + 1];
}
//3.将数组的有效长度 - 1.
for (i = 0; i < 5 - 1; i ++)
printf("%d ", a[i]);
printf("\n");
return 0;
}
5.选择排序
从所有元素中找出最小的一个,将其放在最前面,接着在余下的数中找出最小的一个放在第二位,依此类推,数列由前往后逐渐成型。
#include <stdio.h>
int main(int argc, const char * argv[]) {
int score[6] = {98, 90, 67, 78, 92, 89};
int min = score[0];
int index = 0, temp;
int len = 6;
for (int i = 0; i < len - 1; i ++) //0~4
{
min = score[i];
index = i;
for (int j = i + 1; j < len; j ++)
{
if (min > score[j])
{
min = score[j];
index = j;
}
}
if (index != i)
{
temp = score[i];
score[i] = score[index];
score[index] = temp;
}
}
for (int i = 0; i < 6; i ++)
printf("%d ", score[i]);
printf("\n");
return 0;
}
6.冒泡排序
对相邻两个数进行比较,将较小的调到前面,两两比较一轮之后,最大的一个数被放置在最后面;接着从头开始重复执行以上操作,次大的数被放置在倒数第二位,依次类推,数列由后往前逐渐成型。
#include <stdio.h>
int main(int argc, const char * argv[]) {
int score[6] = {6,1,2,3,4,5};
int temp;
int len = 6;
int isswap = 0;
for (int i = 0; i < len - 1; i ++)
{
isswap = 0;
for (int j = 0; j < len - 1 - i; j ++)
{
if (score[j] > score[j + 1])
{
temp = score[j];
score[j] = score[j + 1];
score[j + 1] = temp;
isswap = 1;
}
}
if (isswap == 0)
break;
}
for (int i = 0; i < 6; i ++)
printf("%d ", score[i]);
printf("\n");
return 0;
}
四、二维数组
1.二维数组的定义
定义形式:类型 数组名[行数][列数]
比如:int a[2][3]; // 共2行3列,6个元素
2.二维数组的存储
- C语言把二维数组当作是一维数组的集合,即二维数组是一个特殊的一维数组:它的元素是一维数组。例如int a[2][3]可以看作由一维数组a[0]和一维数组a[1]组成,这两个一维数组都包含了3个int类型的元素
- 二维数组的存放顺序是按行存放的,先存放第一行的元素,再存放第2行的元素。例如int a[2][3]的存放顺序是:a[0][0] → a[0][1] → a[0][2] → a[1][0] → a[1][1] → a[1][2]
- 再来看看在内存中的存储情况,例如int a[2][2]
*
(注意:a[0]、a[1]也是数组,是一维数组,而且a[0]、a[1]就是数组名,因此a[0]、a[1]就代表着这个一维数组的地址)
1> 数组a的地址是ffc1,数组a[0]的地址也是ffc1,即a = a[0];
2> 元素a[0][0]的地址是ffc1,所以数组a[0]的地址和元素a[0][0]的地址相同,即a[0] = &a[0][0];
3> 最终可以得出结论:a = a[0] = &a[0][0],以此类推,可以得出a[1] = &a[1][0]
3.二维数组的初始化
-
按行进行初始化:int a[2][3] = { {2, 2, 3}, {3, 4, 5} };
-
按存储顺序进行初始化(先存放第1行,再存放第2行)
-
int a[2][3] = {2, 2, 3, 3, 4, 5};
-
对部分元素进行初始化
int a[2][3] = { {2}, {3, 4} };
int b[3][3] = { { }, { , , 2}, {1, 2, 3}}; -
如果只初始化了部分元素,可以省略行数,但是不可以省略列数
int a[][3] = {1, 2, 3, 4, 5, 6};
int a[][3] = {{1, 2, 3}, {3, 5}, {}};
有些人可能想不明白,为什么可以省略行数,但不可以省略列数。也有人可能会问,可不可以只指定行数,但是省略列数?
其实这个问题很简单,如果我们这样写:
int a[2][] = {1, 2, 3, 4, 5, 6}; // 错误写法
大家都知道,二维数组会先存放第1行的元素,由于不确定列数,也就是不确定第1行要存放多少个元素,所以这里会产生很多种情况,可能1、2是属于第1行的,也可能1、2、3、4是第一行的,甚至1、2、3、4、5、6全部都是属于第1行的