C Structs & Pointers
Pointers to Structures
Pointers to structures allow you to work with structures efficiently, especially when passing them to functions or dynamically allocating memory. Understanding how to use pointers with structures is crucial for advanced C programming.
Declaring Structure Pointers
Example
#include <stdio.h>
struct Point {
int x;
int y;
};
int main(void) {
struct Point p1 = {10, 20};
struct Point *ptr = &p1; // Pointer to structure
// Using dereference + dot
printf("Coordinates (via *ptr): (%d, %d)\n", (*ptr).x, (*ptr).y);
// Using arrow (shorthand)
printf("Coordinates (via ->): (%d, %d)\n", ptr->x, ptr->y);
return 0;
}
Output
Coordinates (via *ptr): (10, 20) Coordinates (via ->): (10, 20)
ℹ️ Note: The parentheses around *ptr are necessary because the dot operator has higher precedence than the dereference operator.
Arrow Operator (->)
Example
#include <stdio.h>
struct Student {
char name[50];
int id;
float gpa;
};
int main(void) {
struct Student s1 = {"Alice", 101, 3.8f};
struct Student *ptr = &s1;
// Access members using arrow operator
printf("Name: %s\n", ptr->name);
printf("ID: %d\n", ptr->id);
printf("GPA: %.2f\n", ptr->gpa);
return 0;
}
Output
Name: Alice ID: 101 GPA: 3.80
ℹ️ Note: The arrow operator (->) is shorthand for (*ptr).member and is more commonly used for clarity.
Dynamic Memory Allocation for Structures
⚠️ Warning: Always check if malloc() returns NULL and always free allocated memory to avoid memory leaks.
Example
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Book {
char title[100];
char author[50];
float price;
};
int main(void) {
// Dynamically allocate memory for a structure
struct Book *bookPtr = malloc(sizeof *bookPtr);
if (bookPtr == NULL) {
printf("Memory allocation failed.\n");
return 1;
}
// Access members using arrow operator
strcpy(bookPtr->title, "The C Programming Language");
strcpy(bookPtr->author, "K&R");
bookPtr->price = 45.99f;
printf("Book: %s by %s - $%.2f\n", bookPtr->title, bookPtr->author, bookPtr->price);
free(bookPtr);
return 0;
}
Output
Book: The C Programming Language by K&R - $45.99
Passing Structures to Functions
Example
#include <stdio.h>
struct Rectangle {
float length;
float width;
};
float areaByValue(struct Rectangle r) {
return r.length * r.width;
}
float areaByPointer(const struct Rectangle *r) {
return r->length * r->width;
}
void scaleRectangle(struct Rectangle *r, float factor) {
r->length *= factor;
r->width *= factor;
}
int main(void) {
struct Rectangle rect = {5.0f, 3.0f};
printf("Original area: %.2f\n", areaByValue(rect));
printf("Area via pointer: %.2f\n", areaByPointer(&rect));
scaleRectangle(&rect, 2.0f);
printf("Scaled area: %.2f\n", areaByPointer(&rect));
return 0;
}
Output
Original area: 15.00 Area via pointer: 15.00 Scaled area: 60.00
ℹ️ Note: Passing structures by pointer is more efficient for large structures and allows modifying the original structure.
Arrays of Structure Pointers
Example
#include <stdio.h>
#include <stdlib.h>
struct Person {
char name[50];
int age;
};
int main(void) {
struct Person *people[3]; // Array of structure pointers
for (int i = 0; i < 3; i++) {
people[i] = malloc(sizeof *people[i]);
if (!people[i]) {
// Clean up any previously allocated entries then exit
for (int j = 0; j < i; j++) free(people[j]);
fprintf(stderr, "Allocation failed\n");
return 1;
}
snprintf(people[i]->name, sizeof people[i]->name, "Person %d", i + 1);
people[i]->age = 20 + i;
}
for (int i = 0; i < 3; i++) {
printf("%s is %d years old.\n", people[i]->name, people[i]->age);
}
for (int i = 0; i < 3; i++) {
free(people[i]);
}
return 0;
}
Output
Person 1 is 20 years old. Person 2 is 21 years old. Person 3 is 22 years old.
ℹ️ Note: Use snprintf instead of sprintf to avoid buffer overflows; always free each allocated element.
Self-Referential Structures
Example
#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node *next; // Pointer to the same structure type
};
int main(void) {
struct Node *head = malloc(sizeof *head);
if (!head) return 1;
head->data = 10;
head->next = NULL;
struct Node *second = malloc(sizeof *second);
if (!second) { free(head); return 1; }
second->data = 20;
second->next = NULL;
head->next = second;
struct Node *current = head;
while (current != NULL) {
printf("%d -> ", current->data);
current = current->next;
}
printf("NULL\n");
// Properly free the whole list
current = head;
while (current) {
struct Node *next = current->next;
free(current);
current = next;
}
return 0;
}
Output
10 -> 20 -> NULL
ℹ️ Note: Self-referential structures are the foundation for data structures like linked lists, trees, and graphs.