变长数组



#include <stdio.h>

typedef struct
{
	int d;
	int a[];
}A;


int main()
{
	printf("%d\n", sizeof(A));

	A *a;
	int d = 10;
	a = malloc(sizeof(*a) + 3 * sizeof(int));
	//memcpy(a->a, &d, sizeof(int)); 
	*(a->a + 1) = d;


	printf("%d\n",*(a->a + 1));

	return 0;
}
上面是测试代码。即自己申请空间供struct里面的变长数组使用。

以下内容为转载:


1. 变长数组(Arrays of Variable Length)或者(variable-length array,VLA)

c99标准的一个特性。c89的一个扩展(对gcc来说)
变长数组和变量都分配在栈上,普通变量的内存分配是按照定义顺序, 先定义的先分配, 但是变长数组不同,它是在最后分配的, 因此总在栈的最下面。变长数组在效率上比在堆上malloc/free好一点,它不需要显式回收,因此不会引起内存泄漏。(The storage is allocated at the point of declaration and deallocated when the brace-level is exited)
变长数组需要编译器的支持,gcc对 变长数组(Arrays of Variable Length)有支持。
对变长数组进行sizeof操作得到的是真正的数组大小。

2. 灵活数组域(flexible array member)
c99标准的一个特性,使得可以声明一种特殊的结构,这种结构中的数组是可变长度的,我是在redis的源代码中第一次见到:
C代码   收藏代码
  1. struct sdshdr {  
  2.     int len;  
  3.     long free;  
  4.     char buf[];  
  5. };  
  6.   
  7. char *aName = "Michel Jackson";  
  8. struct sdshdr *nm = malloc(sizeof(*nm) + strlen(aName) + 1);  
  9. strcpy(nm->buf, aName);   
  10. 。。。  

也就是说,最后一个指针成员变量所指向的数组空间是变长的。
sizeof计算结构体的大小时,不会计算变长数组的大小,因此上面的结构体实际上是len和free两个成员组成的结构体大小。
灵活数组域规定,可变数组成员变量必须在结构体的最后声明。

灵活数组域的一个优点是不用两次分配内存,也就减少了内存碎片。(不然的话,nm初始化分配一次,buf分配一次,free也要两次,麻烦又容易出错)同时施放内存也不用两次释放,一次搞定。

3. 给结构体分配内存的方法
对于结构体,最后这样分配内存
C代码   收藏代码
  1. struct T *p = malloc(sizeof *p);  

而不是
C代码   收藏代码
  1. struct T *p = malloc(sizeof (struct T));  

这样对所有类型的指针(除了void类型)都可以完成分配,
这种方式的好处是:如果p的类型换成另外一种结构了,malloc的地方不用修改。
在《C语言接口与实现》第5章看到的这个技巧。

4. NULL 指针的问题
char *str = NULL
strlen(str); // 会出现bus error

不过sizeof(str)还是正确的,即使str是NULL,这也说明sizeof是根据类型计算大小的。

5. 关于void
不同类型的指针间引用的转换
int i = 7;
void *p = &i;
printf("i = %d\n", * ((int *)p); // 先把void指针转化成int指针,然后对转化的指针解引用操作
有void类型的指针变量,而没有void类型的一般变量

如果函数无返回指,应该指定返回类型是void的,不指定的话缺省返回的是int

5. 关于size_t
malloc等函数中分配内存大小的参数是size_t类型的,这是一个无符号的整数类型,但是有符合的整数也能传递,编译时不会给出警告:
C代码   收藏代码
  1. int n = -1;  
  2. p = malloc(n);  


打印size_t数据:
size_t sz = 999;
printf("size: %zu\n", sz);

6. 数组指针
数组指针是一种指针,这个指针指向一个数组。
C代码   收藏代码
  1. #include <stdio.h>  
  2.   
  3. typedef int (*x)[10] ;  
  4. int main() {  
  5.     int arr[10] = {1,2,3,4,5,6,7,8,9,0};  
  6.     int (*p2)[10];  
  7.     p2 = &arr;  
  8.     x p3 = &arr;  
  9.   
  10.     printf("ptr sz: %zu, %zu\n"sizeof(p2), sizeof(p3));  
  11.     printf("arr ptr sz: %zu, %zu, %zu\n"sizeof(arr), sizeof(*p2), sizeof(*p3));  
  12.     printf(" arr = %p, &arr = %p\n", arr, &arr);  
  13.     printf("p2+1 = %p, p3+1 = %p\n\n", p2+1, p3+1);  
  14.   
  15.     for(int i=0; i<10; ++i) {  
  16.         printf("%d, %d, %d; ", arr[i], (*p2)[i], (*p3)[i]);  
  17.     }  
  18.     printf("\n");  
  19.     return 0;  
  20. }  

注意数组arr的指和&arr的值相同,但含义不同,至少类型不同。
(to be continue)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值