1.引入——学习数组之前,我们保存一个数,都会定义一个变量:
int a;//保存一个整数
double b;//保存一个小数
char c;//保存一个字符
......
如果需要保存N个整数、小数、字符,怎么办?一个个得保存显然是行不通的,这时候就该数组出手了。
2.一维数组
2.1 语法格式
类型说明符 数组名[整型表达式];
类型说明符:指定数组元素的类型,任意c语言合法类型都可以。
数组名: 和变量一样,数组也有一个名字,符合c语言标识符的规定。
整型表达式 :指定数组中元素的个数(之前的c语言标准规定该表达式中不能有变量,后面的标准
允许该表达式中出现变量,但是不能初始化)
int n = 10;
int a[n];//可以
int a[n] = {1,2,3....};//不可以
例如:
int a[10];//定义了一个数组,有10个元素,每个元素都是int类型,所以分配了 4*10 字节内存
double b[5];//定义了一个数组,有5个元素,每个元素都是double类型,这里分配了 5*8 字节内存
......
2.2 一维数组元素在内存的存放顺序是存放在连续的内存地址空间。
2.3怎么表示数组中的某个元素:下标法
数组名[下标]//下标:整数范围 [0,n-1] (n表示数组元素个数)
见图
练习:
定义一个数组 int a[10];
依此从键盘输入10个数字,为数组a的各个元素赋值
#include<stdio.h>
int main()
{
int a[10];
int i;
for(i=0;i<10;i++)//验证数组元素存储是连续并且按顺序的
{
printf("%p ",&a[i]);//这里打印输出的是地址(%p)
}
for(i=0;i<10;i++)//依次输入10个整数给数组元素赋值
{
scanf("%d",&a[i]);
}
for(i=0;i<10;i++)//输出数组元素
{
printf("%d ",a[i]);
}
printf("\n");
return 0;
}
2.4 一维数组初始化 (定义数组的时候给数组元素初始值),数组的初始化要用 {}
(1) 数组元素全部初始化
int a[5] = {10,6,23,100,68};//定义了一个数组a,有5个元素,值分别初始化为 10,6,23,100,68
int a[5];
a = {1,2,3,4,5};//错误的
(2) 可以只对前面部分元素初始化
后面的元素采取默认值(int类型默认值为0 double类型默认值 0.0 char类型的默认值'\0'..)
int a[10] = {1,2,3,4,5};
a[0] ~ a[4] 分别初始化为 1,2,3,4,5,而a[5] ~ a[9] 都采取默认值0
(3) 如果对全部元素初始化,定义数组时,可以省略数组元素个数
如:
int a[] = {1,2,3,4,5,6};
可以省略元素个数,编译器会根据{}里面的数值个数反推元素个数,[ ]里会自动补充6
(4) char 类型的数组初始化
char c[5] = {'a','b','c','d','e'};这里因为没有'\0'作为结束标志 所以它是没有指定长度的,后面会细说。
char c[6] = {'a','b','c','d','e'}; //c[5]保存的是 '\0'
还有一种简洁的特殊写法
char c[6] = "abcde"; //这种初始化的效果和上面的效果完全一样, c[5]保存的是 '\0'
练习:
定义一个数组,元素类型为int,为其初始化,再求该数组所有元素之和、最小值和最大值
"打擂台"思路,先假设某个元素是目标元素,然后依次和后面的元素进行比较(打擂台)
int main()
{
int a[10] = {1,2,3,4,5,6,10,21,100,50};
int sum = 0;
int i;
int min = a[0];
int max = a[0];
for(i=0;i<10;i++)
sum += a[i];
for(i=1;i<10;i++)
{
if(a[i] < min)
{
min = a[i];
}
if(a[i] > max)
{
max = a[i];
}
}
printf("数组元素之和:%d\n",sum);
printf("数组最小值为:%d,最大值为:%d\n",min,max);
return 0;
}
练习:
计算斐波拉契数列前15项之和,1 1 2 3 5 8 ...:从第三项开始的数为前两项之和。
先求前15项每一项的值,再循环相加即可
int a[15] = {1,1};
int i;
for(i=2;i<15;i++)//从第三项开始,等于前两项之和
{
a[i] = a[i-1] + a[i-2];//依次计算 a[2]~a[14]的值
}
int sum = 0;
for(i=0;i<15;i++)
{
sum+=a[i];
}
printf("前15项之和为%d\n",sum);
练习:
给定一个一维数组(元素类型是Int),判断该数组元素是否递增
如果递增打印 YES 否则打印NO
int a[10] = {3,4,5....};
递增
a[0] < a[1] < a[2] < a[3] < a[4] < a[5] < a[6] < a[7] < a[8] < a[9]
int flag = 0;
for(i=0;i<9;i++)//注意:防止数组下标越界
{
if(a[i]>=a[i+1])
{
printf("NO\n");
flag = 1;
break;//只要 a[i]>=a[i+1]成立一次,就说明不是递增,打印NO,并且break
}
}
if(flag == 0) //if(i==9)
printf("YES\n");
练习:
给定一个升序的一维数组,查找是否存在某个元素,如果存在打印YES 不存在打印NO
int a[10] = {5,10,14,20,25,30,37,50,100,200};
int x;
scanf("%d",&x);
int i;
for(i=0;i<10;i++)
{
if(a[i] == x)
{
printf("YES\n");
break;
}
}
if(i==10)
{
printf("NO\n");
}
如果上面的数组中有1000000个元素,最坏的情况需要查找1000000次,效率不高,优化算法:
“二分查找法/折半查找法” (使用这种方法的前提是有序)
思路:每次都和中间元素做比较,比中间元素大(排除了前面一半数据),比中间元素小(排除了后面一半数据),相等 就是找到了
#include<stdio.h>
int main()
{
int a[10000];
int i;
for(i=0;i<10000;i++)
{
a[i] = i*2;
}
int x;
scanf("%d",&x);//输入要查找的元素
int begin = 0;
int end = 10000-1;
int mid = (end - begin)/2 + begin; //也可以写为:(end+begin)/2,前面那个方便理解
int count = 0;
while(begin<=end)// begin>end说明范围不存在了,结束循环
{
count ++;
if(x == a[mid])//和中间元素做比较
{
printf("YES,下标为%d\n",mid);
break;
}
else if(x > a[mid])//排除了 mid及前面的所有元素 [mid+1, end]
{
begin = mid+1;
mid = (end - begin)/2+ begin;
}
else//排除了 mid及后面的所有元素 [begin, mid-1]
{
end = mid-1;
mid = (end - begin)/2+ begin;
}
}
if(begin>end)
{
printf("NO\n");
}
printf("一共比较了%d次\n",count);
return 0;
}
还有很多种关于排序的算法,下一章将会做出详解。
3,二维数组:类似数学上的矩阵,有行和列
定义语法:
类型说明符 数组名[行大小][列大小];
行大小,列大小:整形表达式(之前是不能写变量的)
元素个数: 行大小*列大小
类型说明符:每个元素的类型
比如:
int a[3][4];
3行4列共12个元素,每个元素都是int类型
内存分布:
连续按顺序存储
怎么表示数组中的某个元素:下标法
a[i][j](0<=i<N 0<=j<M 其中N为行大小,M为列大小)
一个三行4列的二位数组可以这样表示:
int a[3][4];
a[0][0] a[0][1] a[0][2] a[0][3]
a[1][0] a[1][1] a[1][2] a[1][3]
a[2][0] a[2][1] a[2][2] a[2][3]
练习:
定义一个二维数组,元素类型为int,依次从键盘输入给各个元素赋值,
再打印验证
int a[3][3];
int i,j;
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
{
scanf("%d",&a[i][j]);
}
}
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
{
printf("%d ",a[i][j]);
}
printf("\n");
}
二维数组初始化
用{}
int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
int a[3][4] = {1,2,3,4,5,6,7,8,9,10};//a[2][2] = 0 a[2][3] = 0
int a[3][4] = {{1,2,3},{5,6},{9,10,11}};//a[0][3]=0 a[1][2]=0 a[1][3]=0 a[2][3]=0
//有些情况,行大小可以省略,根据后面的初始值的个数自动推导出来。列大小永远不能省略
int a[][4] = {1,2,3,4,5,6,7,8,9,10};
练习:
定义一个二维数组并初始化,元素类型为int。求“山顶元素”的个数
“山顶元素”:比周围(上下左右)的元素都要大
10 20 80
9 90 70
30 10 8
80,90,30都是山顶元素
#include<stdio.h>
int main()
{
int a[3][3] = {
10, 20 ,80 ,
9 , 90 ,70 ,
30, 10 ,8
};
int count = 0;
int i,j;
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
{
if((i==0 || a[i][j] > a[i-1][j]) //利用惰性运算
&& (i==2 || a[i][j] > a[i+1][j])
&& (j==0 || a[i][j] > a[i][j-1])
&& (j==2 || a[i][j] > a[i][j+1])
)
{
count++;
}
}
}
printf("count=%d\n",count);
return 0;
}
练习:
打印杨辉三角的前10行
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 1
.........
#include<stdio.h>
int main()
{
int a[15][15] = {0};
int i,j;
for(i=0;i<15;i++)
{
a[i][0] = 1;//第一列所有元素都为1
a[i][i] = 1;//斜对角所有元素都为1
}
for(i=2;i<15;i++)//行
{
for(j=1;j<i;j++)
{
a[i][j] = a[i-1][j] + a[i-1][j-1];
}
}
for(i=0;i<15;i++)
{
for(j=0;j<=i;j++)
{
printf("%4d ",a[i][j]);
}
printf("\n");
}
return 0;
}
5,字符数组
数组元素类型是 char ,基本语法也满足前面讲的数组的所有语法
比如:
char c[5] = {'a','b','c','d','e'};
访问元素下标法 : c[0] c[1] ...c[4]
有一些和其他类型数组不一样的地方。如:
初始化可以这么做:
char c[6] = "abcde";//最后一个元素是系统自动补 '\0'
c语言中可以用字符数组来表示一个字符串,字符串:一串以'\0'字符结尾的字符集合
字符串长度:'\0'之前的字符个数(不包括'\0'本身,它是字符串的结束符)
char c[6] = "abcde"; //数组c有6个元素,字符串c的长度是5
char c[5] = {'a','b','c','d','e'};//数组c有5个元素,字符串c的长度不确定的
char c[] = "abcde";//数组c有6个元素,后面有一个'\0',字符串c的长度是5
char c[] = {'a','b','c','d','e'};//数组c有5个元素,字符串c的长度不确定的
char c[6] = {'a','b','c','d','e'};//数组c有6个元素,c[5]默认为'\0',字符串c的长度是5
char c[5]={“abcde”}; “abcde"占用空间是6字节,超出c的长度了
当你想把字符数组当做字符串使用时,必须要明确其长度。在明确其长度时,遍历字符数组比遍历其他类型的数组多了一种方法.
int a[10] = {1,2,3,4,5,6,7,8,9,10};
for(i=0;i<10;i++)
{
printf("%d ",a[i]);
}
char c[6] = "abcde";
for(i=0;i<5;i++)//可以像其他数组一样使用循环语句遍历数组元素
{
printf("%c",c[i]);
}
还可以直接使用 %s 对其进行遍历,如:
printf("%s",c);//使用%s打印时,必须明确其长度,否则会出问题的
//因为 %s打印时,是从第一个元素开始,直到遇到'\0'结束;不会管是否越界
练习:
使用字符数组保存一个字符串,然后把这个字符串中的小写字母变为大写,大写字母变为小写
char c[] = "abc12XYz";
int i;
for(i=0;i<strlen(c);i++)
{
if(c[i]>='a' && c[i]<='z')
c[i] -= 32;
else if(c[i]>='A' && c[i]<='Z')
c[i] += 32;
}
-------------------
int i=0;
while(c[i] != '\0')
{
if(c[i]>='a' && c[i]<='z')
c[i] -= 32;
else if(c[i]>='A' && c[i]<='Z')
c[i] += 32;
i++;
}