Structs in C

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

// This `person` struct type has `name` and `age` fields.
struct person {
    char* name;
    int age;
};

// `newPerson` constructs a new person struct with the given name.
struct person* newPerson(const char* name) {
    // In C, we need to manually allocate memory for the struct and its fields
    struct person* p = malloc(sizeof(struct person));
    p->name = strdup(name);  // strdup allocates memory for the string
    p->age = 42;
    return p;
}

int main() {
    // This syntax creates a new struct.
    struct person bob = {"Bob", 20};
    printf("{%s %d}\n", bob.name, bob.age);

    // You can name the fields when initializing a struct.
    struct person alice = {.name = "Alice", .age = 30};
    printf("{%s %d}\n", alice.name, alice.age);

    // Omitted fields will be zero-valued.
    struct person fred = {.name = "Fred"};
    printf("{%s %d}\n", fred.name, fred.age);

    // An `&` prefix yields a pointer to the struct.
    struct person ann = {.name = "Ann", .age = 40};
    printf("&{%s %d}\n", ann.name, ann.age);

    // It's idiomatic to encapsulate new struct creation in constructor functions
    struct person* jon = newPerson("Jon");
    printf("&{%s %d}\n", jon->name, jon->age);

    // Access struct fields with a dot.
    struct person sean = {.name = "Sean", .age = 50};
    printf("%s\n", sean.name);

    // You can also use arrow notation with struct pointers.
    struct person* sp = &sean;
    printf("%d\n", sp->age);

    // Structs are mutable.
    sp->age = 51;
    printf("%d\n", sp->age);

    // If a struct type is only used for a single value, we can use an anonymous struct.
    struct {
        char* name;
        int isGood;
    } dog = {"Rex", 1};
    printf("{%s %d}\n", dog.name, dog.isGood);

    // Clean up dynamically allocated memory
    free(jon->name);
    free(jon);

    return 0;
}

In C, structs are similar to those in other languages, but there are some key differences:

  1. Memory Management: In C, you’re responsible for memory management. When creating structs dynamically (like in newPerson), you need to manually allocate memory with malloc and free it when you’re done.

  2. String Handling: C doesn’t have a built-in string type. Strings are represented as char arrays or pointers. When assigning strings, you need to be careful about memory allocation (like using strdup).

  3. No Method Syntax: C doesn’t have methods associated with structs. Instead, you typically pass a pointer to the struct as the first argument to functions that operate on it.

  4. Initialization: C99 and later allow designated initializers (like .name = "Fred"), which is similar to named field initialization in some other languages.

  5. Pointers: In C, you often work with pointers to structs. The -> operator is used to access fields through a pointer, while . is used for direct struct access.

  6. No Garbage Collection: C doesn’t have garbage collection, so you need to manually free any dynamically allocated memory to prevent memory leaks.

To compile and run this program:

$ gcc -o structs structs.c
$ ./structs
{Bob 20}
{Alice 30}
{Fred 0}
&{Ann 40}
&{Jon 42}
Sean
50
51
{Rex 1}

This C code demonstrates the basics of working with structs, including creation, initialization, access, and memory management.