Defining elastic/flexible structure in C - c

I have a task to do and the content of the task is:
Please suggest a definition of linked list, which will keep the person's name and age in a flexible structure. Then write the procedure for inserting elements with the given name and age.
What exactly is a flexible structure? How to define it? And then how to malloc the size?
typedef struct Test {
int age; // ?
char name[?]; // ?
struct Test * next;
}Structure;
int main(void) {
Structure *one = malloc(???);
}

You are on the right track. However, there is no "flexible structure". You want to use a flexible array member (avail since C99) in a struct:
typedef struct {
int age;
size_t name_size; // size of the array, not length of the name!
char name[]; // Flexible array member
} Structure;
int main(void) {
Structure *one = malloc(sizeof(*one) + SIZE_OF_NAME_ARRAY);
}
Note I added a name_size field. C does not store the size of allocated arrays, so you might need this for safe copy/compare, etc. (prevent buffer overflows).
Using *one makes this term independent of the actual type used. The size of such a struct is as if the arrray had zero elements. However, it will be properly aligned, so it can differ from the same struct without the array.
Also note that you have to change the allocated size if you use other than a char array to something like sizeof(element_type) * ARRAY_SIZE. This is not necessary for chars, as their size is defined by the standard to be 1.

my guess: a flexible struct would be one that could handle any age and any name.
A unsigned int field would handle any age (within reason).
A char * field would handle any name.
The struct itself would be:
struct nameAge { unsigned int age; char * pName; };
an instance of the struct would be:
struct nameAge myNameAge;
Setting the age field would be:
myNameAge.age = ageValue;
Setting the name field would be:
myNameAge.name = malloc( numCharactersInName+1 );
strcpy( myNameAge.name, nameString );
How the code obtained the ageValue for age and/or the characters for NameString is up to the programmer to decide/implement.

Related

C newbie: can I have fixed-size dynamically allocated structs? [duplicate]

I have a task to do and the content of the task is:
Please suggest a definition of linked list, which will keep the person's name and age in a flexible structure. Then write the procedure for inserting elements with the given name and age.
What exactly is a flexible structure? How to define it? And then how to malloc the size?
typedef struct Test {
int age; // ?
char name[?]; // ?
struct Test * next;
}Structure;
int main(void) {
Structure *one = malloc(???);
}
You are on the right track. However, there is no "flexible structure". You want to use a flexible array member (avail since C99) in a struct:
typedef struct {
int age;
size_t name_size; // size of the array, not length of the name!
char name[]; // Flexible array member
} Structure;
int main(void) {
Structure *one = malloc(sizeof(*one) + SIZE_OF_NAME_ARRAY);
}
Note I added a name_size field. C does not store the size of allocated arrays, so you might need this for safe copy/compare, etc. (prevent buffer overflows).
Using *one makes this term independent of the actual type used. The size of such a struct is as if the arrray had zero elements. However, it will be properly aligned, so it can differ from the same struct without the array.
Also note that you have to change the allocated size if you use other than a char array to something like sizeof(element_type) * ARRAY_SIZE. This is not necessary for chars, as their size is defined by the standard to be 1.
my guess: a flexible struct would be one that could handle any age and any name.
A unsigned int field would handle any age (within reason).
A char * field would handle any name.
The struct itself would be:
struct nameAge { unsigned int age; char * pName; };
an instance of the struct would be:
struct nameAge myNameAge;
Setting the age field would be:
myNameAge.age = ageValue;
Setting the name field would be:
myNameAge.name = malloc( numCharactersInName+1 );
strcpy( myNameAge.name, nameString );
How the code obtained the ageValue for age and/or the characters for NameString is up to the programmer to decide/implement.

Is there a way to initialize an array of strings in a struct when you don't know how many elements you will put in the string?

I have this struct:
typedef struct SomeStruct {
char someString[];
} SomeStruct;
This produces an error since someString's size is not defined when initialized.
I want to make someString an array of strings, but I will not know the size of the array at the time of initialization. (The elements that will be in the array will depend on user input later in the program).
Is it possible to initialize this as an array of strings without knowing the size of the array?
Yes, the C standard talks about this in 7.2.18-26. What you are describing is known as a flexible array member of a struct. From the standard:
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.
Essentially what it is saying is, if the last member of the struct is an array of undefined size (as might be the case for runtime sizes), then when using the struct, you would allocate the appropriate size of your struct including how large you want the string to be. For example:
typedef struct SomeStruct {
char someString[];
} SomeStruct;
has the flexible array member someString. A common way to use this is:
SomeStruct *p = malloc(sizeof (SomeStruct) + str_size);
Assuming that the call to malloc succeeds, the object pointed to by p behaves, for most purposes, as if p had been declared as:
struct {char someString[str_size]; } *p;
Read the standard for more detail. The buzzword flexible array member will show up a lot of information too. The wikipedia is a good place to start.
You can use a structure with flexible array. For example
typedef struct SomeStruct
{
size_t n;
char someString[];
} SomeStruct;
where n is used to store the number of elements in the array.
Then you can create objects of the structure the following way
SomeStruct *s = malloc( sizeof( SomeStruct ) + 10 * sizeof( char[100] ) );
s->n = 10;
If you can't use a dynamic array (it sounds like this, if you get a compile error for it), you can actually overrun the array, as long as it's at the end of the struct, and as long as you can actually access that memory. Example:
#include <stdio.h>
#include <stdlib.h>
typedef struct SomeStruct {
char someString[10];
} SomeStruct;
int main (void)
{
// Allocate 4x space, so we have room to overrun
SomeStruct *p = malloc(sizeof(SomeStruct) * 4);
p->someString[38] = 'a';
printf("%c\n", p->someString[38]);
}
Of course, you still have to actually allocate the space, so it may not be so useful to you depending on your case.

get size of list struct in struct

I have following structs:
struct Student{
char *name;
int age;
};
struct Class{
char *class_name;
struct Student students[];
};
And a counting function :
int countStdInClass(struct Class *classA){
int sizeOfStd = sizeof(classA->students)/sizeof(classA->students[0])
return sizeOfStd ;
}
When compiling ,an error occurrence :
invalid application of ‘sizeof’ to incomplete type ‘struct Student[]'
Please help me correct it .
Thanks.
1. In struct Class -
struct Student students[ ];
/* ^ you haven't given any size . */
You need to give number of elements as you use it as operand to sizeof . Example -
struct Student students[5]; // give any desired size
2. Also in your function int countStdInClass-
int sizeOfStd = sizeof(classA->students)/sizeof(classA->students[0])
/* ^ ; missing */
The C standard explicitly states (6.7.2.1) that a flexible array member isn't counted when taking the sizeof the struct:
In particular, the size of the structure is as if the flexible array
member were omitted except that it may have more trailing padding than
the omission would imply.
It only makes sense to use flexible array members if you allocate memory dynamically. And as for all other cases of dynamic memory, it doesn't make any sense to use the sizeof operator on the allocated segment.
When using the flexible array member students, you have to allocate memory as:
struct Class* c = malloc( sizeof(*c) + n*sizeof(struct Student) );
Meaning you already know the size! It is n*sizeof(struct Student).

Char with a variable length

Is it possible to define a char with a variable length?
I have a char "name" (member of a struct named "person") with a length of 25 but I want it to be a variable length between the values 1 and 25, because I want to generate random strings of that char with different sizes and not always with the same length (25). One of the parameters of the method is sizeof(n.name).
Note: n is a struct (struct person n).
The struct "person" is defined this way:
struct person{
int c;
char name[25];
};
Anyone?
struct person{
int c;
char name[]; /* Variable length array */
};
I think this should serve your purpose.
Else you can have dynamic memory allocation using
char *name;
name is a pointer and memory should be allocated and it can be done using malloc()
You can use a flexible array. It must be the last data member of a structure.
struct person{
int c;
char name[];
};
The memory for a structure with a flexible array has to be allocated dynamically.
From the C Standard (6.7.2.1 Structure and union specifiers)
the flexible array member is ignored. In particular, the size of the
structure is as if the flexible array member were omitted except that
it may have more trailing padding than the omission would imply. Howev
er, when a . (or ->) operator has a left operand that is (a pointer
to) a structure with a flexible array member and the right operand
names that member, it behaves as if that member were replaced with the
longest array (with the same element type) that would not make the
structure larger than the object being accessed; the offset of the
array shall remain that of the flexible array member, even if this
would differ from that of the replacement array. If this array would
have no elements, it behaves as if it had one element but the behavior
is undefined if any attempt is made to access that element or to
generate a pointer one past it.
And there is an example of its using
20 EXAMPLE 2 After the declaration:
struct s { int n; double d[]; };
the structure struct s has a flexible array member d. A typical way to use this is:
int m = /* some value */;
struct s *p = malloc(sizeof (struct s) + sizeof (double [m]));
and assuming that the call to malloc succeeds, the object pointed to by p behaves, for most purposes, as if
p had been declared as:
struct { int n; double d[m]; } *p;
(there are circumstances in which this equivalence is broken; in particular, the offsets of member d might
not be the same).
Or you could declare a pointer to char and dynamically allocate only the array itself
struct person{
int c;
char *name;
};
char[25] lets you store C strings of length between zero and 24, inclusive (one character is needed for '\0' terminator).
You can use one of two solutions:
Use a flexible array member, or
Use a pointer.
The first solution lets you keep the name together with the rest of the struct, but you would not be able to make arrays of these structs:
struct person{
int c;
char name[];
};
See this Q&A for more information on flexible array members. You need a compiler compatible with C99 to use flexible array members.
The second solution takes slightly more memory, but the size of your struct does not change, making it possible to use it in an array:
struct person{
int c;
char *name;
};
A better way to do this is to use the strings library and declare the variable 'name' of type string.
#include<string>
struct person{
int c;
string name;
};

Copying one value from one struct camp into another struct but same data type

So I have one struct and I initialized a variable A with that struct data type then Ι put in some values. But now Ι need to take those values and put it into another variable B with the same struct data type. How can Ι achieve this?
struct s_Especialidade{
int id;
char nome[60];
char descricao[60];
struct s_Especialidade *proximo;
};
typedef struct s_Especialidade Especialidade;
PESPECIALIDADE p, *array;
p->nome = &array[i]->nome; //THIS LINE GIVES THE ERROR
Since it is an array of characters, you need to copy each element of the array.
strcpy(p->nome, array[i]->nome) will do it, but for extra security look at strncpy where you can set a maximum length to avoid overruns.
Try that way :
memcpy( p->nome, array[i].nome, 60 * sizeof(char) );
Or generalizing the type as well, picking the type used in the p->nome array :
memcpy( p->nome, array[i].nome, 60 * sizeof(*(p->nome)) );
This is the generalized and secure way to copy an array into another (not only for strings).
To extend the answer recommending strcpy() I'd use memcpy() and use a #defined length to make sure you always use the same value.
#define NOME_LENGTH 60
struct s_Especialidade{
int id;
char nome[NOME_LENGTH];
char descricao[60];
struct s_Especialidade *proximo;
};
typedef struct s_Especialidade Especialidade;
PESPECIALIDADE p, *array;
memcpy(p->nome, array[i]->nome, NOME_LENGTH);
Things get even more complicated trying to consider what an assignment does, but, in an example program:
struct stuff {
char buf[2];
};
int main() {
struct stuff a;
memcpy(a.buf, "aa", 2); // *Edit: "aa" is a bad example as it
// actually becomes at compilation 3 bytes long
// {'a','a','\0'} as noted in the comments
struct stuff b;
b.buf = a.buf; // *Edit: For illustrative purposes, an assignment
// between two char[2] members is not correct and
// does not compile.
}
Compilation yeilds the error error: incompatible types when assigning to type ‘char[2]’ from type ‘char *’ for the b.buf = a.buf line.
The topic of pointers and arrays has been covered elsewhere, Is an array name a pointer? among others.
*Edit: As noted in the comments, in the above code if instead of b.buf = a.buf; the struct assignemnt b = a; were done, the internal members would be copied correctly. This is because struct to struct assignment is effectively memcpy(&b, &a, sizeof(b)); (Assign one struct to another in C)

Resources