Structs


Struct Structure

Supported in C and C++, structs provide a way to group variables of mixed data types into one element. That element is a struct (meaning structure).

There is an important distinction here as well. When you define a struct, you are defining the shape of the struct. You then use this struct (shape) to create a struct instance.

struct test_scores_t{
    int midterm_1;
    int midterm_2;
    int final_exam;
};

struct person_t{
    /* a struct can accept a mixture of unordered types */
    char name[10];
    int class_year;
    char gender;
    test_scores_t test_scores; /* a struct can be nested within a struct */
};

int main(void){
    person_t Ahmed;
    return 0;
}

You can define multiple variables within a struct, each with a different data type and name. When accessing the struct, the struct elements can be accessed by name.

By default, when creating a struct, you are creating the shape of the struct. Creating an instance of the struct is an additional step. The struct resembles a composite data type in a way.

Here, we declare a struct type (its shape) and include three variables. Now we have test_scores_t that defines this new (data type) that has three int elements.

struct test_scores_t{
    int midterm_1;
    int midterm_2;
    int final_exam;
};

Here we declare a different struct, and include an array , variables and a struct. Yes, structs can embed other structs.

struct person_t{
    /* a struct can accept a mixture of unordered types */
    char name[10];
    int class_year;
    char gender;
    test_scores_t test_scores; /* a struct can be nested within a struct */
};

Note, again, that the struct created is only a "template". Here we actually create an instance of the struct person_t called Ahmad. Now the struct instance Ahmed has the members: name , class_year, gender and the test scores struct which then has the midterm and final grades.

person_t Ahmed;

Accessing Struct Members

Once a struct instance is created, we can access its members by the dot operator.

#include <iostream>
#include<cstring>

struct person_t{ /* person_t is a struct type */
    int age;
    char gender;
    char name[10];
};

int main(void){
    person_t Ahmed; /* A new struct object of type person_t is created */
    Ahmed.age    = 18; /* Struct members are accessed by . (dot) character */
    Ahmed.gender = 'M';
    strcpy(Ahmed.name, "Ahmed");

    std::cout << "Name: " << Ahmed.name << ", Age:" << Ahmed.age 
    << ", Gender = " << Ahmed.gender << std::endl;

    return 0;
}
Output:
Name: Ahmed, Age:18, Gender = M

Here we use the function string copy to copy over the literal string to the name array. More on strings later.

strcpy(Ahmed.name, "Ahmed");

Manipulating Structs

#include <iostream>
struct person_t{
    int age; char gender; char name[10];
}Sara, Abdullah; /* Struct objects can be created, they are global */

void add_age(person_t &person, int age){
    person.age = age;
}
void sub_routine(void);

int main(void){
    person_t Ahmed; /* A a struct created here has a local scope */
    add_age(Ahmed, 24);
    sub_routine();
    return 0;
}
void sub_routine(void){
    add_age(Sara, 19); /* Global structs can be accessed here */
    add_age(Abdullah, 21);
}
Output:

test
test2

We can create multiple instances of the struct after the struct declaration, separated by comma, ending with a semicolon. Note that these struct instances are global.

struct person_t{
    int age; char gender; char name[10];
}Sara, Abdullah; /* Struct objects can be created, they are global */

We can pass a struct to a function. Here we pass the struct by reference, so the original struct is access directly, not a copy of it.

void add_age(person_t &person, int age){
    person.age = age;
}
add_age(Ahmed, 24);

And since Sara, and Abdullah are global struct instances, they can be accessed anywhere in the file.

void sub_routine(void){
    add_age(Sara, 19); /* Global structs can be accessed here */
    add_age(Abdullah, 21);
}

Struct as function return

A function can actually return a struct. Note that it will return a copy of a struct here, perhaps this may not be the most efficient way, especially if the struct is large or this function is called many times.

#include <iostream>
struct person_t{
    int age; char gender; char name[10];
}Sara;

void add_age_1(person_t &person, int age){ /* Takes struct by reference */
    person.age = age;
}
person_t add_age_2(person_t person, int age){ /* Takes a copy of struct, returns a struct */
    person.age = age;
    return person;
}

int main(void){
    person_t Ahmed; /* A a struct created here has a local scope */
    add_age_1(Sara, 19); /* Original object is manipulated */
    Ahmed = add_age_2(Ahmed, 24); /* A copy of the original object is passed */
    return 0;
}

Since the add_age_2 function returns a struct, we can copy over the returned struct to Ahmad struct. Again, this might not be the most efficient way to do it.

Next: Classes