Structs + Functions + Pointers — 10 Examples
0%
Structs  ·  Functions  ·  Pointers  ·  10 Examples

Structs + Functions + Pointers —
10 Programs

Ten focused programs that combine struct, function, and pointer in one place — passing structs by value, by pointer, returning structs, modifying fields through pointers, and more.

1
Pass by Value
2
Pass by Pointer
3
Return Struct
4
Update via Ptr
5
Array + Func
6
Swap Structs
7
Nested Struct
8
Ptr Arithmetic
9
Find Max
10
Complete Mini App
1
📋 Pass Struct to Function — By Value
A copy is made — original struct is never changed inside the function
Pass by Value
When you pass a struct to a function by value, C makes a complete copy. Any changes inside the function affect only the copy — the caller's original struct remains unchanged. Here display() receives a full copy of Student s and prints it. tryChange() changes the copy's marks — but back in main() the marks are still the original value.
ex1_pass_by_value.c
C
#include <stdio.h>

typedef struct {
    char  name[20];
    int   roll;
    float marks;
} Student;

/* Receives a COPY — original is untouched */
void display(Student s) {
    printf("Name  : %s\n",  s.name);
    printf("Roll  : %d\n",  s.roll);
    printf("Marks : %.1f\n", s.marks);
}

/* Tries to change marks — but only changes the local copy */
void tryChange(Student s) {
    s.marks = 0;   /* affects the copy only */
    printf("Inside tryChange — marks = %.1f\n", s.marks);
}

int main() {
    Student s = {"Ananta", 101, 88.5};

    printf("--- Before function call ---\n");
    display(s);

    tryChange(s);  /* pass by value — s is unchanged */

    printf("--- After tryChange() ---\n");
    printf("Marks in main : %.1f\n", s.marks); /* still 88.5 */
    return 0;
}
output
--- Before function call ---
Name  : Ananta
Roll  : 101
Marks : 88.5
Inside tryChange — marks = 0.0
--- After tryChange() ---
Marks in main : 88.5
Key rule: Pass by value = safe read-only. The function gets its own copy. Large structs passed by value every time are slow — use a pointer instead (next example).
example 2
2
📌 Pass Struct to Function — By Pointer
Pass the address — function modifies the original struct directly
Pass by Pointer
When you pass a pointer to a struct, the function works on the original — no copy is made. Use the arrow operator p->field to access members through a pointer. Here applyBonus() receives &emp and adds 500 to the original salary. The change is visible back in main().
ex2_pass_by_pointer.c
C
#include <stdio.h>

typedef struct {
    char   name[20];
    int    id;
    double salary;
} Employee;

/* Receives a POINTER — modifies the original */
void applyBonus(Employee *p, double bonus) {
    p->salary += bonus;   /* arrow operator: (*p).salary */
    printf("Bonus applied! New salary: %.2f\n", p->salary);
}

void displayEmp(Employee *p) {
    printf("ID     : %d\n",     p->id);
    printf("Name   : %s\n",     p->name);
    printf("Salary : %.2f\n", p->salary);
}

int main() {
    Employee emp = {"Priya", 1002, 32000.00};

    printf("--- Original ---\n");
    displayEmp(&emp);       /* pass address */

    applyBonus(&emp, 5000); /* modifies original */

    printf("--- After bonus ---\n");
    displayEmp(&emp);       /* shows updated salary */
    return 0;
}
output
--- Original ---
ID     : 1002
Name   : Priya
Salary : 32000.00
Bonus applied! New salary: 37000.00
--- After bonus ---
ID     : 1002
Name   : Priya
Salary : 37000.00
p->salary is shorthand for (*p).salary. Both do the same thing — dereference the pointer, then access the field. Arrow (->) is almost always preferred because it's cleaner to read.
example 3
3
🔁 Function Returns a Struct
Build a struct inside a function and return it to main
Return Struct
A function can return a struct — not just int or float. Here createStudent() takes name, roll, and marks as arguments, fills a local Student struct, assigns the grade, and returns the whole struct. In main() the returned struct is caught in a variable and printed. Clean, reusable object creation.
ex3_return_struct.c
C
#include <stdio.h>
#include <string.h>

typedef struct {
    char  name[20];
    int   roll;
    float marks;
    char  grade;
} Student;

/* Function returns a complete Student struct */
Student createStudent(char *nm, int roll, float marks) {
    Student s;
    strcpy(s.name, nm);
    s.roll  = roll;
    s.marks = marks;
    /* Assign grade */
    if      (marks >= 90) s.grade = 'A';
    else if (marks >= 75) s.grade = 'B';
    else if (marks >= 55) s.grade = 'C';
    else                   s.grade = 'F';
    return s;   /* return the whole struct */
}

void print(Student s) {
    printf("%-12s Roll:%d  Marks:%.1f  Grade:%c\n",
           s.name, s.roll, s.marks, s.grade);
}

int main() {
    /* Catch the returned struct in a variable */
    Student a = createStudent("Ananta", 101, 88.5);
    Student b = createStudent("Priya",  102, 93.0);
    Student c = createStudent("Rahul",  103, 52.0);

    printf("--- Student Cards ---\n");
    print(a);
    print(b);
    print(c);
    return 0;
}
output
--- Student Cards ---
Ananta       Roll:101  Marks:88.5  Grade:B
Priya        Roll:102  Marks:93.0  Grade:A
Rahul        Roll:103  Marks:52.0  Grade:F
Returning a struct from a function is perfectly valid in C. The struct is copied to the caller. This is the foundation of object-construction patterns — think of createStudent() like a constructor in other languages.
example 4
4
✏️ Update Struct Fields via Pointer
Functions that take struct pointer and change specific fields
Modify via Ptr
Multiple focused functions each accept a Point* or Rectangle* and modify one or more fields. setPoint() sets coordinates, scale() multiplies the dimensions, area() reads without modifying (marked const). This is the C equivalent of member functions — small functions that operate on a struct through a pointer.
ex4_update_via_ptr.c
C
#include <stdio.h>

typedef struct { float x; float y; } Point;
typedef struct { float w; float h; } Rect;

/* Set both fields via pointer */
void setPoint(Point *p, float x, float y) {
    p->x = x;
    p->y = y;
}

/* Move point by offset */
void movePoint(Point *p, float dx, float dy) {
    p->x += dx;
    p->y += dy;
}

/* Scale rectangle — modifies w and h */
void scaleRect(Rect *r, float factor) {
    r->w *= factor;
    r->h *= factor;
}

/* Read-only — const pointer, won't modify */
float areaRect(const Rect *r) {
    return r->w * r->h;
}

int main() {
    Point p;
    setPoint(&p, 3.0, 4.0);
    printf("Point : (%.1f, %.1f)\n", p.x, p.y);

    movePoint(&p, 2.0, -1.0);
    printf("Moved : (%.1f, %.1f)\n", p.x, p.y);

    Rect r = {10.0, 5.0};
    printf("\nRect  : %.1f x %.1f  area=%.1f\n",
           r.w, r.h, areaRect(&r));

    scaleRect(&r, 2.0);
    printf("Scaled: %.1f x %.1f  area=%.1f\n",
           r.w, r.h, areaRect(&r));
    return 0;
}
output
Point : (3.0, 4.0)
Moved : (5.0, 3.0)

Rect  : 10.0 x 5.0  area=50.0
Scaled: 20.0 x 10.0  area=200.0
const Rect *r means "pointer to a Rect I promise not to modify." The compiler will error if you try to assign to r->w inside that function. Use it for read-only functions — documents intent and prevents bugs.
example 5
5
📊 Array of Structs Passed to Function
Pass entire array to functions — display, find average, find topper
Array + Func
An array of structs passed to a function decays to a pointer to its first element — just like a plain array. Three functions all take Student arr[], int n: one prints all records, one computes the average marks, one finds and returns a pointer to the topper. The pointer return from findTopper() lets us access all the topper's fields directly.
ex5_array_to_func.c
C
#include <stdio.h>

typedef struct {
    char  name[20];
    float marks;
} Student;

void printAll(Student arr[], int n) {
    printf("%-12s %s\n", "Name", "Marks");
    printf("-------------------\n");
    for (int i = 0; i < n; i++)
        printf("%-12s %.1f\n", arr[i].name, arr[i].marks);
}

float average(Student arr[], int n) {
    float sum = 0;
    for (int i = 0; i < n; i++)
        sum += arr[i].marks;
    return sum / n;
}

/* Returns a POINTER to the topper inside the array */
Student* findTopper(Student arr[], int n) {
    int top = 0;
    for (int i = 1; i < n; i++)
        if (arr[i].marks > arr[top].marks) top = i;
    return &arr[top];   /* pointer to the actual element */
}

int main() {
    Student batch[] = {
        {"Ananta", 88.5},
        {"Priya",  95.0},
        {"Rahul",  72.0},
        {"Sneha",  91.5}
    };
    int n = 4;

    printAll(batch, n);

    printf("\nAverage  : %.2f\n", average(batch, n));

    Student *top = findTopper(batch, n);
    printf("Topper   : %s (%.1f)\n", top->name, top->marks);
    return 0;
}
output
Name         Marks
-------------------
Ananta       88.5
Priya        95.0
Rahul        72.0
Sneha        91.5

Average  : 86.75
Topper   : Priya (95.0)
Student *top = findTopper(...) — the returned pointer points directly into the batch array. So top->name and top->marks access the actual element, not a copy. Efficient: no struct is ever duplicated.
example 6
6
🔄 Swap Two Structs Using Pointers
Classic swap via temporary variable — on whole structs using pointers
Swap via Ptr
The classic swap pattern extended to entire structs. swapStudents() receives two Student* pointers and uses a temporary Student variable to exchange all fields at once. Without pointers, the swap would be local only — the original variables would be unchanged.
ex6_swap.c
C
#include <stdio.h>

typedef struct {
    char  name[20];
    int   roll;
    float marks;
} Student;

void print(Student *s) {
    printf("  %-10s roll=%-4d marks=%.1f\n",
           s->name, s->roll, s->marks);
}

/* Swap the entire struct contents via pointers */
void swapStudents(Student *a, Student *b) {
    Student temp = *a;  /* copy all fields of *a into temp */
    *a = *b;            /* copy all fields of *b into *a   */
    *b = temp;          /* copy temp into *b               */
}

int main() {
    Student s1 = {"Ananta", 101, 88.5};
    Student s2 = {"Priya",  102, 95.0};

    printf("Before swap:\n");
    printf("s1: "); print(&s1);
    printf("s2: "); print(&s2);

    swapStudents(&s1, &s2);

    printf("\nAfter swap:\n");
    printf("s1: "); print(&s1);
    printf("s2: "); print(&s2);
    return 0;
}
output
Before swap:
s1:   Ananta     roll=101  marks=88.5
s2:   Priya      roll=102  marks=95.0

After swap:
s1:   Priya      roll=102  marks=95.0
s2:   Ananta     roll=101  marks=88.5
Student temp = *a; — the * dereferences the pointer, giving you the full struct value. Assignment on structs copies every field at once. This one-line swap idiom works on any struct of any size.
example 7
7
🏠 Nested Struct — Address Inside Person
Struct inside a struct — pass outer struct pointer, access inner fields
Nested Struct
A Person struct contains an Address struct as one of its fields. When the outer struct is passed by pointer, inner fields are reached by chaining the dot or arrow operator: p->addr.city. updateCity() changes only the city inside the nested struct without touching any other field.
ex7_nested_struct.c
C
#include <stdio.h>
#include <string.h>

typedef struct {
    char city[20];
    char state[20];
    int  pin;
} Address;

typedef struct {
    char    name[20];
    int     age;
    Address addr;           /* nested struct */
} Person;

void displayPerson(const Person *p) {
    printf("Name  : %s (age %d)\n", p->name, p->age);
    printf("City  : %s\n", p->addr.city);   /* arrow then dot */
    printf("State : %s\n", p->addr.state);
    printf("PIN   : %d\n", p->addr.pin);
}

/* Update only the city inside the nested struct */
void updateCity(Person *p, char *newCity, int newPin) {
    strcpy(p->addr.city, newCity);
    p->addr.pin = newPin;
}

int main() {
    Person per = {
        "Ananta", 21,
        {"Haridwar", "Uttarakhand", 249401}
    };

    printf("--- Original ---\n");
    displayPerson(&per);

    updateCity(&per, "Dehradun", 248001);

    printf("\n--- After updateCity() ---\n");
    displayPerson(&per);
    return 0;
}
output
--- Original ---
Name  : Ananta (age 21)
City  : Haridwar
State : Uttarakhand
PIN   : 249401

--- After updateCity() ---
Name  : Ananta (age 21)
City  : Dehradun
State : Uttarakhand
PIN   : 248001
Access pattern for nested structs via pointer: p->addr.city means — follow pointer p (arrow), reach addr (which is a plain struct, not a pointer), then access city (dot). Arrow then dot.
example 8
8
⬆️ Pointer Arithmetic on Struct Array
Walk an array of structs using a pointer — increment the pointer each step
Ptr Arithmetic
A pointer to a struct array can be incremented just like an int pointer. p++ advances by sizeof(Product) bytes — landing on the next struct. This is exactly how the compiler implements arr[i] internally. Both the index method and the pointer method produce identical output — they compile to the same machine code.
ex8_ptr_arithmetic.c
C
#include <stdio.h>

typedef struct {
    char  name[20];
    float price;
    int   qty;
} Product;

/* Walk array using index — traditional */
void printByIndex(Product arr[], int n) {
    printf("--- Index method ---\n");
    for (int i = 0; i < n; i++)
        printf("%-12s Rs%.2f  qty=%d\n",
               arr[i].name, arr[i].price, arr[i].qty);
}

/* Walk array using pointer arithmetic */
void printByPointer(Product *p, int n) {
    printf("--- Pointer method ---\n");
    for (int i = 0; i < n; i++, p++) /* p++ = move to next struct */
        printf("%-12s Rs%.2f  qty=%d\n",
               p->name, p->price, p->qty);
}

int main() {
    Product shop[] = {
        {"Rice",   60.0, 100},
        {"Oil",   180.0,  50},
        {"Sugar",  45.0, 200}
    };
    int n = 3;

    printByIndex(shop, n);
    printf("\n");
    printByPointer(shop, n);

    /* Pointer arithmetic demo */
    Product *p = shop;
    printf("\nAddress of shop[0] : %p\n", (void*)p);
    printf("Address of shop[1] : %p\n", (void*)(p+1));
    printf("Difference         : %zu bytes (= sizeof Product)\n",
           (char*)(p+1) - (char*)p);
    return 0;
}
output
--- Index method ---
Rice         Rs60.00  qty=100
Oil          Rs180.00  qty=50
Sugar        Rs45.00  qty=200

--- Pointer method ---
Rice         Rs60.00  qty=100
Oil          Rs180.00  qty=50
Sugar        Rs45.00  qty=200

Address of shop[0] : 0x7ffce1b0
Address of shop[1] : 0x7ffce1cc
Difference         : 28 bytes (= sizeof Product)
Why 28 bytes? char name[20] = 20 bytes, float price = 4 bytes, int qty = 4 bytes. Total = 28 bytes. p++ skips exactly 28 bytes — jumping to the start of the next Product in memory.
example 9
9
🏅 Return Pointer to Max Struct in Array
Function scans array, returns pointer to the highest-salary employee
Return Ptr
findHighestPaid() takes an array and size, scans all employees, and returns a Employee* pointing to the one with the highest salary. The caller gets a pointer directly into the array — no copy. Change best->salary and the real array element changes too. Shows why returning pointers is both powerful and requires care.
ex9_return_ptr.c
C
#include <stdio.h>

typedef struct {
    char   name[20];
    char   dept[15];
    double salary;
} Employee;

/* Returns pointer to the highest-paid employee */
Employee* findHighestPaid(Employee *arr, int n) {
    Employee *best = &arr[0];
    for (int i = 1; i < n; i++)
        if (arr[i].salary > best->salary)
            best = &arr[i];
    return best;   /* pointer into the array — no copy */
}

void printAll(Employee *arr, int n) {
    printf("%-12s %-12s %10s\n", "Name", "Dept", "Salary");
    printf("--------------------------------------\n");
    for (int i = 0; i < n; i++)
        printf("%-12s %-12s %10.2f\n",
               arr[i].name, arr[i].dept, arr[i].salary);
}

int main() {
    Employee team[] = {
        {"Ananta",  "Engineering", 55000},
        {"Priya",   "Design",      62000},
        {"Rahul",   "Marketing",   48000},
        {"Sneha",   "Engineering", 71000},
        {"Vikram",  "HR",          39000}
    };
    int n = 5;

    printAll(team, n);

    Employee *best = findHighestPaid(team, n);
    printf("\n🏅 Highest paid: %s (%s) — Rs %.2f\n",
           best->name, best->dept, best->salary);

    /* Modifying through returned pointer changes the real array */
    best->salary += 10000;
    printf("After raise: %s now earns Rs %.2f\n",
           best->name, best->salary);
    return 0;
}
output
Name         Dept            Salary
--------------------------------------
Ananta       Engineering    55000.00
Priya        Design         62000.00
Rahul        Marketing      48000.00
Sneha        Engineering    71000.00
Vikram       HR             39000.00

🏅 Highest paid: Sneha (Engineering) — Rs 71000.00
After raise: Sneha now earns Rs 81000.00
Warning: Never return a pointer to a local variable inside a function — that memory is gone after the function returns. Here we return a pointer into the team[] array which lives in main() — perfectly safe.
example 10
10
🏪 Mini Student Management — Complete Program
All concepts together — add, display, update marks, find topper
Complete App
Everything combined: struct definition, createStudent() returns a struct, displayAll() takes array + size, updateMarks() takes a pointer and modifies in place, getTopper() returns a pointer to the best. A real mini application that uses every technique from examples 1–9 in one cohesive program.
ex10_mini_app.c
C
#include <stdio.h>
#include <string.h>
#define MAX 5

typedef struct {
    char  name[20];
    int   roll;
    float marks;
    char  grade;
} Student;

/* 1. Factory function — returns a struct */
Student makeStudent(char *nm, int roll, float marks) {
    Student s;
    strcpy(s.name, nm);
    s.roll  = roll;
    s.marks = marks;
    s.grade = (marks>=90)?'A':(marks>=75)?'B':(marks>=55)?'C':'F';
    return s;
}

/* 2. Display all — struct array by pointer */
void displayAll(Student *arr, int n) {
    printf("\n%-12s %5s %7s %6s\n","Name","Roll","Marks","Grade");
    printf("-----------------------------------\n");
    for (int i = 0; i < n; i++, arr++)     /* pointer walk */
        printf("%-12s %5d %7.1f %6c\n",
               arr->name, arr->roll, arr->marks, arr->grade);
}

/* 3. Update marks by pointer — modifies original */
void updateMarks(Student *s, float newMarks) {
    s->marks = newMarks;
    s->grade = (newMarks>=90)?'A':(newMarks>=75)?'B':(newMarks>=55)?'C':'F';
}

/* 4. Find topper — returns pointer into array */
Student* getTopper(Student *arr, int n) {
    Student *top = arr;
    for (int i = 1; i < n; i++)
        if ((arr+i)->marks > top->marks)
            top = arr + i;
    return top;
}

int main() {
    Student db[MAX];
    db[0] = makeStudent("Ananta", 101, 88.5);
    db[1] = makeStudent("Priya",  102, 73.0);
    db[2] = makeStudent("Rahul",  103, 91.5);
    db[3] = makeStudent("Sneha",  104, 58.0);
    db[4] = makeStudent("Vikram", 105, 45.0);

    printf("=== Initial Records ===");
    displayAll(db, MAX);

    /* Update Priya's marks via pointer */
    updateMarks(&db[1], 95.0);
    printf("\n=== After updating Priya's marks to 95.0 ===");
    displayAll(db, MAX);

    /* Find and print topper */
    Student *top = getTopper(db, MAX);
    printf("\n🏆 Topper: %s | Marks: %.1f | Grade: %c\n",
           top->name, top->marks, top->grade);
    return 0;
}
output
=== Initial Records ===
Name          Roll   Marks  Grade
-----------------------------------
Ananta         101    88.5      B
Priya          102    73.0      C
Rahul          103    91.5      A
Sneha          104    58.0      C
Vikram         105    45.0      F

=== After updating Priya's marks to 95.0 ===
Name          Roll   Marks  Grade
-----------------------------------
Ananta         101    88.5      B
Priya          102    95.0      A
Rahul          103    91.5      A
Sneha          104    58.0      C
Vikram         105    45.0      F

🏆 Topper: Priya | Marks: 95.0 | Grade: A
All four patterns in one program: makeStudent() returns a struct · displayAll() reads via pointer walk · updateMarks() modifies via pointer · getTopper() returns a pointer to an element. This is how real C programs are structured.
checklist
  • Ex 1 — Pass by value makes a copy. Changes inside the function don't affect the original.
  • Ex 2 — Pass &struct so the function can modify the original. Use p->field inside.
  • Ex 3 — A function can return a whole struct. Assign it: Student s = createStudent(...);
  • Ex 4 — const Rect *r = read-only pointer. Compiler prevents accidental modification.
  • Ex 5 — An array of structs decays to a pointer. Return &arr[i] to point to a specific element.
  • Ex 6 — Swap with Student temp = *a; *a = *b; *b = temp; — copies all fields at once.
  • Ex 7 — Nested struct access via pointer: p->addr.city (arrow then dot).
  • Ex 8 — p++ on a struct pointer moves by sizeof(struct) bytes — lands on the next element.
  • Ex 9 — Return a pointer into an array, not a local variable. Local variables die when function returns.
  • Ex 10 — Factory (return struct) + display (ptr walk) + update (ptr modify) + find (return ptr) in one program.