乐趣区

关于程序员:探秘C语言数组解锁高效数据管理与多维空间编程技巧

✨✨ 欢送大家来到贝蒂大讲堂✨✨

🎈🎈养成好习惯,先赞后看哦~🎈🎈

所属专栏:C 语言学习
贝蒂的主页:Betty‘s blog

引言

后面贝蒂给大家介绍了抉择构造与循环构造,明天,贝蒂筹备给大家介绍 C 语言中一个十分重要的构造——数组

1. 数组的定义

数组到底是什么呢,顾名思义就是很少数的汇合,其大抵满足上面两个条件:

  1. 这些数的类型必须雷同。
  2. 这些数在内存中必须是间断存储的。
  • 换句话说,数组就是在内存中间断存储的具备雷同类型的一组数据的汇合。
  • 数组分为 ⼀维数组 多维数组,多维数组⼀般⽐较多⻅的是⼆维数组。

2. 一维数组

2.1 创立与初始化

(1) 创立

一维数组的定义形式如下:

类型说明符 数组名[常量表达式];

  1. 类型说明符就是咱们罕用的 存储类型(char int float double….),当然也能够自定义类型。
  2. 数组名就是咱们为其取的名字,最好简略易懂,不便他人浏览。
  3. [] 中的常量值是⽤来 指定数组的⼤⼩ 的,这个数组的⼤⼩是依据理论的需要指定就⾏
  • 留神:在 C99 之后 C 语言语法是反对变长数组的,即 [] 中能够是未知数,然而 VS2022 编译器是不反对的。

例如:

int arr[5];// 示意此时数组 arr 中有 5 个元素,每个元素都是 int 型变量
char arr2[6];
float arr3[7];
double arr4[1 + 4];// 也能够是一个表达式

(2) 初始化

有时候,数组在创立的时候,咱们须要给定⼀些初始值,这种就称为初始化。那数组如何初始化呢?数组的初始化⼀般使⽤⼤括号,将须要初始化的数据放在⼤括号中。

初始化分为两种:齐全初始化 不齐全初始化

int arr1[4] = {1,2,3,4};// 齐全初始化
int arr2[4] = {1,2,3};// 不齐全初始化,残余元素默认为 0
char arr3[10] = "hello";// 初始化字符串
int arr4[];// 谬误初始化
  • 如果进行初始化,能够不在 [] 申明有几个元素,数组会默认初始化几个元素,数组大小就是几个元素,然而 不初始化就肯定要申明有几个元素,否则就会报错。

2.2 数组输出和输入

(1) 数组下标

C 语⾔规定数组是有下标的,下标是从 0 开始的(而不是 1),假如数组有 n 个元素,最初⼀个元素的下标是 n -1,例如:int arr[10]={1,2,3,4,5,6,7,8,9,10},其下标如下图所示:

arr 1 2 3 4 5 6 7 8 9 10
下标 0 1 2 3 4 5 6 7 8 9

(2) 输出

其实数组输出和咱们平时输出差不多,只是输出对象换成了数组。

int main()
{int arr[10];
    int i = 0;
    for (i = 0; i < 10; i++)
    {scanf("%d", &arr[i]);// 循环像数组中输出元素
    }
    return 0;
}

(3) 输入

输入也是同理,咱们能够利用循环输入其数组的每一个元素。

int main()
{int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    int i = 0;
    for (i = 0; i < 10; i++)
    {printf("%d", arr[i]);// 循环输入
    }    
    return 0;
}

2.3 数组的内存存储

(1) 数组名

C 语言规定 数组名示意首元素地址,也就是说 arr==&arr[0],咱们能够通过以下代码来证实:

int main()
{int arr[2] = {1,2};
    if (arr == &arr[0])
    {printf("地址雷同 \n");
    }
    else
    {printf("地址不雷同");
    }
    return 0;
}
(2) 数组元素的存储

咱们晓得了数组名示意首元素的地址之后,那么接下来咱们能够探索数组每个元素在内存中又是怎么存储的呢,咱们将其每个元素的地址打印出察看。

#include <stdio.h>
int main()
{int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    int i = 0;
    for (i = 0; i < 10; i++)
    {printf("&arr[%d] = %p\n", i, &arr[i]);
    }
    return 0;
}

输入后果:

从上述地址察看,地址是由⼩到⼤变动 的,90,94,98…… 每次的增量是 4,并且咱们发现每两个相邻的元素之间相差 4(因为 ⼀个整型是 4 个字节 ),就能够很容易得出结论: 数组在内存中存储是间断的,了解到这一点,就能为当前指针的学习打好根底。

arr 1 2 3 4 5 6 7 8 9 10
下标 0 1 2 3 4 5 6 7 8 9

2.4 一维数组例题

题目:求任意十个整数的和与平均数。

思路:咱们能够先将十个数输出一个数组中,而后循环求其和,在求平均数。

  • 留神:尽管是是个整数,然而最初后果可能是浮点数。

代码参考如下:

int main()
{int arr[10];
    int i = 0;
    for (i = 0; i < 10; i++)
    {scanf("%d", &arr[i]);// 循环输出
    }
    int sum = 0;// 和
    for (i = 0; i < 10; i++)
    {sum += arr[i];
    }
    float avr = sum / 10.0;
    printf("这十个数和为 %d 平均数为 %.1f", sum,avr);
    return 0;
}

3. 二维数组

前⾯咱们学习的数组被称为⼀维数组,数组的元素都是内置类型的,如果咱们把⼀维数组做为数组的元素创立数组,这时候就是⼆维数组,⼆维数组作为数组元素的数组被称为三维数组,⼆维数组以上的数组统称为 多维数组

3.1 创立与初始化

(1) 创立

二维数组定义的个别模式为:

  1. 类型说明符 数组名[常量表达式][常量表达式];
  • 类比一维数组的定义,只不过 二维数组第一个常量表达式示意行,第二个常量表达式示意列

    例如:

int arr[5][5];// 创立五行五列的二维数组
char arr2[3][5];// 字符型二维数组
float arr3[4][5];// 浮点型二维数组

(2) 初始化

二维数组的初始化和一维数组的初始化相似,像⼀维数组⼀样,也是使⽤⼤括号初始化的。

int arr1[3][3] = {1,2};// 不齐全初识化

示意图:

1 2 0
0 0 0
0 0 0
  • 不齐全初始化剩下元素默认初始化为 0。
int arr2[3][3] = {1,2,3,4,5,6,7,8,9};// 齐全初始化

示意图:

1 2 3
4 5 6
7 8 9
int arr3[3][3] = {{1,2},{2,3} };// 依照行初始化

示意图:

1 2 0
2 3 0
0 0 0
  • 按行初始化,剩下未初始化的元素默认为 0.
int arr4[][3] = {1,2,3};// 省略行

​ 示意图:

1 2 3
int arr5[3][];// 谬误初始化
int arr6[][];// 谬误初始化
  • 二维数组规定只能省略行,不能省略列。

3.2 数组的输出和输入

(1) 数组下标

⼆维数组拜访和一维数组相似,也是使⽤ 下标 的模式的,⼆维数组是有⾏和列的,只有锁定了⾏和列就能唯⼀锁定数组中的⼀个元素。C 语⾔规定,⼆维数组的⾏是从 0 开始的,列也是从 0 开始的,例如:int arr[3][3]={1,2,3,4,5,6,7,8,9,10};

示意图:

行 / 列 0 1 2
0 1 2 3
1 4 5 6
2 7 8 9

(2) 输出

别离循环输出行和列,思路大抵和输出一维数组雷同。

int main()
{int arr[3][3] = {0};
    int i = 0;
    for (i = 0; i < 3; i++)// 输出行
    {
        int j = 0;
        for (j = 0; j < 3; j++)// 输出列
        {scanf("%d", &arr[i][j]);
        }
    }
    return 0;

}

(3) 输入

输入天然也与一维数组大致相同,利用循环顺次输入。

int main()
{int arr[3][3] = {1,2,3,4,5,6,7,8,9};
    int i = 0;
    for (i = 0; i < 3; i++)
    {
        int j = 0;
        for (j = 0; j < 3; j++)
        {printf("%d", arr[i][j]);
        }
        printf("\n");// 输入一行后换行
    }
    return 0;
}

3.3 二维数组的存储

(1) 数组名

二维数组的数组名也是一个地址,那和一维数组的数组名有何不同呢,其实 二维数组的数组名示意的是第一行的地址,但可能大家还是有上面的纳闷:

int main()
{int arr[3][3] = {0};
    printf("%p,%p\n", arr,&arr[0][0]);
    return 0;
}

为什么明明二维数组名代表的是第一行的地址,那么为什么和第一个元素的地址雷同呢,其实和字符串的存储一样,如果将所有地址示意进去,太节约内存,而数组在内存中是间断存储的,所以找到首元素的地址,就能找到一行中所有元素的地址。所以就以首元素地址代表第一行的地址

(2) 二维数组元素的存储

像⼀维数组⼀样,咱们如果想钻研⼆维数组在内存中的存储⽅式,咱们也是能够打印出数组所有元素的地址的。代码如下:

int main()
{int arr[3][3] = {1,2,3,4,5,6,7,8,9};
    int i = 0;
    for (i = 0; i < 3; i++)
    {
        int j = 0;
        for (j = 0; j < 3; j++)
        {printf("arr[%d][%d]=%p",i,j, &arr[i][j]);
        }
        printf("\n");// 输入一行后换行
    }
    return 0;
}

​ 输入如下:

通过对下面地址的察看,咱们晓得二 维数组也是在内存中间断存储 的,并且 arr0 和 arr1 的地址之间也差 4 个字节(byte),所以内存存储如下:

arr 1 2 3 4 5 6 7 8 9
下标 0,0 0,1 0,2 1,0 1,1 1,2 2,0 2,1 2,2

3.4 二维数组例题

题目:输出六个数到 2 行 3 列的二维数组 arr 中,将二维数组 arr1 中的数组元素转置,即行列调换,存储到 3 行 2 列的二维数组 arr2 中,输入二维数组 arr2 中的数组元素。

思路:就是循环输出,在转置(行与列替换),最初输入。

代码如下:

int main()
{int arr1[2][3];
    int arr2[3][2];
    int i = 0;
    int j = 0;
    for (i = 0; i < 2; i++)
    {for (j = 0; j < 3; j++)
        {scanf("%d", & arr1[i][j]);
        }
    }
    for (i = 0; i < 2; i++)
    {for (j = 0; j < 3; j++)
        {arr2[j][i] = arr1[i][j];// 转置
        }
    }
    for (i = 0; i < 3; i++)
    {for (j = 0; j < 2; j++)
        {printf("%d", arr2[i][j]);
        }
        printf("\n");
    }
    return 0;
}

4. 变长数组

4.1 概 念

在 C99 规范之前,C 语⾔在创立数组的时候,数组⼤⼩的指定只能使⽤常量、常量表达式,或者如果咱们初始化数据的话,能够省略数组⼤⼩。

例如:

int arr1[10];
char arr2[4];
int arr3[] = {1,2,3};
  • 然而这样的语法限度,让咱们创立数组就不够灵便,有时候数组⼤了节约空间,有时候数组⼜⼩了不够⽤,所以在 C99 中给⼀个 变⻓数组(variable-length array,简称 VLA)的新个性,容许咱们能够使⽤变量指定数组⼤⼩

4.2 用法

例如:

int n;
scanf("%d",&n);
int arr1[n];
  • 变⻓数组的基本特色,就是数组⻓度只有运⾏时能力确定,所以变⻓数组不能初始化。
退出移动版