0

I have the following code in C:

typedef struct
{
   int age;
   int phoneNumber;
} Student;

typedef struct
{
  int id;
  int student[1];
} People;

#define NUM_OF_PEOPLE
void *p = malloc(sizeof(People) + sizeof(int) * NUM_OF_PEOPLE + sizeof(Student) * NUM_OF_PEOPLE);

How could I find the pointer to the memory point to the first element of struct Student in the memory?

I try to do it in the following way:

int i = 0;
for(i = 0; i < NUM_OF_PEOPLE; i++)
{
   Student * student_p = p.student[NUM_OF_PEOPLE];
}

It does not work, so can we allocate memory in the way?
And how to find the first element of struct Student in the memory?

Mr.C64
  • 41,637
  • 14
  • 86
  • 162
ratzip
  • 113
  • 2
  • 11
  • [this answer](http://stackoverflow.com/questions/20221012/unsized-array-declaration-in-a-struct/20221073#20221073) of mine has a good example of using flexible array members. – Shafik Yaghmour Mar 27 '14 at 17:26
  • Why not have an array of `Student` in `People`? – Engineer2021 Mar 27 '14 at 17:27
  • well, the struct can not be changed – ratzip Mar 27 '14 at 17:32
  • It seems like you are trying to create an array of pointers in the `People` struct where each pointer points to a `Student` struct. But in that case the `int student[1]` member should be declared as `Student *student[]`; – user3386109 Mar 27 '14 at 17:36

4 Answers4

1

What you have is an ancient way of having a flexible array member, which was technically also undefined behavior.

You are looking for this.

First, you need to define your struct like this (I don't know what the ints before the Students are, so let's just call it id):

typedef struct
{
   int age;
   int phoneNumber;
} Student;

typedef struct
{
  int id;
  Student student;
} StudentAndId;

typedef struct
{
  int id;
  StudentAndId students[];
} People;

Note the lack of size in the array inside People. Now you do this:

People *p = malloc(sizeof(People) + sizeof(StudentAndId[NUM_OF_PEOPLE]));

Then you can access students inside p as if it was an array of NUM_OF_PEOPLE elements.


Remember to compile with C99 (or C11) support. With gcc that would be -std=c99 or -std=gnu99.

Community
  • 1
  • 1
Shahbaz
  • 46,337
  • 19
  • 116
  • 182
0

This will allocate memory for storing the date but how you access it depends on how you store date. using C pointers you can store and access data using this structure and allocation but accessing the members will not be direct. it will involve pointer arithmetic. So better to use other structure if possible. If using this way of allocation then you need to do pointer arithmetic to get the next elements.

LearningC
  • 3,182
  • 1
  • 12
  • 19
0

Try this:

#include <stdio.h>
#include <stdlib.h>

typedef struct
{
   int age;
   int phoneNumber;
} Student;

typedef struct
{
  int id;
  int student[1];
} People;

#define NUM_OF_PEOPLE 10
int main()
{
   People *p = malloc(sizeof(People) + sizeof(int) * NUM_OF_PEOPLE + sizeof(Student) * NUM_OF_PEOPLE);
   int* id = (int*)(p+1);
   Student* s = (Student*)(id+NUM_OF_PEOPLE);

   printf("Size of People : %d\n", sizeof(People));
   printf("p points to    : %p\n", p);
   printf("id points to   : %p\n", id);
   printf("s points to    : %p\n", s);
}

Here's a sample output:

Size of People : 8
p points to    : 0x80010460
id points to   : 0x80010468
s points to    : 0x80010490
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • Note that this is generally not a good idea. For example, if `Student` starts with a `uint64_t` variable and `sizeof(People) + sizeof(int) * NUM_OF_PEOPLE` is not a multiple of 8, then you would end up having mis-aligned 64-bit variables. – Shahbaz Mar 27 '14 at 17:43
0

You may want to add the id field to your Student data structure, e.g.:

typedef struct {
    int id;
    int age;
    int phoneNumber;
} Student;

Then, you can define a structure having a fixed header (in this case, this can be the number of students), followed by a variable-sized array of Students:

#define ARRAY_OF_ANY_SIZE   1

typedef struct {
    int count;
    Student students[ARRAY_OF_ANY_SIZE];
} People;

This blog post explains this technique of having "arrays of size 1", including a discussion of the alignment problem.

I won't repeat the original blog post code here. Just consider that you can use the portable offsetof() instead of the Windows-specific FIELD_OFFSET() macro.

As a sample code, you may want to consider the following:

#include <stdio.h>     /* For printf()                  */
#include <stddef.h>    /* For offsetof()                */
#include <stdlib.h>    /* For dynamic memory allocation */

typedef struct {
    int id;
    int age;
    int phoneNumber;
} Student;

#define ARRAY_OF_ANY_SIZE   1

typedef struct {
    int count;
    Student students[ARRAY_OF_ANY_SIZE];
} People;

int main(int argc, char* argv[]) {
    People* people;
    const int numberOfStudents = 3;
    int i;
    
    /* Dynamically allocate memory to store the data structure */
    people = malloc(offsetof(People, students[numberOfStudents]));
    /* Check memory allocation ... */
    
    /* Fill the data structure */
    people->count = numberOfStudents;
    for (i = 0; i < numberOfStudents; i++) {
        people->students[i].id = i;
        people->students[i].age = (i+1)*10;
        people->students[i].phoneNumber = 11000 + i;
    }  
    
    /* Print the data structure content */
    for (i = 0; i < people->count; i++) {
        printf("id: %d, age=%d, phone=%d\n",
               people->students[i].id,
               people->students[i].age,
               people->students[i].phoneNumber);
    }
    
    /* Release the memory allocated by the data structure */
    free(people);

    return 0;
}

Output:

id: 0, age=10, phone=11000
id: 1, age=20, phone=11001
id: 2, age=30, phone=11002
Community
  • 1
  • 1
Mr.C64
  • 41,637
  • 14
  • 86
  • 162