前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >江哥带你玩转C语言 | 10- C语言数组

江哥带你玩转C语言 | 10- C语言数组

原创
作者头像
极客江南
修改2021-07-12 10:26:23
5490
修改2021-07-12 10:26:23
举报
文章被收录于专栏:代码情缘代码情缘

数组的基本概念

  • 数组,从字面上看,就是一组数据的意思,没错,数组就是用来存储一组数据的
    • 在C语言中,数组属于构造数据类型
  • 数组的几个名词
    • 数组:一组相同数据类型数据的有序的集合
    • 数组元素: 构成数组的每一个数据。
    • 数组的下标: 数组元素位置的索引(从0开始)
  • 数组的应用场景
    • 一个int类型的变量能保存一个人的年龄,如果想保存整个班的年龄呢?
      • 第一种方法是定义很多个int类型的变量来存储
      • 第二种方法是只需要定义一个int类型的数组来存储
代码语言:javascript
复制
#include <stdio.h>

int main(int argc, const char * argv[]) {
    /*
    // 需求: 保存2个人的分数
    int score1 = 99;
    int score2 = 60;
    
    // 需求: 保存全班同学的分数(130人)
    int score3 = 78;
    int score4 = 68;
    ...
    int score130 = 88;
    */
    // 数组: 如果需要保存`一组``相同类型`的数据, 就可以定义一个数组来保存
    // 只要定义好一个数组, 数组内部会给每一块小的存储空间一个编号, 这个编号我们称之为 索引, 索引从0开始
    // 1.定义一个可以保存3个int类型的数组
    int scores[3];
    
    // 2.通过数组的下标往数组中存放数据
    scores[0] = 998;
    scores[1] = 123;
    scores[2] = 567;
   
    // 3.通过数组的下标从数组中取出存放的数据
    printf("%i\n", scores[0]);
    printf("%i\n", scores[1]);
    printf("%i\n", scores[2]);
    return 0;
}

定义数组

  • 元素类型 数组名[元素个数];
代码语言:javascript
复制
// int 元素类型
// ages 数组名称
// [10] 元素个数
int ages[10];

初始化数组

  • 定义的同时初始化
  • 指定元素个数,完全初始化
    • 其中在{ }中的各数据值即为各元素的初值,各值之间用逗号间隔
代码语言:javascript
复制
int ages[3] = {4, 6, 9};
  • 不指定元素个数,完全初始化
    • 根据大括号中的元素的个数来确定数组的元素个数
代码语言:javascript
复制
int nums[] = {1,2,3,5,6};
  • 指定元素个数,部分初始化
    • 没有显式初始化的元素,那么系统会自动将其初始化为0
代码语言:javascript
复制
int nums[10] = {1,2};
  • 指定元素个数,部分初始化
代码语言:javascript
复制
int nums[5] = {[4] = 3,[1] = 2};
  • 不指定元素个数,部分初始化
代码语言:javascript
复制
int nums[] = {[4] = 3};
  • 先定义后初始化
代码语言:javascript
复制
int nums[3];
nums[0] = 1;
nums[1] = 2;
nums[2] = 3;
  • 没有初始化会怎样?
    • 如果定义数组后,没有初始化,数组中是有值的,是随机的垃圾数,所以如果想要正确使用数组应该要进行初始化。
代码语言:javascript
复制
int nums[5];
printf("%d\n", nums[0]);
printf("%d\n", nums[1]);
printf("%d\n", nums[2]);
printf("%d\n", nums[3]);
printf("%d\n", nums[4]);
输出结果:
0
0
1606416312
0
1606416414
  • 注意点:
  • 使用数组时不能超出数组的索引范围使用, 索引从0开始, 到元素个数-1结束
  • 使用数组时不要随意使用未初始化的元素, 有可能是一个随机值
  • 对于数组来说, 只能在定义的同时初始化多个值, 不能先定义再初始化多个值
代码语言:javascript
复制
int ages[3];
ages = {4, 6, 9}; // 报错

数组的使用

  • 通过下标(索引)访问:
代码语言:javascript
复制
// 找到下标为0的元素, 赋值为10
ages[0]=10;
// 取出下标为2的元素保存的值
int a = ages[2];
printf("a = %d", a);

数组的遍历

  • 数组的遍历:遍历的意思就是有序地查看数组的每一个元素
代码语言:javascript
复制
    int ages[4] = {19, 22, 33, 13};
    for (int i = 0; i < 4; i++) {
        printf("ages[%d] = %d\n", i, ages[i]);
    }

数组长度计算方法

  • 因为数组在内存中占用的字节数取决于其存储的数据类型和数据的个数
    • 数组所占用存储空间 = 一个元素所占用存储空间 * 元素个数(数组长度)
  • 所以计算数组长度可以使用如下方法 数组的长度 = 数组占用的总字节数 / 数组元素占用的字节数
代码语言:javascript
复制
    int ages[4] = {19, 22, 33, 13};
    int length =  sizeof(ages)/sizeof(int);
    printf("length = %d", length);
输出结果: 4

练习

  • 正序输出(遍历)数组
代码语言:javascript
复制
    int ages[4] = {19, 22, 33, 13};
    for (int i = 0; i < 4; i++) {
        printf("ages[%d] = %d\n", i, ages[i]);
    }
  • 逆序输出(遍历)数组
代码语言:javascript
复制
    int ages[4] = {19, 22, 33, 13};
    for (int i = 3; i >=0; i--) {
        printf("ages[%d] = %d\n", i, ages[i]);
    }
  • 从键盘输入数组长度,构建一个数组,然后再通过for循环从键 盘接收数字给数组初始化。并使用for循环输出查看

数组内部存储细节

  • 存储方式:
    • 1)内存寻址从大到小, 从高地址开辟一块连续没有被使用的内存给数组
    • 2)从分配的连续存储空间中, 地址小的位置开始给每个元素分配空间
    • 3)从每个元素分配的存储空间中, 地址最大的位置开始存储数据
    • 4)用数组名指向整个存储空间最小的地址
  • 示例
代码语言:javascript
复制
#include <stdio.h>
int main()
{
    int num = 9;
    char cs[] = {'l','n','j'};
    printf("cs = %p\n", &cs);       // cs = 0060FEA9
    printf("cs[0] = %p\n", &cs[0]); // cs[0] = 0060FEA9
    printf("cs[1] = %p\n", &cs[1]); // cs[1] = 0060FEAA
    printf("cs[2] = %p\n", &cs[2]); // cs[2] = 0060FEAB

    int nums[] = {2, 6};
    printf("nums = %p\n", &nums);      // nums = 0060FEA0
    printf("nums[0] = %p\n", &nums[0]);// nums[0] = 0060FEA0
    printf("nums[1] = %p\n", &nums[1]);// nums[1] = 0060FEA4
    
    return 0;
}
  • 注意:字符在内存中是以对应ASCII码值的二进制形式存储的,而非上述的形式。

数组的越界问题

  • 数组越界导致的问题
    • 约错对象
    • 程序崩溃
代码语言:javascript
复制
    char cs1[2] = {1, 2};
    char cs2[3] = {3, 4, 5};
    cs2[3] = 88; // 注意:这句访问到了不属于cs1的内存
    printf("cs1[0] = %d\n", cs1[0] );
输出结果: 88

为什么上述会输出88, 自己按照"数组内部存储细节"画图脑补


数组注意事项

  • 在定义数组的时候[]里面只能写整型常量或者是返回整型常量的表达式
代码语言:javascript
复制
 int ages4['A'] = {19, 22, 33};
 printf("ages4[0] = %d\n", ages4[0]);

  int ages5[5 + 5] = {19, 22, 33};
  printf("ages5[0] = %d\n", ages5[0]);

  int ages5['A' + 5] = {19, 22, 33};
  printf("ages5[0] = %d\n", ages5[0]);
  • 错误写法
代码语言:javascript
复制
// 没有指定元素个数,错误
int a[];

// []中不能放变量
int number = 10;
int ages[number]; // 老版本的C语言规范不支持
printf("%d\n", ages[4]);

int number = 10;
int ages2[number] = {19, 22, 33} // 直接报错

// 只能在定义数组的时候进行一次性(全部赋值)的初始化
int ages3[5];
ages10 = {19, 22, 33};

// 一个长度为n的数组,最大下标为n-1, 下标范围:0~n-1
int ages4[4] = {19, 22, 33}
ages4[8]; // 数组角标越界
  • 练习
    • 从键盘录入当天出售BTC的价格并计算出售的BTC的总价和平均价(比如说一天出售了10个比特币)

数组和函数

  • 数组可以作为函数的参数使用,数组用作函数参数有两种形式:
    • 一种是把数组元素作为实参使用
    • 一种是把数组名作为函数的形参和实参使用

数组元素作为函数参数

  • 数组的元素作为函数实参,与同类型的简单变量作为实参一样,如果是基本数据类型, 那么形参的改变不影响实参
代码语言:javascript
复制
void change(int val)// int val = number
{
    val = 55;
}
int main(int argc, const char * argv[])
{
    int ages[3] = {1, 5, 8};
    printf("ages[0] = %d", ages[0]);// 1
    change(ages[0]);
    printf("ages[0] = %d", ages[0]);// 1
}
  • 用数组元素作函数参数不要求形参也必须是数组元素

数组名作为函数参数

  • 在C语言中,数组名除作为变量的标识符之外,数组名还代表了该数组在内存中的起始地址,因此,当数组名作函数参数时,实参与形参之间不是"值传递",而是"地址传递"
  • 实参数组名将该数组的起始地址传递给形参数组,两个数组共享一段内存单元, 系统不再为形参数组分配存储单元
  • 既然两个数组共享一段内存单元, 所以形参数组修改时,实参数组也同时被修改了
代码语言:javascript
复制
void change2(int array[3])// int array = 0ffd1
{
    array[0] = 88;
}
int main(int argc, const char * argv[])
{
    int ages[3] = {1, 5, 8};
    printf("ages[0] = %d", ages[0]);// 1
    change(ages);
    printf("ages[0] = %d", ages[0]);// 88
}

数组名作函数参数的注意点

  • 在函数形参表中,允许不给出形参数组的长度
代码语言:javascript
复制
void change(int array[])
{
    array[0] = 88;
}
  • 形参数组和实参数组的类型必须一致,否则将引起错误。
代码语言:javascript
复制
void prtArray(double array[3]) // 错误写法
{
    for (int i = 0; i < 3; i++) {
        printf("array[%d], %f", i, array[i]);
    }
}
int main(int argc, const char * argv[])
{
    int ages[3] = {1, 5, 8};
    prtArray(ages[0]);
}
  • 当数组名作为函数参数时, 因为自动转换为了指针类型,所以在函数中无法动态计算除数组的元素个数
代码语言:javascript
复制
void printArray(int array[])
{
    printf("printArray size = %lu\n", sizeof(array)); // 8
    int length = sizeof(array)/ sizeof(int); // 2
    printf("length = %d", length);
}
  • 练习:
    • 设计一个函数int arrayMax(int a[], int count)找出数组元素的最大值
    • 从键盘输入3个0-9的数字,然后输出0~9中哪些数字没有出现过
    • 要求从键盘输入6个0~9的数字,排序后输出

如果觉得文章对你有帮助,点赞、收藏、关注、评论,一键四连支持,你的支持就是江哥持续更新的动力。

配套视频地址

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 数组的基本概念
  • 定义数组
  • 初始化数组
  • 数组的使用
  • 数组的遍历
  • 数组长度计算方法
  • 练习
  • 数组内部存储细节
  • 数组的越界问题
  • 数组注意事项
  • 数组和函数
  • 数组元素作为函数参数
  • 数组名作为函数参数
  • 数组名作函数参数的注意点
  • 配套视频地址
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档