C语言——数组

数组

数组的概念

什么是数组

数组是相同类型,有序数据的集合。

数组的特征

  • 数组中的数据被称为数组的元素,是同构的
  • 数组中的元素存放在内存空间里 (char player_name[6]:申请在内存中开辟6块连续的基于char类型的变量空间)

衍生概念:下标(索引)

  • 下标或索引代表了数组中元素距离第一个元素的偏移位置。
  • 数组中元素的地址值,下标越大,地址值越大。(每一块内存空间都有一个独有的内存地址)。
  • 数组的下标是从0开始的。

一维数组

数组的定义

类型说明符 数组名[数组容量]

说明:

  • 数组的类型说明符由数组中的元素来决定,也就是元素是什么类型,数组就是什么类型

  • 数组名也是标识符, 我们所说的数组(名),大家可以理解为数据类型是数组的变量(名)。

  • 数组容量也可以叫做常量表达式,举例: int ages[10]、int lcd[1024*768]

类型:代表了数组中元素的类型

容量:数组中能存储多少个元素,数组容量可以是一个常量、常量表达式,还可以是符号常量,但必

须是整型。

深入理解:

  • 定义一个数组,相当于申请了一个可以容纳所指定元素数量的内存单元。所申请的内存单元是连续的。
  • 定义一个数组,相当于定义了多个匿名变量,这些变量可以通过 数组名[下标] 来标识。

举例:

// 定义一个数组
int arr[10];
// 问题:上面数组中,最小下标0,最大下标9

经过上面的案例,分析得到

数组的最大下标 = 数组元素个数(数组容量) - 1

数组元素的访问

原则:数组中的元素不能一次性访问所有元素,只能一个一个的访问。

访问方式:

数组名[下标];

举例:

// 定义一个容纳10个元素的int数组
int arr[10];
// 给数组的第一个元素进行赋值
arr[0] = 89;
// 访问数组的第一个元素
int a = arr[0];
// 问题:以下访问是否正确
int b = arr[10]; // error,下标越界异常

注意:数组元素的访问一定不能越界。

案例:

/*
需求:一维数组案例-引用数组元素。利用循环给数组元素a[0]~a[9]赋值0~9,并且逆序输出
*/
#include <stdio.h>
int main()
{
    // 创建一个数组
    int arr[10];
    // 使用for循环给数组赋值
    for(int i = 0;i < 10;i++)
    {
    	arr[i] = i;
    }
    // 逆序输出
    // 我们通过循环将数组中的元素一个个取出来,称之为遍历
    for(int j = 9;j >= 0;j--)
    {
    	printf("%d ",arr[j]);
    }
    printf("\n"); // 纯粹换行
    return 0;
}

数组的初始化

定义数组的同时,用指定数据来给对应元素赋值。

简化数组定义后,需要对元素一一赋值操作。

语法规则:

类型 数组名[容量] = {常量1,常量2,常量3…};

注意事项:

  • 数组可以部分初始化:也就是可以给数组中前几个元素初始化,未被初始化的元素系统将自动初始化,如0;如果定义数组时未指定数据容量,则系统会根据初始化元素的个数来决定数组容量。
// 1. 如果定义数组时只给数组前几个初始化,后续剩余元素会自动完成初始化,比如赋值0
int arr[10] = {1,2,3,4,5} // 推荐写法,等价于以下写法
int arr[10] = {1,2,3,4,5,0,0,0,0,0}

// 2. 如果定义数组时未指定数据容量,根据初始化元素个数来决定容量
int arr[] = {1,2,3,4,5} // 推荐写法,等价于以下写法
int arr[5] = {1,2,3,4,5}

衍生概念:

  • 柔性数组:柔性数组的概念是在C99标准,针对结构体的最后一个成员可以是一个未指定大小的数组;

广义简单理解:数组容量待定或者待确定的数组,举例: int arr[] = {1,2,3,4,5}

面试题:

  • 在不知道数组类型的情况下,如何确定数组元素的个数
int length = sizeof(arr) / sizeof(arr[0])

说明:

  1. arr就是我们计算的数组本身,sizeof(arr)用来计算该数组中总的字节大小。

  2. sizeof(arr[0])用来计算数组中一个元素所占的字节大小,因为数组中的元素类型相同,所以计算哪一个都行。

  3. sizeof(arr)/sizeof(arr[0])就是用数组中总的字节数除以每一个元素所占的字节数,从而得到元素的个数。

请添加图片描述

数组的典型应用:数据排序

冒泡排序

  • 向后冒泡

    思想:

    1. 一次只排好一个数,针对n个数,最差情况需要 n-1次就可以排好

    2. 每次排序将相邻数据两两比较,将较大或较小的数据向后交换,等所有数据都比较完成,将较大/较小的数就会出现在最后,这也是该数应该有的位置。

    3. 在余下的数中,再次应用第2步的操作,直到只剩下一个数。

  • 向前冒泡

    思想:

    1. 一次只排好一个数,针对n个数,最差情况需要n-1次就可以排好

    2. 每次排序假定第一个元素是最大/最小的,用第一个元素的后面的元素一一与第一个元素比较,遇到较大/较小的和第一个元素交换,访问完数组的最后一个元素,就排好了一个数;

    3. 在余下的数中,再次应用第2步的操作,直到只剩下一个数。

一维数组案例

案例1:非波拉契数列

/*
需求:一维数组案例-非波拉契数列
*/
#include <stdio.h>
int main()
{
    int i;// 循环变量
    int f[20] = {1,1}; // 定义一个数组,用来存储数列,默认存储第1位和第2位
    int length = sizeof(f)/sizeof(f[0]);// 计算数组的元素个数
    // 生出数列存入数组
    for(i = 2;i < length;i++)
    {
        // 给数组元素赋值,从数组的第3个元素开始
        f[i] = f[i - 2] + f[i - 1];
    }
    // 遍历数组
    // 通过循环将数组中的每一个元素取出来,称之为遍历
    for(i = 0;i < length;i++)
    {
        // 遍历的时候,要求一行显示5个数
        if(i % 5 == 0)
        {
        	printf("\n");
        }
        printf("%6d",f[i]);
    }
    printf("\n");
    return 0;
}

案例2:冒泡排序

/*
需求:一维数组案例-冒泡排序
*/
#include <stdio.h>
int main()
{
    // 创建一个数组,用来存储排序的数列
    int arr[11];
    int i,j,temp;// i:比较的轮数,j:每一轮比较的次数,temp:临时变量,用来比较时交换数据
    printf("请输入11个测试整数:\n");
    // 计算数组的大小
    int length = sizeof(arr) / sizeof(int); // 这里 sizeof(int) 等价于 sizeof(arr[0]);
    // 通过循环录入数据
    for(i = 0;i < length; i++)
    {
    	scanf("%d",&arr[i]);
    }
    printf("\n");
    // 对数组arr使用冒泡进行排序(注意:我们使用标准冒泡,大家也可以自行补充优化版的冒泡,如鸡尾酒排序法
    等等)
    // 外层循环:控制比较的轮数,因为有11个数,所以我们需要比较 length -1 轮,也就是比较10轮
    for(i = 0;i < length -1;i++)
    {
        // 内层循环:每一轮比较的次数,每一轮比较的次数为 length - 1 - i, 3-1-0=2,3-1-1=1,3-1-2=0
        for(j = 0;j < length-1-i;j++)
        {
            // 相邻的两个数进行比较,满足条件交换位置
            if(arr[j] > arr[j+1])
            {
                temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
        }
    }
    printf("冒泡排序后遍历数组:\n");
    for(i = 0; i < length; i++)
    {
    	printf("%4d",arr[i]);
    }
    printf("\n");
    return 0;
}

案例3:从键盘输入年、月、日,计算并输出该日是该年的第几天。

/*
需求:一维数组案例-从键盘输入年、月、日,计算并输出该日是该年的第几天。
*/
#include <stdio.h>
int main()
{
    // 定义变量:年,月,日,统计总天数,循环变量,用来遍历当前月前面的月份
    int year,month,day,sum,k;
    // 定义一个数组,用来存放1~12月每月的天数
    int t[] = {31,0,31,30,31,30,31,31,30,31,30,31};// 柔性数组
    printf("请输入年份、月份、天:\n");
    scanf("%d,%d,%d",&year,&month,&day);
    // 因为二月比较特殊,存在平年和润年这样的因素,所以需要进行平年和润年的判断
    if((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
    {
    	t[1] = 29; // 润年 2月 29天
    }
    else
    {
    	t[1] = 28; // 平年 2月 28天
    }
    sum = day; // 默认记录最后一个月的天数
    // 这是该年的第几天
    for(k = 0; k < month -1;k++)
    {
    	sum += t[k]; // 叠加前几个月的天数
    }
    printf("%d月%d日是%d年的第%d天。\n",month,day,year,sum);
    return 0;
}
t[1] = 29; // 润年 2月 29天
}
else
{
	t[1] = 28; // 平年 2月 28天
}
sum = day; // 默认记录最后一个月的天数
// 这是该年的第几天
for(k = 0; k < month -1;k++)
{
	sum += t[k]; // 叠加前几个月的天数
}
printf("%d月%d日是%d年的第%d天。\n",month,day,year,sum);
return 0;

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值