原地址
作者:(m.p)
移植c接口时,免不了与数组打交道,可能为.尽管d与c的数组实现不一样,但基本构造块是一样的.因而,只要记得区别,就容易兼容.
d中用c接口时,要转换c代码至d.直接用c,从中受益.移植时尽量保持原样.然后继续看声明/初化及如何转换.还要讲多维数组,d数组分析,从c函数中传递数组,及如何利用垃集.现在c的都少了.
声明1维数组:

int c0[3];

栈上连续分配,c0有可能初化.全局变量/静态本地变量初化为0.如definit.c:

#include <stdio.h>
// global (can also be declared static)
int c1[3];
void main(int argc, char** argv)
{
    static int c2[3];       // static local
    int c3[3];              // non-static local
    printf("one: %i %i %i\n", c1[0], c1[1], c1[2]);
    printf("two: %i %i %i\n", c2[0], c2[1], c2[2]);
    printf("three: %i %i %i\n", c3[0], c3[1], c3[2]);
}

打印:

one: 0 0 0
two: 0 0 0
three: -1 8 0

等价的d如下:

int[3] d0;

曾经可以用c风格数组,不过现在已弃用了,现在会报编译错误.

Error: instead of C-style syntax, use D-style int[3] d0

主要是为了风格一致性.d主要是从右到左读,与c风格不一样.考虑如下指针声明:

int* p0, p1;

d中都是指针,而c则是p0为指针,p1为整.d中都是类型在左,符号在右.考虑:

int d1[3], d2[3];
int[3] d4, d5;

使c代码非法,提高代码的一致性.提高了可读性.
d0,c0的另一个区别是d0始终会默认初化为预定义的类型.初值.数组初化为元素的初值.
转换cd时,默认初化可能是个陷阱.考虑:

// static variables are default initialized to 0 in C
static float vertex[3];
some_func_that_expects_inited_vert(vertex);

直接翻译为d会出错,因为float.init == float.nan,而不是0.转换c时,一定要小心,哪个c变量未显式初化.哪个期望初化,及d中基本类型的默认初值.否则,真是掉坑里了.可用=空来禁止d的默认初化.
这对读值前加载值的数组及初值无用(仅是未初化标记)时,很有用.

float[16] matrix = void;
setIdentity(matrix);

默认初化,只是为了区别未初化值.常见错误是初值为float.nan,而初值0xFF(无效变长码).这样的值都是未初化的标志,初值一般没用.是整/极打破规则,因为任意值都是有意义的.不能说这是未初化.因而将0/假作为默认值,浮/符则要尽快显式初化.

显式初化数组

c方式:

int ci0[3] = {0, 1, 2};  // [0, 1, 2]
int ci1[3] = {1};        // [1, 0, 0]
int ci2[]  = {0, 1, 2};  // [0, 1, 2]
int ci3[3] = {[2] = 2, [0] = 1}; // [1, 0, 2]
int ci4[]  = {[2] = 2, [0] = 1}; // [1, 0, 2]

可见:
元素用初化列表元素初化.不够则补0.省略长度,则用初化列表的长度.用[索引]=值来指定相应位值.没有索引的,初化为0.省略长度时,用最大索引作为长度基.其余为0.假定初化器比数组短.而gcc如果更长的话则初化前面的,忽略后面的.并警告.可以混合指定与非指定.

// [0, 1, 0, 5, 0, 0, 0, 8, 44]
int ci5[] = {0, 1, [3] = 5, [7] = 8, 44};

注意,有的c编译器不支持c99.转换为d,小心:

int[3] wrong = {0, 1, 2};
int[3] right = [0, 1, 2];

d不是用{}初化,而是用[].产生错误:

Error: a struct is not a valid initializer for a int[3]

d中用{}来初化.注意别与构字面量混淆了.
下个惊奇:

// int ci1[3] = {1};
int[3] di1 = [1];

产生编译错误:

Error: mismatched array lengths, 3 and 1

长度不匹配.看ci2.

// int ci2[] = {0, 1, 2};
int[] di2 = [0, 1, 2];

c中,[数]与[]是没啥区别的.而d中作了区分.如果直接复制到d,就会出问题.d区分为静态/动态数组.而c始终是固定数组.后者在d中为动态数组/切片.静态数组的初化器必须与数组长度相等.d不允许小于数组长度的初化器.动态数组可伸缩大小.也可以不初化.而cint foo[]这样是不行的.只有当初化器出现时,才可省略长度.可见c数组主要就是静态数组.

// gcc says "缺少数组大小'illegalC'"
// int illegalC[]
int[] legalD;
legalD ~= 10;

legalD为空数组,用~=附加.动态数组显式初化时分配内存.如无初化器,一般在添加第1个元素时分配,默认用垃集.尽管编译器可决定在栈上分配是安全的,来优化.至于分配策略,看需要.参见d数组文章
@无垃集时,区分静态动态数组就比较重要了.

@nogc void main()
{
    int[] di2 = [0, 1, 2];
}

此时,动态数组不管用了.

Error: array literal in @nogc function D main may cause a GC allocation

静态数组,则在上分配.而c程序员,则糊涂了.其实就是c数组静态数组,而d中必须显式指定大小.见垃集不是敌人
总之.c指定数组初化器(c99),d也支持,只是语法不一样.

// [0, 1, 0, 5, 0, 0, 0, 8, 44]
// int ci5[] = {0, 1, [3] = 5, [7] = 8, 44};
int[] di5 = [0, 1, 3:5, 7:8, 44]
int[9] di6 = [0, 1, 3:5, 7:8, 44];

看起来就像字典,但却是数组.对动态/静态数组都适用.

要点
1 d静态/动态数组,c只有静态数组.
2 在栈上分配静态,垃集堆上分配动态数组.
3 未初化静态数组初化为元素类型.初值.
4 可显式初化动态数组,并按初化器长度作为长度.
5 不能在@无垃集域中显式初化动态数组.
6 未初化动态数组是空的.

还可以用std.array最近添加的staticArray函数来转换类似int ci2[] = {0, 1, 2};c声明.@无垃集的.