先看负索引的示例:
#include <stdio.h>
int main(void)
{
int array[] = {1, 2, 3, 4, 5, 6};
int *ip = &array[-1];
int sum = 0;
int i = 1;
for(; i < 7; i++)
{
sum += ip[i];
}
printf("%d/n", sum);
return 0;
}
运行结果:21
需要注意的是i 的初始值为1 而不是0。我们知道对于一个数组array,array[i]可以写作*(array + i)。那么array[-1]就是*(array - 1)。
这样做虽不安全却完全合法。以上代码中的int *ip = &array[-1];就是int *ip = &(*(array - 1))。
也就是int *ip = array - 1;了。因此要取到array[0]也就*(array + 0)的值就必须是ip[1]也就是
*(ip + 1)也就是*(array - 1 + 1)了。因此所谓的负索引不过是使用了指针运算的小技巧罢了。
再看0 长数组的示例:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define ADD_LEN 20
typedef struct Test
{
char name[100];
char array[0];
}Test;
int main(void)
{
Test *t = NULL;
printf("sizeof(Test): %d/n", sizeof(Test));
t = (Test*)malloc(sizeof(Test) + ADD_LEN);
if(t == NULL)
{
return -1;
} strcpy(t->name, "
Jackson");
strcpy(t->array, "Michael");
printf("%s %s/n", t->name, t->array);
free(t);
return 0;
}
通过结果看以看出,在结构体中增加了一个零长数组并没有增大结构体的大小。在申请
空间的时候有意增加了额外的ADD_LEN 大小的空间。这样就可以实现变长结构体了。而
最后的零长数组array 恰好指向了这部分额外空间的首地址。在新的C99 标准中有个柔性数
组的说法,它允许在结构体的最后定义个不加长度的数组(在它上面要存在其它的域)。这
与0 长数组的的特性一致。例如可以将以上的Test 结构体写作:
struct Test
{
char name[100];
char array[];
}
至于这么做有什么大用,那就要发挥您的创造力了。值得一提的是在linux 内核源码中
存在不少这样的用法。
以下是我自己的测试,用到了结构体数组特殊的赋值方式。
#include <stdio.h>
struct new_arr
{
const char *test;
int t;
char a[0];
};
struct new_arr arr[10] =
{
[0].test = "hahah",
[0].t=9,
[3].t=1001,
[1].t=100
};
int main()
{
printf("1.t=%d/n",arr[1].t);
struct new_arr *t = &arr[0];
arr[0].a[1] = 'c';
printf("1.t=%c/n",t->a[1]);
return 1;
}