【C 语言初级】数组

在上个系列【C 语言入门】里面,已经对数组和指针定义和使用做了初步的了解。在本文章中,将深入探索:如何使用数组来处理相同类型的批量数据

数组概述

定义:数组是具有相同数据类型,并且按照一定顺序排列的一组变量的集合。

特征

  • 有序性:数组元素之间具有固定的先后顺序
  • 可索引:通过数组名和下标可以唯一地确定数组中的元素

一维数组

一维数组的定义
类型名 数组名[常量表达式]
数组的命名

数组的命名遵循《C 语言标识符的命名规则》 :

  • 标识符由字母、数字和下划线组成
  • 第一个字母不能是数字,只能是字母或下划线
  • 区分大小写字母
  • C 语言规定了一个标识符的字符个数。C 语言规定标识符的最大长度可达 255 个字符,只有前 32 个字符在编译时有效
数组的长度

在定义数组时,需要指定数组元素的个数,即数组长度。
方括号 [ ] 中的常量表达式用于表示数组元素的个数。

Example 1:使用常量表达式指定数组长度

// 定义了一个 int 型的数组,数组长度为 4,具有 4 个数组元素
int a[4];

// 数组下标是从 0 开始
// 注意: 依据上面的定义,数组 a 仅有 4 个数组元素,
//      分别为:a[0]、 a[1]、 a[2]、 a[3],并不存在数组元素 a[4] 
a[0] = 0;   /* 将数组 a 的 第 0 个 数组元素赋值为 0 */
a[1] = 1;   /* 将数组 a 的 第 1 个 数组元素赋值为 1 */
a[2] = 2;   /* 将数组 a 的 第 2 个 数组元素赋值为 2 */
a[3] = 3;   /* 将数组 a 的 第 3 个 数组元素赋值为 3 */
a[4] = 4;   /* 错误! */

Example 2 :使用初始化列表指定数组长度。

// 通过对全部数组元素赋初值来指定数组长度,此时,可以不指定数组长度。
char g_A_Array[] = {0, 1, 2, 3, 4, 5};

printf("g_A_Array's length is %d\r\n", sizeof(g_A_Array));

运行结果
这里写图片描述

数组长度不允许动态定义

C 语言不允许对数组的长度做动态定义。即:常量表达式可以包括常量和符号常量,但不能包含变量。

  • 常量表达式可以包含常量
int a[4];       // 正确
int b[1 + 3];   // 正确
  • 常量表达式可以包含符号常量
#define ArraySize   4
int c[ArraySize];   // 正确
  • 常量表达式不可以包含变量
int n;
scanf("%d", &n);
int a[n];   // 错误

NOTE
如果在被调用的函数(不包含主函数)中定义数组,数组的长度可以是变量或非常量表达式,此数组称为“可变长数组,variable-length arrays(VLAs)”

Example:VLAs

/* 数组 a 的数组长度表达式为在调用 func 函数时形参 n 从实参得到的值
 * 允许在每次调用 func 函数时,n 有不同的值
 * 称数组 a 为 可变长数组,variable-length arrays (VLAs)
 * VLAs 为 C99 标准中新增的一项
 * 
 * 值得注意的是,Visual Studio 不支持 VLAs
 * 若在 Visual Studio 中使用 VLAs,会报 “error C2123:表达式的计算结果不是常量” 的错误
 */
void func(int n)
{
    int a[n];  /*正确*/
}
 /* 若 a 数组为静态存储方式(static), 则不能用 VLAs,即 funb 的写法是错误的 */
void funb(int n)
{
    static int a[n];  /*错误*/
}
一维数组元素的引用

NOTE:只能引用数组元素,而不能一次整体调用整个数组的全部元素的值。

引用数组元素的形式

数组名[下标]

Example 1 :a[0] 表示数组 a 中序号为 0 的元素。

Example 2:依次给数组 a 的元素赋值,再倒序输出数组 a 的元素。

int main()
{
    int a[10];   // 创建数组
    int i;

    for (i = 0; i < 10; i++)
    {
        a[i] = i;    // 数组元素赋值
    }

    for (i = 9; i >= 0; i--)
    {
        printf("a[%d] = %d\r\n", i, a[i]);
    }

    return 0;
}

输出结果:
这里写图片描述
NOTE:数组元素的下标由 0 开始。即最后一个数组元素的下标为数组长度减 1。

一维数组的初始化

一维数组的初始化:在定义数组的同时,给各数组元素赋值,这称为数组的初始化。

  • 在定义数组时对全部数组元素进行赋初值
    Example
// 花括号 {} 内的数据称为 “初始化列表”
int a[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};  
  • 只给一部分数组元素赋初值
    Example:仅给 a 数组的前面 5 个元素赋初值
int main()
{
    int a[10] = { 0, 1, 2, 3, 4 };
    int i;

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

运行结果
这里写图片描述

  • 对一维数组中的全部元素值赋值为 0
    方式 1:
a[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

方式 2:

a[10] = {0};
  • 通过对全部数组元素赋初值来确定数组的元素个数,从而不指定数组长度
    Example
int main()
{
    int a[] = { 0, 1, 2, 3, 4 };  // 数组定义并初始化
    int i, aLength;

    aLength = sizeof(a) / sizeof(int);  // 获取数组长度
    printf("a's Length = %d\r\n", aLength);

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

输出结果
这里写图片描述

一维数组的经典应用:冒泡排序
#include <stdlib.h>

int main()
{
    int a[10];
    int i,j, temp;

    printf("Original a:\r\n");
    for (i = 0; i < 10; i++)
    {
        a[i] = rand();  // 生成随机数
        printf("a[%d] = %d\r\n", i, a[i]);
    }

    // 排序过程
    for (i = 0; i < 10 - 1; i++)
    {
        for (j = 0; j < 10 - 1 - i; j++)
        {
            if (a[j + 1] < a[j])
            {
                temp = a[j];
                a[j] = a[j + 1];
                a[j + 1] = temp;
            }
        }
    }

    printf("After rank:\r\n");
    for (i = 0; i < 10; i++)
    {
        printf("a[%d] = %d\r\n", i, a[i]);
    }

    return 0;
}

输出结果
这里写图片描述

二维数组

二维数组常称为矩阵(matrix)。

NOTE

  • 行(column)
  • 列(row)
二维数组的定义
类型名 数组名[常量表达式 col][常量表达式 row]

Example

a[3][4];    // 定义 3 行 4 列的数组
b[4][3];    // 定义 4 行 3 列的数组 

NOTE
C 语言中,二维数组中元素排列的顺序是按行排列,即在内存中,先顺序存放第 1 行的元素,再存放第 2 行的元素。同时,各个元素都是连续存放的。

Example:使用指针查看二维数组 a 的存放情况。

int main()
{
    int a[3][4];
    int i,j;
    int *addrOfa = &a[0][0];

    printf("a:\r\n");
    for (i = 0; i < 3; i++)
    {
        for (j = 0; j < 4; j++)
        {
            a[i][j] = 4*i + j;
            printf("a[%d][%d] = %d ,", i, j, a[i][j]);
        }
        printf("\r\n");
    }

    printf("a's Base Address: %x\r\n", addrOfa);
    for (i = 0; i < (3 * 4); i++)
    {
        printf("Addr %x = %d\r\n", (addrOfa + i), *(addrOfa+i));
    }
    getchar();
    return 0;
}

运行结果:
这里写图片描述
通过运行结果,可得知:

  • 在内存中,先顺序存放第 1 行的元素,再存放第 2 行的元素。
  • 各个元素都是连续存放的。
二维数组元素的引用

二维数组元素的引用形式:

数组名[下标 col][下标 row]

Example

a[0][1] 表示数组 a 中第 0 行第 1 列的元素。
a[8][9] 表示数组 a 中第 8 行第 9 列的元素。  

NOTE
二维数组的下标均从 0 开始。

二维数组的初始化
  • 分行给二维数组初始化
  • 将所有数据写在一个花括号内,按数组元素在内存中的排序顺序对各个元素赋初值
  • 对部分元素进行赋初值

Example

    int a[3][4] = { {0, 1, 2, 3},
                    {4, 5, 6, 7},
                    {8, 9, 10, 11} };
二维数组的实例

Example:行列置换。
源数组:

 aArray = {{1, 2, 3},
           {4, 5, 6}}

目标数组:

 bArray = {{1, 4},
           {2, 5},
           {3, 6}}

实现代码:

#include "stdio.h"
#define aLine   2
#define aColumn 3

int a[aLine][aColumn] = { { 1, 2, 3 },
                          { 4, 5, 6 } };
int b[aColumn][aLine];

static void OutputA(void)
{
    int i, j;

    printf("a[%d][%d]={\r\n", aLine, aColumn);
    for (i = 0; i < aLine; i++)
    {
        printf("{");
        for (j = 0; j < aColumn; j++)
        {
            printf("%d", a[i][j]);
            if (j != (aColumn - 1)){
                printf(", ");
            }
        }
        printf("}");

        if (i != (aLine - 1)){
            printf(", ");
        }
        printf("\r\n");
    }
    printf("}\r\n");
}

static void OutputB(void)
{
    int i, j;

    printf("b[%d][%d]={\r\n",aColumn , aLine);
    for (i = 0; i < aColumn; i++)
    {
        printf("{");
        for (j = 0; j <aLine; j++)
        {
            printf("%d", b[i][j]);
            if (j != (aLine - 1)) {
                printf(", ");
            }
        }
        printf("}");

        if (i != (aColumn - 1)) {
            printf(", ");
        }
        printf("\r\n");
    }
    printf("}\r\n");
}

int main(void)
{
    int i, j;
    OutputA();

    for (i = 0; i < aLine; i++)
    {
        for (j = 0; j < aColumn; j++)
        {
            b[j][i] = a[i][j];
        }
    }
    OutputB();
}

输出结果:
这里写图片描述

字符数组

字符型数据是以字符的 ASCII 码形式存放在内存单元中的。C 语言中没有字符串类型,字符串是存放在字符型数组中的。

字符数组的定义

字符数组:用来存放字符数据的数组,字符数组中的一个元素存放一个字符。

char 数组名[数组长度]
字符数组的初始化

使用初始化列表对字符数组进行初始化,把各个字符依次赋给数组中的各个元素。
Example:把 10 个字符依次赋给 a[0] ~ a[10]。

char a[10] = {'I', ' ', 'a', 'm', ' ', 'h', 'a', 'p', 'p', 'y'};

NOTE
如果在定义字符数组时不进行初始化,则数组中的各个元素的值是不可预料的。

  • 若花括号 {} 中提供的初值个数大于数组长度,则出现语法错误
  • 如初值个数小于数组长度,则只将这些字符赋给数组中前面的元素,其余的元素自动定为空字符,即 '\0'
    Example:打印字符数组 a 元素的字符值和整型值。
int main(void)
{
    char a[10] = { 'I', ' ', 'a', 'm' };
    int i;

    for (i = 0; i < 10; i++)
    {
        printf("a[%d] = '%c'(char), %3d(int)\r\n", i, a[i], a[i]);
    }
    return 0;
}

输出结果
这里写图片描述

  • 若提供的初值个数与预期的数组长度相同,则可省略数组长度,系统会自动根据初值个数确定数组长度。
    Example
char a[ ] = {'I', ' ', 'a', 'm', ' ', 'h', 'a', 'p', 'p', 'y'};
字符数组的元素引用

可以通过引用字符数组的一个元素,得到一个字符。
Example:打印已知的字符串。
Example:打印字符数组 a 元素的字符值和整型值。

int main(void)
{
    char a[10] = { 'I', ' ', 'a', 'm' };
    int i;

    printf("a[10] = \"%s\"\r\n", a);
    for (i = 0; i < 10; i++)
    {
        printf("a[%d] = '%c'(char), %3d(int)\r\n", i, a[i], a[i]);
    }
    getchar();
}

输出结果
这里写图片描述
在输出结果中,能发现 使用 %s 进行打印时,a 仅输出了 4个字符:‘I’, ‘ ’, ‘a’, ‘m’。这是因为 ‘\0’ (整型值为 0)是 C 语言规定的 “字符串结束标记”,也就是说在遇到字符 ‘\0’ 时,表示字符串结束,把它之前的字符组合成一个字符串。C 系统中,在用字符数组存储字符串常量时会自动加一个 ‘\0’ 作为结束字符。
在执行 printf 函数时,没输出一个字符检测一次,看下一个字符是否为 ‘\0’, 遇到 ‘\0’ 就停止输出。因此,上例子,仅输出了 I am

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值