zhyDaDa的个人站点

目录
定义数组
语法
本质和特征
数组的特点
数组的单元、下标
有效的下标范围
数组的集成初始化
定义
写法注意
集成初始化时的定位
数组操作
数组长度
数组赋值
数组的应用
搜索
素数判断
二维数组
内存中的排布
遍历
初始化


定义数组

语法

语法: <类型> 变量名称[元素数量]
+ 类型是指数组中每个元素的类型
+ 元素数量必须是整数
+ 元素数量应当在编译时就是确定的字面量, 在C99之后可以是变量

本质和特征

数组的本质是一个容器 (放东西的东西)

就现代编程语言而言, 评判其能力大小的一项标准, 就是该语言提供容器的能力

数组的特点

  • 所有元素都具有相同的数据类型
  • 数组的大小一旦创建就不得改变
  • 在内存中, 数组中的元素是紧密、连续、依次排列

数组的单元、下标

数组的每个单元就是数组类型的一个变量
使用数组时放在[]中的数字称为 下标 or 索引
下标是从0开始计数的

虽然数组并不是C语言发明的, 但下标从0开始计数是从C语言开始的
重要的原因是, C语言的编译器可以简化很多

有效的下标范围

编译器和运行环境不会检查数组的下标是否越界(无论读写)
可能会造成报错/警告: segmentation fault

int a[0]
长度为0的数组可以存在, 但毫无用处, 因为不存在有效的下标范围

数组的集成初始化

定义

int a[] = {1,22,333}这种写法被称为 数组的集成初始化
+ 直接用大括号给出数组中所有元素的初始值
+ 不需要给出数组的大小, 编译器会自动计数

写法注意

注意: 如果是这种写法
int a[5]={2,3};
其效果等同于
int a[]={2,3,0,0,0};

集成初始化时的定位

C99中, 允许用[n]在初始化数据中给出定位
没有定位的数据接在前面的位置后面
其他位置填补零
如果不给出数组大小, 编译器会把涉及到的最大的位置定为数组的长度
这种写法特变适合初始数据稀疏的数组

int a[8] = {
  [0]=2, [2]=3, 6,
};

上面的写法等同于
int a[8] = {2,0,3,6,0,0,0,0};

int a[] = {[3] = 1, 2, 3, [5] = 6, 7, 8};
等同于 “`int a[] = {0, 0, 0, 1, 2, 6, 7, 8};

数组操作

数组长度

int a[]={1,2,3,};
int length_a = sizeof(a)/sizeof(a[0]); 

这个小技巧对于所有数组都成立

有趣的是在定义数组时, 最后多出来的那个,
这是为了后来人不用再打上逗号而准备的, 对程序来说毫无影响
这么做可以显得自己读过70/80年代的编程书

数组赋值

int a[]={1,2,3,};
int b[]=a;

这么做无法将数组a赋值给数组b
唯一方法是遍历数组

数组的应用

搜索

在一个数组中找出要找的数字

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int search(int key, int a[], int length);

int main()
{
    int a[] = {2, 4, 6, 82, 455, 1, 10, 54, 4, 3, 5, 17, 14, 32, 8};
    int x;
    int loc;
    printf("请输入一个数字: ");
    scanf("%d", &x);
    loc = search(x, a, sizeof(a) / sizeof(a[0]));
    if (loc != -1)
    {
        printf("%d在第%d个位置上\n", x, loc);
    }
    else
    {
        printf("%d不存在\n", x);
    }

    return 0;
}

int search(int key, int a[], int length)
{
    int ret = -1;
    for (int i = 0; i < length; i++)
    {
        if (a[i] == key)
        {
            ret = i;
            break;
        }
    }
    return ret;
}

这里注意: 数组作为函数的参数时, 往往要求用另一个参数来传入数组的大小
这是因为当数组作为参数时:
+ 不能再利用sizeof来计算数组的元素个数
+ 也就无法计算数组的大小

素数判断

如果使用素数去判断数字是否是素数, 时间复杂度最低
但仅仅在构造素数表的时候有用

以下代码用于找出前100个素数

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int isPrime(int x, int knownPrimes[], int length);

int main()
{
    const int number = 100;
    int prime[number];
    prime[0] = 2;
    int count = 1;
    int i = 3;
    while (count < number)
    {
        if (isPrime(i, prime, count))
        {
            prime[count++] = i;
        }
        i++;
    }

    for (i = 0; i < number; i++)
    {
        printf("%d", prime[i]);
        if ((i + 1) % 5)
            printf("\t");
        else
            printf("\n");
    }

    return 0;
}

int isPrime(int x, int knownPrimes[], int length)
{
    int ret = 1;
    for (int i = 0; i < length; i++)
    {
        if (x % knownPrimes[i] == 0)
        {
            ret = 0;
            break;
        }
    }
    return ret;
}

如果说想构造n以内的素数表, 可以采用挖空法
即, 挖掉所有倍数
以下求出25以内的素数

int main()
{
    const int number = 25;
    int isPrime[number];
    for (int i = 0; i < number; i++)
    {
        isPrime[i] = 1;
    }

    for (int x = 2; x < number; x++)
    {
        if (isPrime[x])
        {
            for (int i = 2; i * x < number; i++)
            {
                isPrime[i * x] = 0;
            }
        }
    }
    for (int i = 2; i < number; i++)
    {
        if (isPrime[i])
        {
            printf("%d\t", i);
        }
    }
    printf("\n");

    return 0;
}

要多多考虑时间复杂度, 有时候不能被人的思维所局限

二维数组

int a[3][5]通常被理解为一个3行5列的矩阵

内存中的排布

| | | | | |
| :—–: | :—–: | :—–: | :—–: | :—–: |
| a[0][0] | a[0][1] | a[0][2] | a[0][3] | a[0][4] |
| a[1][0] | a[1][1] | a[1][2] | a[1][3] | a[1][4] |
| a[2][0] | a[2][1] | a[2][2] | a[2][3] | a[2][4] |

遍历

for (i = 0; i < 3; i++)
{
    for (j = 0; j < 3; j++)
    {
        a[i][j] = i * j;
    }
}

平时数学上的 $a[i,j]$ 表示坐标系中的一个点
但在C语言中, 由于,是一个运算符
a[i,j]a[j]是等价的, 这显然不是正确的表达二维数组的方式

初始化

int a[][5] = {
    {0, 1, 2, 3, 4},
    {2, 3, 4, 5, 6},
};

列数必须给出, 行数可以省略
其他一些细节和一位数组一致

其实可以用一长串数字初始化
因为这与内存中的结构实质上一致
为了人类读者阅读方便, 还是用{}来写较好

Avatar photo
我是 zhyDaDa

前端/UI/交互/独立游戏/JPOP/电吉他/游戏配乐/网球/纸牌魔术

发表回复