04_数组

1 数组的使用

        在实际的数据存储过程中,有多个相同类型的数据元素需要存储,此时可以使用数组来存储。在数组存储过程,内存空间连续,可以通过数据元素的存储位置表示具体的数据元素。

数组的定义:

        所谓的数组,表示的多个相同数据类型元素(变量)在连续内存空间中依次存储的数据集合。

数组分类:

        根据集合数据元素的维度可以将其分为:一维数组、二维数组和多维数组。

        根据数据元素的数据类型可以将其分为:int数组、char数组等。

数组使用的意义:

        1. 对于数组元素的访问时,对于连续的数组元素访问可以使用循环控制语句访问,从而可以简化代码逻辑。

        2. 通过数组元素,可以实现多个相同类型数据元素存储,简化数据访问过程。

2 一维数组

        所谓的一维数组,数据元素的维度为一,线性关系。

2.1 一维数组定义语法

        存储类型 数据类型 数组变量名称[常量表达式];

        存储类型:整个集合的存储类型,表示整个数组空间的存储属性。

        数据类型:数组集合中数组元素的数据类型,可以是基本数据类型、构造数据类型;

        数组变量名称:整个数组集合的名称,也是一个变量(由多个相同类型元素所构成的集合变量);

        常量表达式:是一个常量值,表示数组集合中数据元素的个数。

对于数组的定义,可以定义为全局变量,也可以定义为局部变量。

#include <stdio.h>

int Arr[10];    /* 定义全局变量数组:数组集合是由10个int类型数据元素构成的集合 */

int main()
{
        int arr[5];    /* 定义局部变量数组:数组集合是由5个int类型数据元素构成的集合 */
        
        printf("sizeof(Arr) = %ld\n", sizeof(Arr));    /* 10 * sizeof(int) = 40 */
        printf("sizeof(arr) = %ld\n", sizeof(arr));
    /* 5 * sizeof(int) = 20 */
}

2.2 一维数组元素的访问

        对于数组元素的访问,不能整体访问,只能逐一元素访问

        在数组元素访问的时候,避免数组元素的越界,在越界的时候会出现未知异常(段错误、数据异常、程序正常执行等)。

2.3 一维数组元素的初始化

2.3.1 只做定义,不做初始化

        如果定义数组是全局变量或者static修饰的局部变量,数组元素的初始值为0值。

        如果定义数组是auto局部变量,数组元素的初始值为随机值。

#include <stdio.h>

int arr[5];    /* 定义了5个int类型的元素,由于只做定义未设置初始值,每一个元素的初始值为默认0值 */

int main()
{
        int i;

        static int Arr[5];    /* 定义了5个int类型的元素,由于只做定义未设置初始值,每一个元素的初始值为默认0值 */
        int arrary[5];        /* 定义了5个int类型的元素,由于只做定义未设置初始值,每一个元素的初始值为随机值 */

        for (i = 0; i < sizeof(arr)/sizeof(arr[0]); i++) {
                printf("arr[%d] = %d\n", i, arr[i]);
        }
    
        for (i = 0; i < sizeof(Arr)/sizeof(Arr[0]); i++) {
                printf("Arr[%d] = %d\n", i, Arr[i]);
        }

        for (i = 0; i < sizeof(arrary)/sizeof(arrary[0]); i++) {
                printf("arrary[%d] = %d\n", i, arrary[i]);
        }
}

2.3.2 在定义的同时,设置元素初始值

        1.全部元素初始化

                a.保留数组元素定义时候的常量表达式,同时初始化数组的元素个数等于常量表达式;

int a[5] = {1, 2, 3, 4, 5};    /* 依次初始化数组元素:a[0] = 1, a[1] = 2, a[2] = 3, a[3] = 4, a[4] = 5 */

                b.在定义的时候初始化数组元素,省略常量表达式;

               数组元素的个数由初始化元素的个数决定。

int a[] = {1, 2, 3, 4, 5};    /* 数组定义的时候会统计初始化元素的个数表示数组元素的个数,并依次对数组元素初始化:
a[0] = 1, a[1] = 2, a[2] = 3, a[3] = 4, a[4] = 5 */

        2.部分初始化

        在定义的时候,不省略常量表达式,同时初始化元素值的个数小于常量表达式的值。

从数组的首元素开始依次初始化,未初始化元素的初始值默认为0值。

int a[5] = {1, 2, 3};    /* 定义的数组元素个数大于初始化元素值个数,从首元素开始依次赋值,未赋值数组元素默认为0值:
a[0] = 1, a[1] = 2, a[2] = 3, a[4] = 0, a[5] = 0 */

2.4 一维数组练习

1.现由以下序列:1,1,2,3,5,8,…… 现要求倒序输出序列的前30项。

        分析:

        1) 需要输出序列的前30项,定义一个至少30个int类型元素的数组;

        2)从序列的第2项开始满足规则:a[i] = a[i-1]+a[i-2];

        3) 对于前2项数据,直接初始设置为1;

#include <stdio.h>

int main()
{
        int i;
        int a[30] = {1, 1};     /* 定义一个有30个int类型元素的一维数组,并初始化a[0]=1,a[1]=1 */

        for(i = 2; i < 30; i++)
                a[i] = a[i-1] + a[i-2];    /* 从第2项开始,值等于前两项之和 */

        for (i = 29; i >= 0; i--) 
                printf("a[%d] = %d\n", i, a[i]);

        return 0;
}

2.有序序列,倒序存储

        分析:

        1) 构建有序序列,定义有n个元素的一维数组存储;

        2)依次实现数据元素的交换:第i项和第n-1-i项进行交换。

        3) 在交换的前n/2和后n/2项进行交换。

#include <stdio.h>

int main()
{
        int i;
        int tmp;
        int a[10] = {0,1,2,3,4,5,6,7,8,9};

        for (i = 0; i < 5; i++) {    /* 循环实现第i项和第9-i项数据的交换 */
                tmp = a[i];
                a[i] = a[9-i];
                a[9-i] = tmp;
        }
    
        for (i = 0; i < 10; i++)
                printf("%d", a[i]);
        printf("\n");
}

3.实现无序数组元素的排序

分析:

        就是实现一维数组元素的顺序存储,排序的实现。排序的算法有很多;

        顺序插入排序,冒泡排序、折半查找插入排序、快速排序等。

#include <stdio.h>

int main()
{
        int i;
        int j;
        int tmp;
    
        int a[10] = {12, 3, 26, 7, 23, 98, 1, 65, 2, 10};
        /* 外部循环,控制排序的次数,每循环一次排序序列元素个数-1 */         
        for (j = sizeof(a)/sizeof(a[0]); j > 1; j--) {
                /* 内循环,依次对相邻的两个元素进行比较,满足条件交换。实现将最大一个元素移动到序列的最后位置 */
                for (i = 0; i < j-1; i++) {
                        /* 相邻两个元素比较,前者大交换数据 */
                        if (a[i] > a[i+1]) {
                                tmp = a[i];    
                                a[i] = a[i+1];
                                a[i+1] = tmp;
                        }
                }
        }    
        /* 循环输出数组中的元素 */
        for (i = 0; i < sizeof(a)/sizeof(a[0]); i++)
                printf("%d ", a[i]);
        printf("\n");
        return 0;
}

3 二维数组

        所谓的二维数组,指的是数组集合中维度为二,分别表示行维度和列维度。

3.1 二维数组定义的语法

        存储类型 数据类型 数组变量名称[行常量表达式][列常量表达式];

                存储类型:表示整个数组集合存储空间的属性。

                数据类型:表示数组元素的数据类型,可以基本数据类型和构造数据类型;

                数组变量名称:表示的是整个数组集合变量的名称,表示的是整个数组集合空间。

                常量表达式:由行和列构成,表示数组集合中每一个元素。

                        行常量表达式:表示的是数组元素的行数;

                        列常量表达式:表示的是数组元素的列数;

        实例:定义一个有3行4列的数据元素类型为int类型的二维数组arr: int arr[3][4];

        在整个定义的过程中,可以是全局变量和局部变量。

#include <stdio.h>

int Arr[3][4];        /* 定义一个全局的3行4列的二维数组:元素类型是int类型, */

int main()
{
        int arr[3][4];    /* 定义一个局部的3行4列的二维数组:元素类型是int类型, */

        printf("sizeof(Arr) = %ld\n", sizeof(Arr));    /* 整个集合空间的大小为:3*4*sizeof(int) = 48 */
        printf("sizeof(arr) = %ld\n", sizeof(arr));    /* 整个集合空间的大小为:3*4*sizeof(int) = 48 */
}

3.2 二维数组的理解和访问

二维数组的访问:在访问的过程中,和一维数组相同,不能整体访问,只能逐一元素访问;

具体形式:数组名称[行下标][列下标]; 行下标范围:[0,行常量表达式值-1],列下标范围:[0, 列常量表达式值-1]

#include <stdio.h>

int main()
{
        int i;
        int j;

        int a[3][4];    /* 定义一个3行4列的二维数组 */

        for (i = 0; i < sizeof(a)/sizeof(a[0]); i++) {    /* 行循环 */
                for (j = 0; j < sizeof(a[0])/sizeof(a[0][0]); j++) {    /* 列循环 */
                        printf("%d", a[i][j]);    /* 输出当数据元素数据 */
                }   
                printf("\n");    /* 每完成一行的输出,换行 */
        }   
}

3.3 二维数组初始化

3.3.1 只做定义,不做初始化

        如果定义的二维数组是全局变量和static修饰的局部变量,数组元素的默认初始值为0值;

        如果定义的二维数组是auto局部变量,数组元素的默认初始值为随机值。

#include <stdio.h>

int arr[3][4];    /* 在定义的时候未初始化,默认初始化值为0值 */

int main()
{
        int i;
        int j;

        int a[3][4];    /* 局部变量定义的时候未设置初始值,默认初始值为随机值 */

        for (i = 0; i < sizeof(a)/sizeof(a[0]); i++) {
                for (j = 0; j < sizeof(a[0])/sizeof(a[0][0]); j++) {
                        printf("%d", a[i][j]);    /* 局部变量,元素未初始化,默认初始值为随机值 */
                }   
                printf("\n");
        }   

        for (i = 0; i < sizeof(arr)/sizeof(arr[0]); i++) {
                for (j = 0; j < sizeof(arr[0])/sizeof(arr[0][0]); j++) {
                        printf("%d", arr[i][j]);    /* 全局变量,元素未初始化,默认初始值为0值 */
                }
                printf("\n");
        }
         return 0;
}

3.3.2 在定义的时候设置初始值

1.全部初始化

        a.保留常量表达式

                初始化数值个数等于行常量表达式乘以列常量表达式的结果;依次将初始化数值赋值给数组元素

          i.逐个元素初始化 

int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};    /* 依次将初始化数值赋值给数组元素 */
/*  数组元素的值:
    a[0][0] = 1, a[0][1] = 2, a[0][2] = 3, a[0][3] = 4,
    a[1][0] = 5, a[1][1] = 6, a[1][2] = 7, a[1][3] = 8,
    a[2][0] = 9, a[2][1] = 10, a[2][2] = 11, a[2][3] = 12,
*/

         ii.逐行元素初始化

int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};    /* 依次将每行初始数值数据依次赋值给数组元素 */
/*  数组元素的值:
    a[0][0] = 1, a[0][1] = 2, a[0][2] = 3, a[0][3] = 4,
    a[1][0] = 5, a[1][1] = 6, a[1][2] = 7, a[1][3] = 8,
    a[2][0] = 9, a[2][1] = 10, a[2][2] = 11, a[2][3] = 12,
*/

        b.省略常量表达式

                只能省略行常量表达式,不能省略列常量表达式。

                行数会根据初始化数据元素的个数来自动统计计算得到。

int a[][4] = {1,2,3,4,5,6,7,8,9,10,11,12};    /* 依次将初始化数值赋值给数组元素, */
/*  数组元素的值:
    a[0][0] = 1, a[0][1] = 2, a[0][2] = 3, a[0][3] = 4,
    a[1][0] = 5, a[1][1] = 6, a[1][2] = 7, a[1][3] = 8,
    a[2][0] = 9, a[2][1] = 10, a[2][2] = 11, a[2][3] = 12,
*/
int a[][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};    /* 依次将每行初始数值数据依次赋值给数组元素 */
/*  数组元素的值:
    a[0][0] = 1, a[0][1] = 2, a[0][2] = 3, a[0][3] = 4,
    a[1][0] = 5, a[1][1] = 6, a[1][2] = 7, a[1][3] = 8,
    a[2][0] = 9, a[2][1] = 10, a[2][2] = 11, a[2][3] = 12,
*/

2.部分元素初始化

        a.保留常量表达式

/* 1. 逐个元素初始化设置 */
int a[3][4] = {1,2,3,4,5,6,7};    /* 在逐个数组元素初始化设置的时候,初始化元素个数 小于 行常量表达式值*列常量表达式值 */
/*  数组元素的值:顺序设置,未初始化元素默认值为0值
    a[0][0] = 1, a[0][1] = 2, a[0][2] = 3, a[0][3] = 4,
    a[1][0] = 5, a[1][1] = 6, a[1][2] = 7, a[1][3] = 0,
    a[2][0] = 0, a[2][1] = 0, a[2][2] = 0, a[2][3] = 0,
*/
/* 2. 逐行元素初始化设置 */
int a[3][4] = {{1,2},{3,4}};    /* 每一行初始化数值个数 小于等于 二维数组列数 */
/*  数组元素的值:按行顺序设置,行元素的值未初始化则默认为0值。如果需要将某行元素全部设置为0,直接将该行使用{}。
    a[0][0] = 1, a[0][1] = 2, a[0][2] = 0, a[0][3] = 0,
    a[1][0] = 3, a[1][1] = 4, a[1][2] = 0, a[1][3] = 0,
    a[2][0] = 0, a[2][1] = 0, a[2][2] = 0, a[2][3] = 0,
*/

3.4 二维数组的练习

输出杨辉三角的前10行

1

1 1

1 2 1

1 3 3 1

1 4 6 4 1

……

思路:

1) 对于杨辉三角,第i行有i个元素需要存储,此时可以定义一个二维数组,行元素个数和列元素个数相同

        int a[N][N];

2) 第i行的第0个元素和第i个元素,初始值为1;

        a[i][0] = a[i][i] = 1;

3) 从2行开始,当 0 < j < i,满足:a[i][j] = a[i-1][j] + a[i-1][j-1];

#include <stdio.h>

#define N  10
int main()
{
        int i; 
        int j;

        int a[N][N] = {{1}, {1,1}};

        for (i = 2; i < N; i++) {
                a[i][0] = a[i][i] = 1;
                for (j = 1; j < i; j++) {
                        a[i][j] = a[i-1][j] + a[i-1][j-1];
                }
        }

        for (i = 0; i < N; i ++) {
                for (j = 0; j <= i; j++ ) {
                        printf("%5d", a[i][j]);
                }
                printf("\n");
        }        
        return 0;
}

使用二维数组存储杨辉三角的时候,存在空间资源的浪费。优化资源,可以考虑使用一维数组顺序存储。

        1) 空间的开辟:需要存储n行数据的存储空间大小 = 1+2+3+……+n

                需要存储元素的个数:(n+1)*n/2

        2) 第i行元素的起始序号:i*(i+1)/2

        3) 第i行第j个元素的值的设置:

                a[start_num+j] = a[start_num+j-i-1] + a[start_num+j-i];

#include <stdio.h>

#define N       10
int main()
{
        int i;
        int j;
        int start_num;

        int a[N*(N+1)/2] = {1,1,1};    /* 定义一维数组空间 */

        for (i = 2; i < N; i++) {
                start_num = i*(i+1)/2;    /* 得到第i行元素的起始序号 */
                a[start_num] = 1;
         /* 设置第i行首元素的值 */
                a[start_num+i] = 1;       /* 设置第i行最后一个元素的值 */
                for (j = 1; j < i; j++) {
                        a[start_num+j] = a[start_num+j-i-1] + a[start_num+j-i];    /* 设置第i行第j个元素的值 */
                }
        }

        for (i = 0; i < N; i++) {
                start_num = i*(i+1)/2;  
                for (j = 0; j <= i; j++ ) {
                        printf("%5d", a[start_num+j]);
                }
                printf("\n");
        }
        return 0;
}

4. 多维数组

        所谓的多维数组,指的是数组的维度有多个维度。

4.1 多维数组的定义语法

        存储类型 数据类型 数组变量名称[常量表达式]……[常量表达式]; 说明:数组每增加一个维度,其[常量表达式]增加一个。

4.2 多维数组的理解

#include <stdio.h>

int main()
{
        int i;
        int j;
        int k;

        int a[2][3][4] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24};
        
        
 
        for (i = 0; i < sizeof(a)/sizeof(a[0]); i++) {    /* 按层循环 */
                for (j = 0; j < sizeof(a[0])/sizeof(a[0][0]); j++) {    /* 按行循环 */
                        for (k = 0; k < sizeof(a[0][0])/sizeof(a[0][0][0]); k++) {    /* 列循环 */
                                printf("%d", a[i][j][k]);
                        }   
                        printf("\n");
                }   
                printf("-------------\n");
        }   

}

5 字符数组

        所谓的字符数组,也称为字节数组,每一个数据元素都占用1字节存储空间,数据内容可以是字符,也可以是整型数值数据。在实际应用过程中,运用较多,可以存储任意数据,包含音频、图像数据等。

5.1 一维字符数组

        其实质是是一维数组,数据元素的类型为char类型

5.1.1 定义语法

        存储类型 数据类型(char) 数组名称[常量表达式];

        实例:有10个元素的字符数组buf

        char buf[10];

5.1.2 数组元素的访问

        对于字符数组的访问,不能整体访问,逐一元素访问

        数组名称[下标]; 下标范围:[0, 数组元素个数-1]

        %c ==> 输出的数据为字符数据

        PS:字符输出的时候,不是将存储的任意字符数据都输出,其中有些数据不能正常输出。只有Ascii编码值的符号可见的情况下,才能够正常输出。

        %d ==> 输出的是Ascii编码的数值

        %s ==> 输出的从起始地址开始的字符串数据

        PS:通过起始地址开始访问,每访问一个元素数据,向后偏移一个元素,遇到'\0'结束访问。

                1) 数组末尾元素之前的某个元素值为'\0',数组元素访问不完整;

                2) 数组末尾元素是'\0',访问到完整的数组元素。

                3) 数组元素空间中没有'\0',访问数组元素越界。

#include <stdio.h>

int main()
{
        int i;
        char buf[32] = "abcdefg\n";

        for (i = 0; i < 32; i++) {
                printf("%c", buf[i]);    /* 访问字符 */
        }   
        printf("\n");

        for (i = 0; i < 32; i++) {
                printf("%d ", buf[i]);    /* 访问Ascii编码数值 */
        }   
        printf("\n");

        printf("%s\n", buf);        /* 通过起始地址访问字符串数据 */

}

5.1.3 字符数组元素初始化

1.只做定义,不做初始化设置

        位于静态存储(全局变量和static修饰的局部变量),数组元素的默认初始值为0值('\0');

        位于栈区存储(auto局部变量),数组元素的默认初始值为随机值。

2.在定义同时设置初始值

        a.全部元素初始化

                保留常量表达式:初始化元素个数等于常量表达式值

#include <stdio.h>

int main()
{
        int i;

        /* 方式一:逐一元素初始化设置,最后一个元素不一定是'\0'. */
//      char buf[5] = {'a', 'b', 'c', 'd', '\0' };    
        /* 方式二:可以使用字符常量整体初始化设置,字符串常量包含结束符号'\0' */
//      char buf[5] = {"abcd"};
        /* 方式三:直接使用字符串常量设置初始值 */
        char buf[5] = "abcd";   

        for (i=0; i < 5; i++) {
                printf("%c", buf[i]);
        }
        printf("\n");
        return 0;
}

        省略常量表达式:会根据初始化元素的个数来决定数组元素的个数。

b.部分元素初始化

        不能省略常量表达式,确定的一维字符数组。在设置初始值的时候,依次初始化,未初始化元素的初始值为0值。

#include <stdio.h>

int main()
{
        int i;

        char buf[10] = {'a', 'b', 'c', 'd', '\0' };    /* buf[0] = 'a', buf[1] = 'b', buf[2] = 'c', buf[3] = 'd', } */
//      char buf[10] = {"abcd"};
//      char buf[10] = "abcd";  

        for (i=0; i < sizeof(buf); i++) {
                printf("%d", buf[i]);
        }
        printf("\n");

}

5.2 多维字符数组

        对于多维字符数组,其实质是多维数组,数组元素是字符。

5.2.1 定义语法

        存储类型 数据类型(char) 数组名称[行常量表达式][列常量表达式];

        char str[5][10];

5.2.2 元素的初始化

1.只定义,不做初始化

         全局变量和static修饰的局部变量初始值默认为0值;

         局部变量初始值为随机值

 2.全部元素初始化

char str[2][3] = {'1','2','3','4','5','6'};
char str[2][3] = {{'1','2','3'},{'4','5','6'}};
char str[2][3] = {"abc","def"};

/* 在省略行下标完成全部元素初始化 */
char str[][3] = {'1','2','3','4','5','6'};
char str[][3] = {{'1','2','3'},{'4','5','6'}};
char str[][3] = {"abc","def"};

3.部分元素初始化

        初始化数据元素的初值为设置的初始化值,未初始化数据元素的初始化值为0值。

char str[2][3] = {'1','2','3','4','5'};
char str[2][3] = {{'1','2'},{'4','5'}};
char str[2][3] = {{},{'4','5'}};
char str[2][3] = {"ab"};
char str[2][4] = {"ab","cd"};
/* 省略行下标 */
char str[][4] = {"ab","cd"};
char str[][3] = {{'1','2'},{'4','5'}};
char str[][3] = {{},{'4','5'}};

  • 23
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值