Skip to main content

Command Palette

Search for a command to run...

Structs in C

Updated
5 min read
T

Hey there! I am a Software Developer who is passionate about data structures, algorithms and application development with C/C++.

In this article, I will show you what structs are and how to effectively use them in your programs. I will go over the following:

  1. What are Structs
  2. Syntax of a Struct
  3. Declaring a Struct
  4. How to Initialize Struct Members
  5. Nested Structs
  6. Struct Pointers
  7. Pointer Data Members inside a Struct
  8. Passing Structs into Functions

1) What are Structs?

Structs, or commonly known as Structure, are user-defined data-types. They help us group elements together that share something in common.

2) Syntax of a Struct

struct [structure tag] {

   member definition;
   member definition;
   ...
   member definition;
} [one or more structure variables];

3) Declaring a Struct

Example 1:

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

int main(int argc, char * argv[]){
    struct date {
        int month;
        int day;
        int year;
    } my_birthday;

    return EXIT_SUCCESS;
}

Example 2:

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

int main(int argc, char * argv[]){
    struct date {
        int month;
        int day;
        int year;
    };

    struct date my_birthday;

    return EXIT_SUCCESS;
}

4) How to Initialize Struct Members

It is important to note that you can not initialize data members inside a struct. You have to do it outide. Structs only hold the variables or data members. They do not hold the value.

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

int main(int argc, char * argv[]){
    struct date {
        int month = 5; //ERROR - Not allowed
        int day = 23; // ERROR - Not allowed
        int year = 2021; // ERROR - Not allowed
    } today_date;

    return EXIT_SUCCESS;
}

Let's see an example of how to correctly initialize values with a struct:

Example 1

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

int main(int argc, char * argv[]){
    struct date {
        int month;
        int day;
        int year;
     };

     struct date my_birthday[1] = {
        [0] = {.month = 6, .day = 15, .year = 1997}
     }

     printf("My birthday is %d/%d/%d",
            my_birthday[0].month,
            my_birthday[0].day,
            my_birthday[0].year);

     return EXIT_SUCCESS;
}

Example 2

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

int main(int argc, char * argv[]){
    struct date {
        int month;
        int day;
        int year;
     };

     struct date my_birthday[3] = {
        [0] = { 6, 15, 1997},
        [1] = {3, 23, 1989},
        [2] = {4, 29, 1979}
     };

     for(size_t i = 0; i < 3; ++i}{
         printf("My birthday is %d/%d/%d",
                my_birthday[i].month,
                my_birthday[i].day,
                my_birthday[i].year);
     };

     return EXIT_SUCCESS;
}

5) Nested Structs

You can also have structs within structs. This is very helpful! Let's say we want a struct called date and it handles just the day, month, and year. Then, let's say we want another struct called time and it handles seconds, minutes, and hours.

What if we want a struct called event that takes in month, day, year, minutes, seconds and hours?

We can do that with nested structs.

Example

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

int main(int argc, char * argv[]) {
    struct date {
        int month;
        int day;
        int year;
    };

    struct time {
        int seconds;
        int minutes; 
        int hours;
    };

    struct date_and_time {
        struct date s_date;
        struct time s_time;
    };

    struct date_and_time event[1] = {
        [0] = {.s_date.month = 6,
               .s_date.day = 15,
               .s_date.year = 1997,
               .s_time.hours = 15,
               .s_time.minutes = 45,
               .s_time.seconds = 59 }
    };

    for(size_t i = 0; i < 1; ++i) {
        printf("I was born on %d/%d/%d at %d: %d: %d ",
                event[i].s_date.month,
                event[i].s_date_day,
                event[i].s_date_year,
                event[i].s_time.hours,
                event[i].s_time.minutes,
                event[i].s_time.seconds);
    };

    return EXIT_SUCCESS;
}

6) Struct Pointers

You can also have a pointer to a struct. This is very helpful. C is a pass-by-value language and we want to be as efficient as possible. If we were to pass a struct through a function as an argument, we would be copying the entire struct. However, with a struct pointer, we just copy the memory address. It is a lot more efficient.

NOTE: In order to access data members with a pointer struct, you use -> operator as seen in the example below.

Example

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

int main(int argc, char * argv[]) {
    struct date{
        int month;
        int day;
        int year;
    };

    struct date new_date;

    struct date * p_date = &new_date;

    p_date->month = 6;
    p_date->day  = 15;
    p_date->year = 1997;

    printf("My birthday is %d/%d/%d",
            p_date->month,
            p_date->day,
            p_date->year); 

    return EXIT_SUCCESS;
}

7) Structs with Pointer Data Members

Structs can also have pointer data members. However, it is important to note that if you do decide to do this, you must dynamically allocate memory.

Since, we are dynamically allocating memory using malloc(), we must also call free() to free up the memory. This is prevent memory leaks.

Also, because have a struct pointer pointing to a struct of pointer data members, we must free the children, then the parent.

Otherwise, you would just free the data members.

Example 1

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

int main(int argc, char * argv[]) {
    struct create_struct {
        char * first_name;
        char * last_name;
    };

    struct create_struct full_name;

    struct create_struct p_full_name = &full_name;

    ptr_full_name->first_name = (char*)malloc(sizeof(char) * 50);
    ptr_full_name->last_name = (char*)malloc(sizeof(char)*50);

    strcpy(ptr_full_name->first_name, "Tomislav");
    strcpy(ptr_full_name->last_name, "Kraljic");

    printf("My name is %s %s",
            ptr_full_name->first_name,
            ptr_full_name->last_name);

    free(ptr_full_name->first_name); 
    free(ptr_full_name->last_name);
    free(ptr_full_name);

    return EXIT_SUCCESS;
}

8) Passing Structs into Functions

We can also pass structs as argument into functions. This is where pointer to a struct comes in handy! We just want to copy the memory address and pass it. We do not want to copy the entire struct and all its data.

Example 1

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

struct create_my_struct {
    char * first_name;
    char * last_name;
} my_name;

struct create_my_struct * ptr_full_name = &my_name;

void create_data(struct create_my_struct * ptr_full_name);

void free_data(struct create_my_struct * ptr_full_name);

void print_data(struct create_my_struct * ptr_full_name);

int main(int argc, char * argv[]) {
    create_data(ptr_full_name);

    print_data(ptr_full_name);

    free_data(ptr_full_name);

    return EXIT_SUCCESS;
}

void create_data(struct create_my_struct * ptr_full_name) {
    ptr_full_name->first_name = (char*)malloc(sizeof(char)*50);
    ptr_full_name->last_name = (char*)malloc(sizeof(char)*50);

    strcpy(ptr_full_name->first_name, "Tomislav");
    strcpy(ptr_full_name->last_name, "Kraljic");
};

void print_data(struct create_my_struct * ptr_full_name) {
    printf("My name is %s %s",
            ptr_full_name->first_name,
            ptr_full_name->last_name);
};

void free_data(struct create_my_struct * ptr_full_name) {
    free(ptr_full_name->first_name);
    free(ptr_full_name->last_name);
    free(ptr_full_name);
};

A

Awesome blog. But would recommend testing the code examples before publishing. I could see some errors though few. Coz it can be frustrating for beginners who are struggling with. Otherwise, I learnt something new from the article and am really grateful for putting effort in writing this blog. Kudos!

D

I find the term “pointer struct” super confusing and I have never heard or read it anywhere before. If you call something “xyz struct” then by the regular usage of the English language (and German and Mandarin for that matter) it means that “xyz” is a struct. But struct xyz * is not a struct. It’s a pointer, a pointer to an object of type struct xyz. Just like int* is a pointer to an object of type int.

Where “object” (in C or C++) refers to a piece of memory that holds a value of some type.

T

You are absolutely right. It was super late when I wrote this article and "pointer struct" is never used. I corrected myself. Thank you!

1

More from this blog

Tomislav Kraljic's Blog

24 posts