'Access the int value of the nested struct in C

I can access the char value of the nested struct, but the int one it shows memory address only, how I can dereference the pointer value of an int one ? here is a sample code:

#include <stdio.h>


    struct Class {
        char name[10];
        int cap;
    };

    struct Student {
        char firstname[10];
        char lastname[10];
        struct Class *class[5];
    };
    


     void printStudents(struct Student *student) {
        struct Class *class;
        class = student->class[2];
        printf("Capacity => %d\n", &class->cap);
        printf("Class => %s\n", &class->name);
    }



int main(void) {
    
struct Class class[] = {
            {"rust",   8},
            {"python", 22},
            {"java",   33}
    };

    struct Student student = {"Ian", "saeidi", (struct Class *) &class};

struct Class class[] = {
            {"rust",   8},
            {"python", 22},
            {"java",   33}
    };

    struct Student student = {"Ian", "saeidi", &class};
    
        printStudents(&student);
    
        return 0;
    }

Output:


Expected Output:

Capacity => 33
Class => java

I have tried the below initialization still does not worked, and the editor says that it is element 0, while I have added the entire struct array:

struct Class class[] = {
            {"rust",   8},
            {"python", 22},
            {"java",   33}
    };

    struct Student student = {"Ian", "saeidi", (struct Class *) &class};

struct Class class[] = {
            {"rust",   8},
            {"python", 22},
            {"java",   33}
    };

    struct Student student = {"Ian", "saeidi", &class};

enter image description here

enter image description here

c


Solution 1:[1]

struct Student student = {"Ian", "saeidi", {"rust", 24}}; is incorrect. The {"rust", 24} part needs to be changed to a pointer to a struct Class. That struct Class could be stored as a variable like this:

struct Class class = {"rust", 24};
struct Student student = {"Ian", "saeidi", &class};

Alternatively, that struct Class could be stored as a compound literal like this:

struct Student student = {"Ian", "saeidi", &(struct Class){"rust", 24}};

A compound literal behaves rather like an initialized variable, but is anonymous.


The printStudents function is passing the wrong arguments to printf(). It is passing the address of class->cap instead of the value of class->cap. And it is also passing the address of class->name instead of the the address of class->name[0]. That can be corrected by removing the & from both calls to printf:

    printf("Capacity => %d\n", class->cap);
    printf("Class => %s\n", class->name);

N.B. class->name is the same value as &class->name[0].


EDIT after OP changed the question

OP changed struct Student member class from struct Class *class to struct Class *class[5]. The previous initialization should still work, but student.class[1] through to student.class[4] will have the default initialization of NULL.

With OP's array of 3 classes, student can be initialized as follows:

struct Class class[] = {
            {"rust",   8},
            {"python", 22},
            {"java",   33}
    };

struct Student student = {"Ian", "saeidi",
                           { &class[0], &class[1], &class[2] } };

Full working code:

#include <stdio.h>

#define ARRAY_LEN(x) (sizeof (x) / sizeof *(x))

struct Student {
    char firstname[10];
    char lastname[10];
    struct Class *class[5];
};

struct Class {
    char name[10];
    int cap;
};

void printStudents(struct Student *student) {
    printf("First name => %s\n", student->firstname);
    printf("Last name => %s\n", student->lastname);
    for (int i = 0; i < ARRAY_LEN(student->class); i++) {
        struct Class *class = student->class[i];
        if (class) {
            printf("Class %d =>\n", i);
            printf("    Capacity => %d\n", class->cap);
            printf("    Name => %s\n", class->name);
        }
    }
}

int main(void) {
    struct Class class[] = {
        {"rust",   8},
        {"python", 22},
        {"java",   33}
    };
    struct Student student = {"Ian", "saeidi",
                               { &class[0], &class[1], &class[2] } };

    printStudents(&student);

    return 0;
}

Solution 2:[2]

You have several problems:

  1. You're not allocating any space for class, so trying to initialize it with {"rust", 24} is incorrect.
  2. Even if that was ok, name is a single char and cannot hold nor point to a string.
  3. Since the initialization is wrong, class = student->class; assigns class to invalid memory, and dereferencing it (class->) invokes undefined behavior.
  4. "%d" printf format specifier expects an int, but you pass it an int*
  5. "%s" printf format specifier expect a char*, but you pass it a char (*)[10] (pointer to a 10 size char array).

One possible fix:

// flip the order of the structs so you can declare a `struct Class class` in
// `struct Student` (no pointer)
struct Class {
    // change this from a pointer to array
    char name[10];
    int cap;
};

struct Student {
    char firstname[10];
    char lastname[10];
    struct Class class;
};

 void printStudents(struct Student *student) {
    // get a pointer to the address of student->class if you want
    struct Class *class;
    class = &(student->class);

    // now things print appropriately
    // pass an `int` to %d
    printf("Capacity => %d\n", class->cap);
    // pass a `char*` to %s. `class->name` in this context "decays" to a
    // pointer to its first element, a `char`
    printf("Class => %s\n", class->name);
}

int main(void) {
    // now your initialization is valid
    struct Student student = {"Ian", "saeidi", {"rust", 24}};

    printStudents(&student);

    return 0;
}

You could also use dynamic memory allocation instead of arrays.

Demonstration


EDIT after OP changed the question, another possible implementation. See explanation comments below:

struct Class {
    char name[10];
    int cap;
};

struct Student {
    char firstname[10];
    char lastname[10];
    // Not exactly sure what you're trying to do, but I've changed your
    // pointer here to be a pointer to an array of three `struct Class`es
    // (since that's what you're creating in main, and so this is the only
    // compatible pointer that can point to such an object).
    struct Class (*class)[3];
};

void printStudent(struct Student *student) {
    struct Class (*class)[3];
    class = (*student).class;
    
    // Take note of the pointer arithmetic here. class+1 advances the
    // pointer the size of three `struct Class`es. From main, there's
    // only one object of this type (three `struct Class`es), so you
    // have to dereference the pointer at that first object only
    // (eg, `(*class)` ), then apply the index for `cap` and `name`.
    // If you do `class[i]`, for `i>0` you point to the `i`th object of
    // 3 `struct Class`es, which of course don't exist. There's only one.
    for (size_t i=0; i<3; i++)
    {
        printf("Capacity => %d\n", (*class)[i].cap);
        printf("Class => %s\n", (*class)[i].name);
    }
}

int main(void) {
    // here you're creating three `struct Class`es
    struct Class class[] = {
            {"rust",   8},
            {"python", 22},
            {"java",   33}
    };

    // pass the address of `class` to your struct. This type is a
    // struct Class (*)[3]. That is, a pointer to a 3-size array of
    // struct Class type.  If you added or subtracted another entry
    // to your class definition above, then you'd have to change the
    // pointer dimension in struct Student as well.
    struct Student student = {"Ian", "saeidi", &class};
    printStudent(&student);
    return 0;
}

New Demonstration

Solution 3:[3]

I have found the problem, the class array length should be determine during initialization:

#include <stdio.h>


    struct Class {
        char name[10];
        int cap;
    };

    struct Student {
        char firstname[10];
        char lastname[10];
        struct Class *class;
    };
    


     void printStudents(struct Student *student) {
        struct Class *class;
        class = student->class[2];
        printf("Capacity => %d\n", &class->cap);
        printf("Class => %s\n", &class->name);
    }



int main(void) {

// here I added the length of the class struct    
struct Class class[5] = {
            {"rust",   8},
            {"python", 22},
            {"java",   33}
    };

    struct Student student = {"Ian", "saeidi", &class};
    
        printStudents(&student);
    
        return 0;
    }

@ian abbott and other guys, Thanks for participating

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 mos