struct#

For putting many values with different data types together in a single variable.

General syntax#

struct TagName {
    Type member1;
    Type member2;
};
struct

defines a composite data type – a named set of values that occupy a block of memory

Tagged struct#

struct Shape {
  int x, y;
  char *name;
}; // struct definition is similar to `enum`

struct Shape s = {.x = 0, .y = 0, .name = "banana"};
// Pay attention to `.`s
// Alternatively: {0, 0, "banana"} in short

int main() {
  s.x = 5;
  // Access elements with `.`

  struct Shape s2 = {};
  // Can be initialized similar to arrays
}

Activity 54 (Comparing structs)

  1. Define a struct named Person with two members:

    • age

    • gender

  2. Create two variables using the struct: p1, p2.

  3. Write a function called are_equal(a, b) that checks whether the two have the same data.

Note

As a convention, I use PascalCase for tags (and also typedef, enum, union, etc). It seems to be more common.

You will see also snake_case and _t suffix in other code. The most important is to stick to the conventions of a code base or project.

Anonymous struct#

We can also declare a variable directly like an enum, but then reusing it becomes more difficult:

Above example using an anonymous struct and typeof:

struct {
  int x, y;
  char *name;
} s = {.x = 0, .y = 0, .name = "banana"};

int main() {
  s.x = 5;
  typeof(s) s2 = {};
}

Tip

Anonymous struct is useful if you plan not to use the struct for further variables.

Typically you can stick to the tagged version.

pass-by-?#

Activity 55 (Passing a struct to a function)

The code below stores same values in an array and a struct. Analyze the following code and its output. Why are a and s not the same in the end?

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

int a[] = {4, 2};

struct {
  int a, b;
} s = {4, 2};

void set_first_element_to_zero_array(typeof(a) a) { a[0] = 0; }
void set_first_element_to_zero_struct(typeof(s) s) { s.a = 0; }

void are_values_of_a_and_s_equal() {
  puts(memcmp(a, &s, sizeof(a)) ? "a != b" : "a == b");
}

int main() {
  are_values_of_a_and_s_equal();

  puts("set_first_element_to_zero()");
  set_first_element_to_zero_array(a);
  set_first_element_to_zero_struct(s);

  are_values_of_a_and_s_equal();
}

Output

a == b
set_first_element_to_zero()
a != b

Tip

Pay attention when you are passing large structs. Structs should be typically passed by address.

Activity 56 (Modifying struct members)

Modify set_first_element_to_zero_struct so the struct is passed by address.

Accessing members of a struct pointer using ->#

-> is the arrow operator.

struct Shape {
  int x, y;
  char *name;
};

struct Shape s;
typeof(s) *sp = &s;

int main() {
  (*sp).x = 1;  // ❌ this is silly
  sp->x = 1;  // ✅
}

Activity 57

Modify your code again to use the dereference operator.

Self-referential struct#

struct can point to itself. This is a superpower 💪:

#include <stdio.h>
#include <string.h>
struct node {
  char *data;
  struct node *next;
};
struct node tail = {"tej", nullptr}, b = {"pos", &tail}, a = {"ver", &b},
            head = {"le", &a};

char puzzle[20], puzzle2[20];

int main() {
  printf("puzzle:  ");
  strcat(puzzle, head.data);
  strcat(puzzle, head.next->data);             // a
  strcat(puzzle, head.next->next->data);       // b
  strcat(puzzle, head.next->next->next->data); // tail
  puts(puzzle);

  // Alternatively through traversing the chain
  printf("puzzle2: ");
  struct node *cursor = &head;
  while (cursor) {
    strcat(puzzle2, cursor->data);
    cursor = cursor->next;
  }
  puts(puzzle2);
}
puzzle:  leverpostej
puzzle2: leverpostej
https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg

Fig. 23 A linked list. Each node contains data (e.g., 12) and a pointer to the next node.
Public domain. By Vectorization: Lasindi. Source: Wikimedia Commons
#

We can build dynamic linked lists using this superpower.

linked list

a linear collection of data elements whose order is not given by their physical placement in memory.

We will visit linked lists in a future chapter again.

🤔 Question to ponder

How can we create an endless string using the linked list above?