问题
Can we declare a structure element of variable length?
The condition is as follows:
typedef struct
{
uint8_t No_Of_Employees;
uint8_t Employee_Names[No_Of_Employees][15];
}st_employees;
回答1:
If coding in C99 or C11, you might want to use flexible array members (you don't give an explicit dimension, but you should have a convention about it at runtime in your head).
typedef struct {
unsigned No_Of_Employees;
char* Employee_Names[]; // conventionally with No_of_Employees slots
}st_employees;
As for any array, each slot of a flexible array member has a fixed size. I'm using a pointer (e.g. 8 bytes on my Linux/x86-64 machine).
(In old compilers before the C99 standards, you might try give a 0
dimension like char* Employee_Names[0];
even if it is against the standard)
Then you would allocate such a structure using e.g.
st_employees* make_employees(unsigned n) {
st_employees* s = malloc(sizeof(s_employees)+n*sizeof(char*));
if (!s) { perror("malloc make_employees"); exit(EXIT_FAILURE); };
s->No_of_Employees = n;
for (unsigned i=0; i<n; i++) s->Employe_Names[i] = NULL;
return s;
}
and you might use (with strdup(3) duplicating a string in the heap) it like
st_employees* p = make_employees(3);
p->Employee_Names[0] = strdup("John");
p->Employee_Names[1] = strdup("Elizabeth");
p->Employee_Names[2] = strdup("Brian Kernighan");
You'll need a void destroy_employee(st_employee*e)
function (left as an exercise to the reader). It probably should loop on i
to free
every e->Employee_Names[i]
, then free(e);
...
Don't forget to document the conventions about memory usage (who is in charge of calling malloc
and free
). Read more about C dynamic memory allocation (and be scared of memory fragmentation and buffer overflows and any other undefined behavior).
If using a GCC older than GCC 5 be sure to compile with gcc -std=c99 -Wall
since the default standard for old GCC 4 compilers is C89. For newer compilers, ask for all warnings and more of them, e.g. gcc -Wall -Wextra
...
回答2:
TL;DR answer - No, you cannot.
To elaborate, let me quote C11
, chapter §6.7.2.1, Structure and union specifiers
(emphasis mine)
A member of a structure or union may have any complete object type other than a variably modified type. [...]
and, a VLA is a variably modified type.
However, quoting from the same standard, regarding the flexible array member
As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member. [...]
So, you can do something like
typedef struct
{
uint8_t No_Of_Employees;
uint8_t* Employee_Names[];
}st_employees;
and later, you can allocate memory dynamically at the runtime to Employee_Names
(and Employee_Names[i]
, too) and make use of it.
回答3:
To my understanding, this is not possible; it is impossible to have one field of a struct defined in terms of a different field.
回答4:
NO,
When you define a structure, its size has to be confirmed, so that when you declare a variable of that structure type, memory can be allocated for that variable.
Think about this scenario. When you want to declare a variable p
of the type st_employees
, since the No_Of_Employees
is not set yet, the size of the variable p
is not confirmed, hence memory for the variable cannot be allocated. But you cannot set No_Of_Employees
without declaring a variable of type st_employees
. Its a paradox.
回答5:
You can do this with dynamic allocation as follow:
#include <stdio.h>
#include <stdlib.h>
#define SIZE_OF_ELEM 15
#define uint8_t char
typedef struct
{
uint8_t No_Of_Employees;
uint8_t **Employee_Names;
}st_employees;
int main()
{
int i;
st_employees emps;
emps.No_Of_Employees = 2; //number of elements
// allocate the number of elements
emps.Employee_Names = malloc(emps.No_Of_Employees);
for (i=0; i < emps.No_Of_Employees; i++)
{
// allocate each element
emps.Employee_Names[i] = malloc(SIZE_OF_ELEM);
// fill the element with some data
sprintf(emps.Employee_Names[i], "emp_n%d", i);
}
// show the content
for (i=0; i<emps.No_Of_Employees; i++)
{
printf("Employee %d content: %s\n", i, emps.Employee_Names[i]);
}
return 0;
}
Of course this is an illustration, you have to check allocation, precise the sizeof type and release memory.
Note that this method allows to create a collection of objects that can have different types, and there is no need to use any particular C compiler version or options.
However, in very basic case (as in the OP example) it is not the better solution as it will fragment the memory (one allocation per object). So use this with caution.
来源:https://stackoverflow.com/questions/32311269/can-we-have-a-struct-element-of-type-variable-length-array