美团笔试题解析:C语言中的柔性数组

来源:微信公众号(开点工作室,ID:kaidiancs)

美团2016招聘笔试中有这样一道C语言题目:


开发C代码时,经常见到如下类型的结构体定义:

typedef struct list_t {

struct list_t *next;

struct list_t *prev;

char data[0];

} list_t;

最后一行char data[0]; 的作用是()。

A.方便管理内存缓冲区                   B.减少内存碎片化

C.标识结构体结束                          D.没有作用


该题目考查的是C语言中柔性数组的知识。 在C语言中,将结构中的最后一个成员定义为数组并将大小定义为0是一种特殊是用法,这种声明可以在C语言中巧妙地实现数组扩展。


在C99标准中,结构中的最后一个元素允许是未知大小的数组,称为柔性数组(flexible array)成员(也称为伸缩性数组成员),但结构中的柔性数组成员前面必须至少一个其他成员。柔性数组成员允许结构中包含一个大小可变的数组。柔性数组成员只作为一个符号地址存在,而且必须是结构体的最后一个成员,sizeof 返回的这种结构大小不包括柔性数组的内存。柔性数组成员不仅可以用于字符数组,还可以是元素为其它类型的数组。包含柔性数组成员的结构用malloc 函数进行内存的动态分配,且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。请看下面程序。


#include <stdio.h>

#include <string.h>

#include <stdlib.h>

typedef struct list_t {

struct list_t *next;

struct list_t *prev;

char data[0];

} list_t;

int main(int argc, char*argv[])

{  char buf[] = "This is a string.", *p;

   list_t *head;

printf("sizeof structlist_t = %d\n", sizeof( list_t ) );

   head = ( list_t * )malloc( sizeof( list_t )+ sizeof( buf )+1 );

   p = head->data;

printf("addr of list_tis %p. addr of data is %p.\n", head, p );

strcpy(head->data, buf);

printf("In struct sizeofdata = %d\n", sizeof( head->data ));

printf("In struct data =%s\n", head->data );

free( head );

return 0;

}

运行程序可能得到如下结果:

sizeof struct list_t = 8

addr of list_t is 003B1068.addr of data is 003B1070.

In struct sizeof data = 0

In struct data = This is astring.

由此可以看出,申请空间可以使用的语句是:

( list_t * )malloc( sizeof( list_t ) + 数组大小)


由于数组data没有元素,该数组在该结构分配时不占用空间,所以sizeof(struct list_t)=8。malloc申请的是26个字节的连续空间,返回一个指针指向这26个字节,强制转换成list_t *时,前面8个字节是list_t结构的两个成员next和prev,data的地址紧跟在结构之后。显然使用柔性数组可以按照实际需要只进行一次内存分配,从而减少了内存碎片。


请分析一下下面的程序,看一看如何使用柔性数组。

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#define NUM 3

typedef struct list_t {

struct list_t *next;

struct list_t *prev;

char data[0];    // 柔性数组

} list_t;

int main(int argc, char* argv[])

{   char buf[][20] ={"This is a string.", "abc", "123456789"};

     list_t * head, *p;

int i;

printf("sizeof list_t = %d\n", sizeof( list_t ) );

head = ( list_t * )malloc( sizeof( list_t ) );

head->next = NULL;

head->prev = NULL;                             // 可不使用

 for ( i=0; i<NUM; i++ )                            // 反向建立单链表

     {   p = ( list_t * )malloc( sizeof( list_t)+strlen(buf[i])+1 );

strcpy( p->data, buf[i] );

printf("p=%p, p->data=%p, size *p=%d, size data=%d\n",

                            p,p->data, sizeof(*p), sizeof(p->data));

printf(" p-data=%s\n", p->data);

p->next = head->next;

head->next = p;

}

i = 1;

p = head->next;

while ( p!=NULL )                                     //输出链表中的结点

{printf("List %d: %p, %2d, %s\n", i++, p,strlen(p->data), p->data);

p = p->next;

 }

while ( head!=NULL )                           // 释放链表

{p = head->next;

free( head );

head = p;

    }

return 0;

}


分析一下下面的程序,看一看在结构中使用指针该如何实现同样的功能。

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#define NUM 3

typedef struct list_t {

struct list_t *next;

struct list_t *prev;

    char * data;                                  //使用指针

} list_t;

int main(int argc, char* argv[])

{    char buf[][20] ={"This is a string.", "abc", "123456789"};

     list_t * head, *p;

int i;

printf("sizeof list_t = %d\n", sizeof( list_t ) );

head = ( list_t * )malloc( sizeof( list_t ) );

head->next = NULL;

     head->prev =NULL;                  //可不使用

     for ( i=0; i<NUM; i++)                  // 反向建立单链表

{  p = ( list_t * )malloc(sizeof( list_t ) );

                            p->data= ( char * )malloc( strlen(buf[i])+1 ); // 分别申请空间

strcpy( p->data, buf[i] );

printf("p=%p, p->data=%p, size *p=%d, size data=%d\n",

                            p,p->data, sizeof(*p), sizeof(p->data));

printf(" p-data=%s\n", p->data);

p->next = head->next;

head->next = p;

     }

     i = 1;

     p = head->next;

while ( p!=NULL )                                     //输出链表中的结点

{  printf("List %d: %p,%2d, %s\n", i++, p, strlen(p->data), p->data);

        p = p->next;

     }

     p = head->next;

while ( p!=NULL )                                  // 释放链表

{  list_t *q = p->next;

        free( p->data );                       // 分别释放空间

free( p );

        p = q;

    }

free( head );

return 0;

}

对照上面的两个程序可以看出,使用柔性数组可以减少内存碎片。所以答案是B。

全部评论
妙不可言
点赞 回复 分享
发布于 2024-04-10 18:25 辽宁

相关推荐

04-17 18:32
门头沟学院 Java
野猪不是猪🐗:他跟你一个学校,你要是进来之后待遇比他好,他受得了?
点赞 评论 收藏
分享
评论
2
7
分享

创作者周榜

更多
牛客网
牛客企业服务