Structures in C Programming
Structures are user-defined data types that allow you to group related variables of different data types under a single name. They provide a way to create complex data types that can represent real-world entities with multiple attributes, making your programs more organized and easier to manage.
Key Takeaways
- Structures group related variables of different data types into a single unit
- Members of a structure are accessed using the dot (.) operator
- Structures can be nested and used in arrays
- Structure pointers use the arrow (->) operator to access members
- Structures help in organizing code and creating complex data models
What Are Structures?
A structure is a collection of variables (called members or fields) that are logically related and grouped together under one name. Unlike arrays that store elements of the same data type, structures can contain elements of different data types.
Think of a structure as a blueprint for creating a custom data type. For example, to represent a student, you might need to store their name, age, ID number, and GPA. Instead of creating separate variables for each piece of information, you can group them all into a single structure.
Without Structures
1char student_name[50];2int student_age;3int student_id;4float student_gpa;56char employee_name[50];7int employee_age;8int employee_id;9float employee_salary;
Scattered variables, hard to manage and organize
With Structures
1struct Student {2 char name[50];3 int age;4 int id;5 float gpa;6};78struct Student student1, student2;
Organized, reusable, and easier to maintain
Declaring Structures
To create a structure, you use the struct
keyword followed by a structure name and a list of member variables enclosed in curly braces.
Basic Syntax
1struct structure_name {2 data_type member1;3 data_type member2;4 // ... more members5};
Don't forget the semicolon after the closing brace when declaring a structure. This is a common source of compilation errors.
Example: Student Structure
1struct Student {2 char name[50]; // Student's name3 int age; // Student's age4 int id; // Student ID number5 float gpa; // Grade Point Average6 char grade; // Letter grade7};
Creating Structure Variables
After declaring a structure, you can create variables of that structure type:
1// Method 1: Declare variables after structure definition2struct Student student1, student2, student3;34// Method 2: Declare variables along with structure definition5struct Student {6 char name[50];7 int age;8 int id;9 float gpa;10} student1, student2;1112// Method 3: Using typedef (recommended)13typedef struct {14 char name[50];15 int age;16 int id;17 float gpa;18} Student;1920Student student1, student2; // No need for 'struct' keyword
Accessing Structure Members
Structure members are accessed using the dot (.) operator, also known as the member access operator. The syntax is: structure_variable.member_name
Example: Basic Member Access
1#include <stdio.h>2#include <string.h>34struct Student {5 char name[50];6 int age;7 int id;8 float gpa;9};1011int main() {12 struct Student student1;1314 // Assigning values to structure members15 strcpy(student1.name, "Alice Johnson");16 student1.age = 20;17 student1.id = 12345;18 student1.gpa = 3.85;1920 // Accessing and displaying structure members21 printf("Student Information:\n");22 printf("Name: %s\n", student1.name);23 printf("Age: %d\n", student1.age);24 printf("ID: %d\n", student1.id);25 printf("GPA: %.2f\n", student1.gpa);2627 return 0;28}2930// Output:31// Student Information:32// Name: Alice Johnson33// Age: 2034// ID: 1234535// GPA: 3.85
Structure Initialization
Structures can be initialized in several ways when they are declared or after declaration.
Initialization at Declaration
1#include <stdio.h>23struct Point {4 int x;5 int y;6};78int main() {9 // Method 1: Initialize all members in order10 struct Point p1 = {10, 20};1112 // Method 2: Designated initializers (C99 and later)13 struct Point p2 = {.x = 30, .y = 40};14 struct Point p3 = {.y = 50, .x = 60}; // Order doesn't matter1516 // Method 3: Partial initialization (remaining members set to 0)17 struct Point p4 = {100}; // x = 100, y = 01819 // Method 4: Zero initialization20 struct Point p5 = {0}; // Both x and y are 021 struct Point p6 = {}; // Same as above (C++ style, some C compilers support)2223 printf("p1: (%d, %d)\n", p1.x, p1.y);24 printf("p2: (%d, %d)\n", p2.x, p2.y);25 printf("p3: (%d, %d)\n", p3.x, p3.y);26 printf("p4: (%d, %d)\n", p4.x, p4.y);27 printf("p5: (%d, %d)\n", p5.x, p5.y);2829 return 0;30}3132// Output:33// p1: (10, 20)34// p2: (30, 40)35// p3: (60, 50)36// p4: (100, 0)37// p5: (0, 0)
Complex Structure Initialization
1#include <stdio.h>23struct Employee {4 char name[30];5 int id;6 float salary;7 char department[20];8};910int main() {11 // Initialize with all values12 struct Employee emp1 = {13 "John Smith",14 1001,15 55000.50,16 "Engineering"17 };1819 // Using designated initializers20 struct Employee emp2 = {21 .name = "Jane Doe",22 .id = 1002,23 .salary = 62000.75,24 .department = "Marketing"25 };2627 printf("Employee 1: %s, ID: %d, Salary: $%.2f, Dept: %s\n",28 emp1.name, emp1.id, emp1.salary, emp1.department);29 printf("Employee 2: %s, ID: %d, Salary: $%.2f, Dept: %s\n",30 emp2.name, emp2.id, emp2.salary, emp2.department);3132 return 0;33}
Arrays of Structures
You can create arrays of structures to store multiple records of the same type. This is particularly useful when working with collections of similar data.
Example: Student Database
1#include <stdio.h>2#include <string.h>34struct Student {5 char name[50];6 int rollNo;7 float marks;8};910int main() {11 struct Student students[3];12 int i;1314 // Input student data15 for (i = 0; i < 3; i++) {16 printf("Enter details for student %d:\n", i + 1);17 printf("Name: ");18 scanf("%s", students[i].name);19 printf("Roll Number: ");20 scanf("%d", &students[i].rollNo);21 printf("Marks: ");22 scanf("%f", &students[i].marks);23 printf("\n");24 }2526 // Display student data27 printf("\n--- Student Records ---\n");28 for (i = 0; i < 3; i++) {29 printf("Student %d:\n", i + 1);30 printf(" Name: %s\n", students[i].name);31 printf(" Roll No: %d\n", students[i].rollNo);32 printf(" Marks: %.2f\n", students[i].marks);33 printf("\n");34 }3536 // Find student with highest marks37 int topStudent = 0;38 for (i = 1; i < 3; i++) {39 if (students[i].marks > students[topStudent].marks) {40 topStudent = i;41 }42 }4344 printf("Top performer: %s with %.2f marks\n",45 students[topStudent].name, students[topStudent].marks);4647 return 0;48}
Initializing Arrays of Structures
1#include <stdio.h>23struct Book {4 char title[50];5 char author[30];6 int pages;7 float price;8};910int main() {11 // Initialize array of structures12 struct Book library[3] = {13 {"The C Programming Language", "Kernighan & Ritchie", 274, 45.99},14 {"Data Structures in C", "Tanenbaum", 456, 39.95},15 {"Algorithms in C", "Robert Sedgewick", 672, 54.50}16 };1718 printf("Library Catalog:\n");19 printf("%-30s %-20s %6s %8s\n", "Title", "Author", "Pages", "Price");20 printf("%-30s %-20s %6s %8s\n", "-----", "------", "-----", "-----");2122 for (int i = 0; i < 3; i++) {23 printf("%-30s %-20s %6d $%7.2f\n",24 library[i].title, library[i].author,25 library[i].pages, library[i].price);26 }2728 return 0;29}
Nested Structures
A structure can contain other structures as members. This is called nesting and allows you to create more complex data models that represent hierarchical relationships.
Example: Address within Person
1#include <stdio.h>2#include <string.h>34// Define the Address structure5struct Address {6 char street[100];7 char city[50];8 char state[30];9 int zipCode;10};1112// Define the Person structure with nested Address13struct Person {14 char name[50];15 int age;16 struct Address address; // Nested structure17 char phone[15];18};1920int main() {21 struct Person person1;2223 // Assign values to the person24 strcpy(person1.name, "Robert Johnson");25 person1.age = 35;26 strcpy(person1.phone, "555-1234");2728 // Assign values to the nested address structure29 strcpy(person1.address.street, "123 Main Street");30 strcpy(person1.address.city, "New York");31 strcpy(person1.address.state, "NY");32 person1.address.zipCode = 10001;3334 // Display the information35 printf("Person Information:\n");36 printf("Name: %s\n", person1.name);37 printf("Age: %d\n", person1.age);38 printf("Phone: %s\n", person1.phone);39 printf("Address:\n");40 printf(" Street: %s\n", person1.address.street);41 printf(" City: %s\n", person1.address.city);42 printf(" State: %s\n", person1.address.state);43 printf(" ZIP Code: %d\n", person1.address.zipCode);4445 return 0;46}
Complex Nested Structure Example
1struct Date {2 int day;3 int month;4 int year;5};67struct Employee {8 char name[50];9 int empId;10 struct Date birthDate;11 struct Date joiningDate;12 struct Address workAddress;13 float salary;14};1516// Accessing nested structure members17struct Employee emp;18emp.birthDate.day = 15;19emp.birthDate.month = 6;20emp.birthDate.year = 1990;2122// Display nested data23printf("Birth Date: %d/%d/%d\n",24 emp.birthDate.day, emp.birthDate.month, emp.birthDate.year);
Structure Pointers
Like other data types, you can create pointers to structures. Structure pointers are especially useful for dynamic memory allocation and passing structures efficiently to functions.
Declaring and Using Structure Pointers
1#include <stdio.h>2#include <stdlib.h>3#include <string.h>45struct Student {6 char name[50];7 int age;8 float gpa;9};1011int main() {12 struct Student student1 = {"Alice", 20, 3.8};13 struct Student *ptr;1415 // Point to the structure16 ptr = &student1;1718 // Method 1: Access using (*ptr).member19 printf("Using (*ptr).member syntax:\n");20 printf("Name: %s\n", (*ptr).name);21 printf("Age: %d\n", (*ptr).age);22 printf("GPA: %.2f\n", (*ptr).gpa);2324 // Method 2: Access using ptr->member (arrow operator)25 printf("\nUsing ptr->member syntax:\n");26 printf("Name: %s\n", ptr->name);27 printf("Age: %d\n", ptr->age);28 printf("GPA: %.2f\n", ptr->gpa);2930 // Modifying values through pointer31 ptr->age = 21;32 ptr->gpa = 3.9;3334 printf("\nAfter modification:\n");35 printf("Age: %d\n", student1.age);36 printf("GPA: %.2f\n", student1.gpa);3738 return 0;39}
Arrow Operator (->))
The arrow operator (->) is a shorthand for (*ptr).member. It makes code more readable when working with structure pointers. Use ptr->
instead of (*ptr).member
.
Dynamic Memory Allocation for Structures
1#include <stdio.h>2#include <stdlib.h>3#include <string.h>45struct Employee {6 char name[50];7 int id;8 float salary;9};1011int main() {12 struct Employee *emp;13 int n, i;1415 printf("Enter number of employees: ");16 scanf("%d", &n);1718 // Allocate memory for n employees19 emp = (struct Employee*)malloc(n * sizeof(struct Employee));2021 if (emp == NULL) {22 printf("Memory allocation failed!\n");23 return 1;24 }2526 // Input employee data27 for (i = 0; i < n; i++) {28 printf("\nEmployee %d:\n", i + 1);29 printf("Name: ");30 scanf("%s", (emp + i)->name); // or emp[i].name31 printf("ID: ");32 scanf("%d", &(emp + i)->id); // or &emp[i].id33 printf("Salary: ");34 scanf("%f", &(emp + i)->salary); // or &emp[i].salary35 }3637 // Display employee data38 printf("\n--- Employee Records ---\n");39 for (i = 0; i < n; i++) {40 printf("Employee %d: %s, ID: %d, Salary: $%.2f\n",41 i + 1, emp[i].name, emp[i].id, emp[i].salary);42 }4344 // Free allocated memory45 free(emp);4647 return 0;48}
Structures and Functions
Structures can be passed to functions in several ways: by value, by reference (using pointers), or by returning them from functions.
Passing Structures by Value
1#include <stdio.h>23struct Rectangle {4 float length;5 float width;6};78// Function that takes structure by value9float calculateArea(struct Rectangle rect) {10 return rect.length * rect.width;11}1213// Function that takes structure by value and returns modified structure14struct Rectangle scaleRectangle(struct Rectangle rect, float factor) {15 rect.length *= factor;16 rect.width *= factor;17 return rect;18}1920int main() {21 struct Rectangle rect1 = {10.5, 6.2};2223 printf("Original rectangle: %.2f x %.2f\n", rect1.length, rect1.width);24 printf("Area: %.2f\n", calculateArea(rect1));2526 struct Rectangle scaledRect = scaleRectangle(rect1, 2.0);27 printf("Scaled rectangle: %.2f x %.2f\n", scaledRect.length, scaledRect.width);28 printf("Original after function call: %.2f x %.2f\n", rect1.length, rect1.width);2930 return 0;31}3233// Output:34// Original rectangle: 10.50 x 6.2035// Area: 65.1036// Scaled rectangle: 21.00 x 12.4037// Original after function call: 10.50 x 6.20
Passing Structures by Reference (Pointer)
1#include <stdio.h>2#include <string.h>34struct Student {5 char name[50];6 int age;7 float gpa;8};910// Function that modifies structure through pointer11void updateGPA(struct Student *student, float newGPA) {12 student->gpa = newGPA;13 printf("Updated %s's GPA to %.2f\n", student->name, student->gpa);14}1516// Function that displays student info17void displayStudent(const struct Student *student) {18 printf("Student: %s, Age: %d, GPA: %.2f\n",19 student->name, student->age, student->gpa);20}2122// Function that creates and returns a structure23struct Student createStudent(char name[], int age, float gpa) {24 struct Student newStudent;25 strcpy(newStudent.name, name);26 newStudent.age = age;27 newStudent.gpa = gpa;28 return newStudent;29}3031int main() {32 struct Student student1 = {"Bob Wilson", 19, 3.2};3334 printf("Before update:\n");35 displayStudent(&student1);3637 updateGPA(&student1, 3.7);3839 printf("After update:\n");40 displayStudent(&student1);4142 // Create new student using function43 struct Student student2 = createStudent("Carol Davis", 21, 3.9);44 displayStudent(&student2);4546 return 0;47}
Performance Consideration
Passing large structures by value can be inefficient as it creates a copy of the entire structure. For large structures, consider passing by pointer to improve performance.
Using typedef with Structures
The typedef
keyword can make working with structures more convenient by creating type aliases, eliminating the need to use the struct
keyword repeatedly.
1#include <stdio.h>23// Method 1: typedef with named structure4struct Point {5 int x;6 int y;7};8typedef struct Point Point;910// Method 2: typedef with anonymous structure (more common)11typedef struct {12 char name[50];13 int age;14 float salary;15} Employee;1617// Method 3: typedef with structure name and alias in one declaration18typedef struct Car {19 char make[30];20 char model[30];21 int year;22 float price;23} Car;2425int main() {26 // Using typedef makes declarations cleaner27 Point p1 = {10, 20}; // No need for 'struct'28 Employee emp1 = {"John Doe", 30, 50000.0};29 Car car1 = {"Toyota", "Camry", 2023, 25000.0};3031 printf("Point: (%d, %d)\n", p1.x, p1.y);32 printf("Employee: %s, Age: %d, Salary: $%.2f\n",33 emp1.name, emp1.age, emp1.salary);34 printf("Car: %d %s %s, Price: $%.2f\n",35 car1.year, car1.make, car1.model, car1.price);3637 return 0;38}
Memory Layout of Structures
Understanding how structures are stored in memory can help you write more efficient code and avoid potential issues with structure padding and alignment.
Structure Padding and Alignment
1#include <stdio.h>23struct Example1 {4 char a; // 1 byte5 int b; // 4 bytes6 char c; // 1 byte7};89struct Example2 {10 char a; // 1 byte11 char c; // 1 byte12 int b; // 4 bytes13};1415struct Example3 {16 int b; // 4 bytes17 char a; // 1 byte18 char c; // 1 byte19};2021int main() {22 printf("Size of char: %zu bytes\n", sizeof(char));23 printf("Size of int: %zu bytes\n", sizeof(int));24 printf("\n");2526 printf("Size of Example1: %zu bytes\n", sizeof(struct Example1));27 printf("Size of Example2: %zu bytes\n", sizeof(struct Example2));28 printf("Size of Example3: %zu bytes\n", sizeof(struct Example3));2930 // Demonstrating memory addresses31 struct Example1 ex1;32 printf("\nMemory layout of Example1:\n");33 printf("Address of ex1: %p\n", (void*)&ex1);34 printf("Address of ex1.a: %p\n", (void*)&ex1.a);35 printf("Address of ex1.b: %p\n", (void*)&ex1.b);36 printf("Address of ex1.c: %p\n", (void*)&ex1.c);3738 return 0;39}404142// Typical output (may vary by system):43// Size of char: 1 bytes44// Size of int: 4 bytes45//46// Size of Example1: 12 bytes47// Size of Example2: 8 bytes48// Size of Example3: 8 bytes4950// Demonstrating offsetof macro51#include <stddef.h>5253printf("54Offset of members in Example1:55");56printf("Offset of a: %zu57", offsetof(struct Example1, a));58printf("Offset of b: %zu59", offsetof(struct Example1, b));60printf("Offset of c: %zu61", offsetof(struct Example1, c));6263return 0;64}6566// Packed structures (compiler-specific)67#pragma pack(1) // or __attribute__((packed)) for GCC68struct PackedExample {69 char a;70 int b;71 char c;72};73#pragma pack() // Reset to default alignment7475// Usage example with packed structure76printf("77Packed structure size: %zu bytes78", sizeof(struct PackedExample));
1## Real-World Examples23### Example 1: Library Management System456#include <stdio.h>7#include <string.h>8#include <stdlib.h>910typedef struct {11 int bookId;12 char title[100];13 char author[50];14 char isbn[20];15 int availableCopies;16 float price;17} Book;1819typedef struct {20 int memberId;21 char name[50];22 char email[50];23 int booksIssued;24} Member;2526// Function to display book information27void displayBook(const Book *book) {28 printf("ID: %d29", book->bookId);30 printf("Title: %s31", book->title);32 printf("Author: %s33", book->author);34 printf("ISBN: %s35", book->isbn);36 printf("Available: %d copies37", book->availableCopies);38 printf("Price: $%.2f39", book->price);40 printf("------------------------41");42}4344// Function to search for a book by title45int searchBookByTitle(Book books[], int count, const char *title) {46 for (int i = 0; i < count; i++) {47 if (strcmp(books[i].title, title) == 0) {48 return i;49 }50 }51 return -1;52}5354int main() {55 Book library[3] = {56 {1, "The C Programming Language", "Kernighan & Ritchie", "978-0131103627", 5, 45.99},57 {2, "Data Structures and Algorithms", "Cormen", "978-0262033848", 3, 89.95},58 {3, "Operating System Concepts", "Silberschatz", "978-1118063330", 2, 79.50}59 };6061 printf("=== Library Management System ===6263");6465 // Display all books66 printf("Available Books:67");68 for (int i = 0; i < 3; i++) {69 displayBook(&library[i]);70 }7172 // Search for a specific book73 char searchTitle[100];74 printf("Enter book title to search: ");75 fgets(searchTitle, sizeof(searchTitle), stdin);76 searchTitle[strcspn(searchTitle, "77")] = 0; // Remove newline7879 int index = searchBookByTitle(library, 3, searchTitle);80 if (index != -1) {81 printf("82Book found:83");84 displayBook(&library[index]);85 } else {86 printf("87Book not found in library.88");89 }9091 return 0;92}9394### Example 2: Student Grade Management959697#include <stdio.h>98#include <string.h>99100#define MAX_SUBJECTS 5101#define MAX_STUDENTS 50102103typedef struct {104 char name[30];105 int marks;106 char grade;107} Subject;108109typedef struct {110 int studentId;111 char name[50];112 Subject subjects[MAX_SUBJECTS];113 int subjectCount;114 float totalMarks;115 float percentage;116 char overallGrade;117} Student;118119// Function to calculate grade based on marks120char calculateGrade(int marks) {121 if (marks >= 90) return 'A';122 else if (marks >= 80) return 'B';123 else if (marks >= 70) return 'C';124 else if (marks >= 60) return 'D';125 else return 'F';126}127128// Function to calculate student's overall performance129void calculateOverallPerformance(Student *student) {130 int totalMarks = 0;131132 for (int i = 0; i < student->subjectCount; i++) {133 totalMarks += student->subjects[i].marks;134 student->subjects[i].grade = calculateGrade(student->subjects[i].marks);135 }136137 student->totalMarks = totalMarks;138 student->percentage = (float)totalMarks / (student->subjectCount * 100) * 100;139 student->overallGrade = calculateGrade((int)student->percentage);140}141142// Function to display student report143void displayStudentReport(const Student *student) {144 printf("145=== Student Report Card ===146");147 printf("Student ID: %d148", student->studentId);149 printf("Name: %s150", student->name);151 printf("152Subject-wise Performance:153");154 printf("%-20s %-10s %-10s155", "Subject", "Marks", "Grade");156 printf("%-20s %-10s %-10s157", "-------", "-----", "-----");158159 for (int i = 0; i < student->subjectCount; i++) {160 printf("%-20s %-10d %-10c161",162 student->subjects[i].name,163 student->subjects[i].marks,164 student->subjects[i].grade);165 }166167 printf("168Overall Performance:169");170 printf("Total Marks: %.0f/%d171", student->totalMarks, student->subjectCount * 100);172 printf("Percentage: %.2f%%173", student->percentage);174 printf("Overall Grade: %c175", student->overallGrade);176}177178int main() {179 Student student1;180181 // Initialize student data182 student1.studentId = 101;183 strcpy(student1.name, "Alice Johnson");184 student1.subjectCount = 5;185186 // Initialize subjects and marks187 strcpy(student1.subjects[0].name, "Mathematics");188 student1.subjects[0].marks = 85;189190 strcpy(student1.subjects[1].name, "Physics");191 student1.subjects[1].marks = 78;192193 strcpy(student1.subjects[2].name, "Chemistry");194 student1.subjects[2].marks = 92;195196 strcpy(student1.subjects[3].name, "English");197 student1.subjects[3].marks = 88;198199 strcpy(student1.subjects[4].name, "Computer Science");200 student1.subjects[4].marks = 95;201202 // Calculate overall performance203 calculateOverallPerformance(&student1);204205 // Display report206 displayStudentReport(&student1);207208 return 0;209}210211212## Common Pitfalls and Best Practices213214### Memory Management215216// DON'T: Return pointer to local structure217struct Point* createPoint(int x, int y) {218 struct Point p = {x, y}; // Local variable219 return &p; // ERROR: Returns pointer to local variable220}221222// DO: Use dynamic allocation or pass by parameter223struct Point* createPoint(int x, int y) {224 struct Point *p = malloc(sizeof(struct Point));225 if (p != NULL) {226 p->x = x;227 p->y = y;228 }229 return p;230}231232233### Structure Comparison234235// DON'T: Compare structures directly236struct Point p1 = {10, 20};237struct Point p2 = {10, 20};238239// if (p1 == p2) { ... } // ERROR: Cannot compare structures directly240241// DO: Compare member by member or use memcmp242int comparePoints(const struct Point *p1, const struct Point *p2) {243 return (p1->x == p2->x && p1->y == p2->y);244}245246// Or using memcmp (be careful with padding)247int result = memcmp(&p1, &p2, sizeof(struct Point));