Three ways to pass a struct to a function:
1.
2.
3.
1.
void display(Student s) — pass by value — function gets a copy. Cannot change the original.2.
void update(Student *s) — pass by pointer — function can change the original.3.
Student create() — function returns a whole struct back to the caller.
dot operator — direct variable
Student s;
s.name = "Ananta"
s.marks = 88.5
display(s) ← pass copy
s.age = 18 ← direct access
s.name = "Ananta"
s.marks = 88.5
display(s) ← pass copy
s.age = 18 ← direct access
arrow operator — pointer to struct
Student *p = &s;
p->name = "Ananta"
p->marks = 88.5
display(p) ← pass pointer
p->age = 18 ← same as (*p).age
p->name = "Ananta"
p->marks = 88.5
display(p) ← pass pointer
p->age = 18 ← same as (*p).age
example 1
1
Pass a Struct to a Function — By Value
Function receives a copy — prints it — original is unchanged
Pass by value
The simplest way to use a struct with a function. Pass the whole struct to
display(). The function gets a copy — it can read the fields and print them, but any changes it makes do NOT affect the original in main.
#include <stdio.h> #include <string.h> typedef struct { char name[20]; int roll; float marks; } Student; /* receives a COPY of the struct */ void display(Student s) { printf("Name : %s\n", s.name); printf("Roll : %d\n", s.roll); printf("Marks : %.1f\n", s.marks); } int main() { Student s1 = {"Ananta", 101, 87.5}; Student s2 = {"Priya", 102, 92.0}; printf("--- Student 1 ---\n"); display(s1); printf("--- Student 2 ---\n"); display(s2); return 0; }
--- Student 1 --- Name : Ananta Roll : 101 Marks : 87.5 --- Student 2 --- Name : Priya Roll : 102 Marks : 92.0
display(s1) — the entire struct s1 is copied into the function's parameter s. All three fields are available inside the function using the dot operator.
example 2
2
Function Returns a Struct
create() builds a struct and sends it back to main
Return struct
A function can return a whole struct. The
create() function takes a name, roll, and marks — fills a local Student struct — and returns it. main receives the complete struct. This is the clean way to build a struct inside a function.
#include <stdio.h> #include <string.h> typedef struct { char name[20]; int roll; float marks; } Student; /* Function builds and RETURNS a struct */ Student create(char n[], int r, float m) { Student s; strcpy(s.name, n); s.roll = r; s.marks = m; return s; /* return the whole struct */ } void display(Student s) { printf("%s Roll:%d Marks:%.1f\n", s.name, s.roll, s.marks); } int main() { Student a = create("Ananta", 101, 87.5); Student b = create("Rahul", 103, 65.0); Student c = create("Sneha", 104, 95.0); display(a); display(b); display(c); return 0; }
Ananta Roll:101 Marks:87.5 Rahul Roll:103 Marks:65.0 Sneha Roll:104 Marks:95.0
example 3
3
Pointer to a Struct — The Arrow Operator
int *p points to int — Student *p points to Student
Pointer + struct
Just like
int *p = &x makes p point to an integer, Student *p = &s makes p point to a struct. To access fields through a pointer you use p->name instead of p.name. The arrow -> means "go to the struct this pointer points to, then access the field."
#include <stdio.h> typedef struct { char name[20]; int roll; float marks; } Student; int main() { Student s = {"Ananta", 101, 87.5}; Student *p = &s; /* p points to s */ /* Both ways give the same result */ printf("Using dot : %s %d %.1f\n", s.name, s.roll, s.marks); printf("Using arrow : %s %d %.1f\n", p->name, p->roll, p->marks); printf("Using (*p). : %s %d %.1f\n", (*p).name, (*p).roll, (*p).marks); printf("\np->marks is same as s.marks: %s\n", (p->marks == s.marks) ? "YES" : "NO"); return 0; }
Using dot : Ananta 101 87.5 Using arrow : Ananta 101 87.5 Using (*p). : Ananta 101 87.5 p->marks is same as s.marks: YES
p->marks is just shorthand for (*p).marks. Both do the same thing — go to the struct p points to and read the marks field. The arrow is cleaner to write and much easier to read.
example 4
4
Modify a Struct Through a Pointer
Pass &s to function — function changes the original using p->field
Modify via ptr
When you pass
&s to a function, the function receives a pointer and can change the original struct. This is pass by pointer — the same idea as with int pointers, just applied to a struct. The giveBonus() function adds 5 marks to the original student.
#include <stdio.h> typedef struct { char name[20]; float marks; } Student; /* Receives pointer — can change the ORIGINAL */ void giveBonus(Student *p, float bonus) { p->marks += bonus; /* changes the real struct */ printf("Bonus given to %s. New marks: %.1f\n", p->name, p->marks); } int main() { Student s = {"Rahul", 65.0}; printf("Before: %s = %.1f\n", s.name, s.marks); giveBonus(&s, 10.0); /* pass address of s */ printf("After : %s = %.1f\n", s.name, s.marks); return 0; }
Before: Rahul = 65.0 Bonus given to Rahul. New marks: 75.0 After : Rahul = 75.0
p->marks += bonus — the
-> goes to the actual struct in memory and updates it directly. After the function returns, s.marks in main is 75.0 — changed permanently.example 5
5
Dot vs Arrow — Side by Side
Same struct, same data — two ways to access depending on what you have
Dot vs Arrow
Simple rule: if you have the struct variable directly — use
. (dot). If you have a pointer to the struct — use -> (arrow). Two functions doing the same job — one takes the struct, one takes a pointer.
#include <stdio.h> typedef struct { char name[20]; int age; float salary; } Employee; /* Has the struct → uses dot */ void showDot(Employee e) { printf("[dot] %s age:%d Rs%.0f\n", e.name, e.age, e.salary); } /* Has a pointer → uses arrow */ void showArrow(Employee *e) { printf("[arrow] %s age:%d Rs%.0f\n", e->name, e->age, e->salary); } int main() { Employee emp = {"Ananta", 28, 45000}; showDot(emp); /* pass the struct */ showArrow(&emp); /* pass the address */ return 0; }
[dot] Ananta age:28 Rs45000 [arrow] Ananta age:28 Rs45000
Both produce the same output. The only difference is what you pass:
showDot(emp) copies the whole struct — showArrow(&emp) passes just the address (8 bytes on a 64-bit system). For large structs, passing a pointer is much faster than copying.example 6
6
Array of Structs — Passed to a Function
Pass the whole array to a display function — loop through with pointer
Array of structs
An array of structs is passed to a function as a pointer —
Student *arr inside the function refers to the whole array. Use arr[i].field inside the function to access each element. The size n is passed separately because the function doesn't know the array length.
#include <stdio.h> typedef struct { char name[20]; int roll; float marks; } Student; /* Array of structs passed as pointer */ void displayAll(Student *arr, int n) { int i; printf("%-10s %-6s %s\n", "Name", "Roll", "Marks"); printf("----------------------------\n"); for (i = 0; i < n; i++) { printf("%-10s %-6d %.1f\n", arr[i].name, arr[i].roll, arr[i].marks); } } int main() { Student s[4] = { {"Ananta", 101, 87.5}, {"Priya", 102, 92.0}, {"Rahul", 103, 65.5}, {"Sneha", 104, 95.0} }; displayAll(s, 4); /* array name = pointer to first element */ return 0; }
Name Roll Marks ---------------------------- Ananta 101 87.5 Priya 102 92.0 Rahul 103 65.5 Sneha 104 95.0
example 7
7
Grade Function — Takes Struct, Returns char
Function reads marks from struct and returns 'A', 'B', 'C', or 'F'
Return value
A function takes a Student struct, reads the marks field, and returns a grade character. Shows that a function receiving a struct can use its fields in any calculation and return a simple value.
#include <stdio.h> typedef struct { char name[20]; float marks; } Student; /* Takes struct, returns grade char */ char getGrade(Student s) { if (s.marks >= 90) return 'A'; else if (s.marks >= 75) return 'B'; else if (s.marks >= 55) return 'C'; else return 'F'; } int main() { Student students[4] = { {"Ananta", 87.5}, {"Priya", 92.0}, {"Rahul", 52.0}, {"Sneha", 95.0} }; int i; for (i = 0; i < 4; i++) { printf("%-10s %.1f Grade: %c\n", students[i].name, students[i].marks, getGrade(students[i])); } return 0; }
Ananta 87.5 Grade: B Priya 92.0 Grade: A Rahul 52.0 Grade: F Sneha 95.0 Grade: A
example 8
8
Find the Topper — Returns Pointer to Best Struct
Function scans array, returns Student* pointing to the topper
Return pointer
The function loops through the array, keeps track of the pointer to the best student, and returns that pointer. The caller uses
-> on the returned pointer to access the topper's details — no copying needed.
#include <stdio.h> typedef struct { char name[20]; int roll; float marks; } Student; /* Returns POINTER to the student with highest marks */ Student *findTopper(Student *arr, int n) { Student *top = &arr[0]; /* start: assume first is best */ int i; for (i = 1; i < n; i++) { if (arr[i].marks > top->marks) top = &arr[i]; /* point to new best */ } return top; } int main() { Student s[4] = { {"Ananta", 101, 87.5}, {"Priya", 102, 92.0}, {"Rahul", 103, 65.5}, {"Sneha", 104, 95.0} }; Student *top = findTopper(s, 4); printf("Topper : %s\n", top->name); printf("Roll : %d\n", top->roll); printf("Marks : %.1f\n", top->marks); return 0; }
Topper : Sneha Roll : 104 Marks : 95.0
start at index 1 because index 0 is already set as the starting best. The loop checks students 1, 2, 3 only — no need to compare student 0 against itself.
example 9
9
Update All Records — Pointer Loop Through Array
Function walks array with pointer — updates each struct in place
Update all
The
addBonus() function receives a pointer to the array and walks through each element using pointer increment p++. Since it has the actual addresses, every update is permanent — the marks in main change for real.
#include <stdio.h> typedef struct { char name[20]; float marks; } Student; void addBonus(Student *p, int n, float bonus) { int i; for (i = 0; i < n; i++) { p->marks += bonus; /* update through pointer */ p++; /* move to next struct */ } } void showAll(Student *p, int n) { int i; for (i = 0; i < n; i++) printf("%-10s %.1f\n", p[i].name, p[i].marks); } int main() { Student s[3] = { {"Ananta", 75.0}, {"Rahul", 58.0}, {"Priya", 88.0} }; printf("Before bonus:\n"); showAll(s, 3); addBonus(s, 3, 5.0); printf("After bonus:\n"); showAll(s, 3); return 0; }
Before bonus: Ananta 75.0 Rahul 58.0 Priya 88.0 After bonus: Ananta 80.0 Rahul 63.0 Priya 93.0
example 10 — mini project
🎓
Mini Project — Student Record System
5 functions · 5 students · input · display · grade · topper · average
A complete small program using everything from examples 1–9. Five functions, each doing one job. User enters 5 student records — the program displays them all with grades, finds the topper, and calculates the class average. This is the right way to build a real C program.
#include <stdio.h> #include <string.h> #define N 5 typedef struct { char name[20]; int roll; float marks; } Student; /* 1. Read one student from keyboard */ void readStudent(Student *p, int num) { printf("Student %d name : ", num); scanf("%s", p->name); printf("Roll number : "); scanf("%d", &p->roll); printf("Marks (out 100): "); scanf("%f", &p->marks); } /* 2. Get grade from marks */ char getGrade(Student s) { if (s.marks >= 90) return 'A'; else if (s.marks >= 75) return 'B'; else if (s.marks >= 55) return 'C'; else return 'F'; } /* 3. Display all students */ void displayAll(Student *arr, int n) { int i; printf("\n%-12s %-6s %-8s %s\n", "Name","Roll","Marks","Grade"); printf("--------------------------------\n"); for (i = 0; i < n; i++) { printf("%-12s %-6d %-8.1f %c\n", arr[i].name, arr[i].roll, arr[i].marks, getGrade(arr[i])); } } /* 4. Find and return pointer to topper */ Student *findTopper(Student *arr, int n) { Student *top = arr; int i; for (i = 1; i < n; i++) if (arr[i].marks > top->marks) top = &arr[i]; return top; } /* 5. Compute class average */ float classAverage(Student *arr, int n) { float total = 0; int i; for (i = 0; i < n; i++) total += arr[i].marks; return total / n; } /* ── main: input → display → topper → average ── */ int main() { Student students[N]; Student *top; int i; printf("=== Student Record System ===\n\n"); for (i = 0; i < N; i++) { readStudent(&students[i], i + 1); printf("\n"); } displayAll(students, N); top = findTopper(students, N); printf("\nTopper : %s (%.1f)\n", top->name, top->marks); printf("Class Avg : %.1f\n", classAverage(students, N)); return 0; }
=== Student Record System === Student 1 name : Ananta Roll number : 101 Marks (out 100): 87.5 Student 2 name : Priya Roll number : 102 Marks (out 100): 92.0 ... (3 more students) Name Roll Marks Grade -------------------------------- Ananta 101 87.5 B Priya 102 92.0 A Rahul 103 65.5 C Sneha 104 95.0 A Vikram 105 78.0 B Topper : Sneha (95.0) Class Avg : 83.6
Five functions, each does exactly one job:
readStudent() — input. getGrade() — grade. displayAll() — output. findTopper() — search. classAverage() — math. main() just calls them in order. This is the correct way to write real C programs.checklist
- Ex 1 — Pass struct by value: function(Student s) gets a copy — original unchanged
- Ex 2 — Function can return a whole struct: Student create(...) { return s; }
- Ex 3 — Student *p = &s makes p point to s — use p->field to access members
- Ex 4 — Pass &s to function — inside use p->marks to change the original
- Ex 5 — dot (.) for direct variable · arrow (->) for pointer to struct
- Ex 6 — Array of structs passed as Student *arr — access with arr[i].field
- Ex 7 — Function takes struct, returns char — getGrade(students[i]) in printf
- Ex 8 — findTopper returns Student* — caller uses top->name to access result
- Ex 9 — p++ moves pointer to next struct in array — updates each in place
- Ex 10 — Mini project: 5 functions, 5 students, each function does one job