目录
输入一个日期(yyyy-mm-dd),计算该日期自(1年1月1日)过了多少天
定义一个5*5的二维数组并随意初始化,找出每一行的最大值、每一列的最小值、和所有数据的平均值(尽可能少遍历)
定义一个5*5的二维数组并初始化,计算出最小值周围一圈数据之和(先找出最小值的行下标、列下标、然后再计算周围八个位置是否合法,合法就累加)
一、数组
什么是数组
数组就是变量的组合,是一种批量定义变量的方式
如何定义数组
类型名 数组名[数量];
int arr[8];// 相当于定义了8个int类型的变量
int a1,a2,a3,...;
访问数组中的变量
数组名[下标];
下标从0开始,范围0~数量-1
遍历数组
与for循环配合,使用循环变量作为数组遍历的下标
int arr[10];
for(int i=0; i<10; i++)
{
printf("%d\n",arr[i]);
}
数组的初始化
数组的元素的默认值也是随机的,如果想要对数组初始化可以使用以下语法:
类型名 数组名[数量] = {v1,v2,v3,...};
注意:
1、如果初始化数据过多,编译器会产生警告并丢弃
2、如果初始化数据不足,编译器会自动补0
3、对数组初始化时,数组的初始值可以省略,大括号不能省略,编译器会自动全部补0
4、当使用初始化语法时,数组的数量可以省略,编译器会计算出大括号中数据的个数,然后确定数组的数量
5、初始化语法只能在定义数组时使用,这也是唯一一次能对数组批量访问的机会,后序只能单个元素访问
数组与sizeof
使用方法 | 功能 |
---|---|
sizeof(数组名) | 计算整个数组的总字节数 |
sizeof(数组名[下标]) | sizeof(arr[0]) 计算某个元素的字节数 |
sizeof(数组名)/sizeof(数组名[0]) | 计算数组的元素个数 |
数组越界
使用非法的下标访问该下标的数组元素,该动作称为数组越界
int arr[10];
arr[10] = 10;
C语言中当数组越界访问时,编译器不会报错,因为C编译器是不检查数组下标是否合法的,因为这样可以提高代码的编译速度、运行速度
数据越界的后果
1、运气好,一切正常
2、段错误,操作系统发现程序非法访问内存,主动杀死程序
3、脏数据,数据越界访问到了其它程序、数组、变量的数据,破坏了别人的数据
一些使用数组实现的简单功能
输入一个整数,分解显示
输入12321 输出 1 2 3 2 1
输入-12321 输出 - 1 2 3 2 1
int main(int argc,const char* argv[])
{
int num = 0,cnt = 0;
printf("请输入一个整数:");
scanf("%d",&num);
char arr[10] = {};
if(num < 0)
{
printf("- ");
num = -num; // num = abs(num);
}
while(num)
{
arr[cnt++] = num % 10;
num /= 10;
}
for(int i=cnt-1; i>=0; i--)
{
printf("%hhd ",arr[i]);
}
}
计算显示出100的阶乘的结果,使用数组模拟乘法的运算过程
int main(int argc,const char* argv[])
{
char result[256] = {6};
int cnt = 1; // 当前结果的位数
for(int i=4; i<=100; i++)
{
int carry = 0; // 进位
for(int j=0; j<cnt; j++)
{
int num = i * result[j] + carry;
result[j] = num % 10;
carry = num / 10;
}
while(carry)
{
result[cnt++] = carry % 10;
carry /= 10;
}
}
for(int i=cnt-1; i>=0; i--)
{
printf("%hhd",result[i]);
}
}
输入n,显示前n项斐波那契数列
int main(int argc,const char* argv[])
{
int n1 = 1, n2 = 0, n3 = 0;
int N = 0;
printf("请输入N的值:");
scanf("%d",&N);
for(int i=0; i<N; i++)
{
n3 = n1 + n2;
printf("%d ",n3);
n1 = n2;
n2 = n3;
}
}
显示9*9乘法表
int main(int argc,const char* argv[])
{
for(int i=1; i<10; i++)
{
for(int j=1; j<=i; j++)
{
printf("%d*%d=%02d ",i,j,i*j);
}
printf("\n");
}
}
显示出100-1000之间所有的素数
int main(int argc,const char* argv[])
{
for(int i=100; i<1000; i++)
{
int j;
for(j=2; j<=i/2; j++)
{
if(0 == i%j) break;
}
if(j > i/2)
{
printf("%d ",i);
}
}
}
输入一个日期(yyyy-mm-dd),计算该日期自(1年1月1日)过了多少天
int main(int argc,const char* argv[])
{
unsigned short year = 0;
unsigned char month = 0,day = 0;
printf("请输入一个日期(yyyy-mm-dd):");
scanf("%hu-%hhu-%hhu",&year,&month,&day);
if(month > 12 || month == 0 || day > 31 || day == 0)
{
printf("日期有误\n");
return 0;
}
int sum = 0;
for(int y=1; y<year; y++)
{
sum += 365 + (0==y%4 && 0!=y%100 || 0==y%400);
}
for(int m=1; m<month; m++)
{
switch(m)
{
case 2:
sum += 28 + (0==year%4 && 0!=year%100||0==year%400);
break;
case 4: case 6: case 9: case 11:
sum += 30;
break;
default:
sum += 31;
break;
}
}
printf("共过了%d天\n",sum + day -1);
}
二、二维数组
什么是二维数组
普通一维数组,可以看做若干个变量排成一排
二维数组,可以把若干个类型相同的变量排成一个方阵
定义二维数组
类型名 数组名[行数][列数];
访问二维数组元素
数组名[行下标][列下标];
行下标:0 ~ 行数-1
列下标:0 ~ 列数-1
二维数组的遍历
一般与双层for循环配合,一般外层循环遍历行,内层循环遍历列
int arr[3][5];
for(int i=0; i<3; i++)
{
for(int j=0; j<5; j++)
{
printf("%d ",arr[i][j]);
}
printf("\n");
}
二维数组的初始化
二维数组在初始化时,其它特点与一维数组基本相同
注意:二维数组初始化时,可以省略行数,但是一定不能省略列数,并且要提供初始化数据才可以省略行数,编译器会自动计算元素个数
类型名 数组名[行数][列数] = {{第一行},{第二行},...};
一些使用二维数组实现的简单功能
定义一个5*5的二维数组并随意初始化,找出每一行的最大值、每一列的最小值、和所有数据的平均值(尽可能少遍历)
int main(int argc,const char* argv[])
{
int arr[5][5];
for(int i=0; i<5; i++)
{
for(int j=0; j<5; j++)
{
arr[i][j] = i*5+j;
printf("%d ",arr[i][j]);
}
printf("\n");
}
float avg = 0;
for(int i=0; i<5; i++)
{
int max = arr[i][0];
int min = arr[0][i];
for(int j=0; j<5; j++)
{
if(max < arr[i][j]) max = arr[i][j];
if(min > arr[j][i]) min = arr[j][i];
avg += arr[i][j]/25.0;
}
printf("第%d行的最大值%d,第%d列最小值是%d\n",i,max,i,min);
}
printf("平均值:%f\n",avg);
}
定义一个5*5的二维数组并初始化,计算出最小值周围一圈数据之和(先找出最小值的行下标、列下标、然后再计算周围八个位置是否合法,合法就累加)
int main(int argc,const char* argv[])
{
int arr[5][5];
for(int i=0; i<5; i++)
{
for(int j=0; j<5; j++)
{
arr[i][j] = i*5+j;
printf("%d ",arr[i][j]);
}
printf("\n");
}
int min_x = 0, min_y = 0;
for(int i=0; i<5; i++)
{
for(int j=0; j<5; j++)
{
if(arr[i][j] < arr[min_x][min_y])
{
min_x = i;
min_y = j;
}
}
}
int sum = 0;
for(int i=min_x-1; i<=min_x+1; i++)
{
for(int j=min_y-1; j<=min_y+1; j++)
{
if(i>=0 && i<=4 && j>=0 && j<=4)
{
sum += arr[i][j];
}
}
}
printf("sum=%d\n",sum-arr[min_x][min_y]);
}
三、变长数组
定长数组
使用常量作为定义数组的长度参数,或者使用初始化数据定义数组时省略长度参数,这些数组都称为定长数组,由编译器最终确定数组的长度
变长数组
使用变量作为定义数组的长度参数时,称为变长数组,当程序运行时,执行定义数组的语句前,可以改变数组的长度变量,所以数组的长度可以每一次运行都不同,但是一旦数组的长度确定后,都无法改变
int len;
scanf("%d",&len);
int arr[len];
变长数组的优缺点
优点:可以根据运行的实际需求定义数组的长度,从而节约内存空间
缺点:变长数组不能初始化,对数组的初始化是发生在编译器编译期间,而变长数组的长度是运行到定义语句后才能确定,因此编译器在编译期间无法得知变长数组的长度,因此无法初始化