Advanced C Language Pointers: Truly Connecting Functions and Structures with Pointers (Highly Practical)

⭐Advanced C Language Pointers: Truly Connecting Functions and Structures with Pointers (Highly Practical)

Author: IoT Smart Academy

In the previous articles, we have clarified three things:

  1. <span>&a</span> is the “address” of the variable.
  2. A pointer is a “variable that stores the address”: <span>int *p</span>
  3. Using <span>*p</span> allows us to find the original variable through its address and modify it.

We have also practiced with: <span>swap(&x, &y)</span>, zeroing arrays, and simple structure addition.

In this article, we will not introduce new concepts but will answer a key question:

In real small projects, when is it essential to use pointers to appear professional and practical?

We will illustrate this with two familiar scenarios:

  • Student Grade Management System
  • IoT Sensor Monitoring System

Let students see: “Oh, so pointers are used to ‘link’ functions and data structures together.”

1. First, let’s see where it feels “awkward” without using pointers.

First, let’s look at a function for “adding points to a student” (incorrect implementation):

#include <stdio.h>

typedef struct {
    int id;
    char name[20];
    float score;
} Student;

void addScoreWrong(Student s, float delta) { // ❌
    s.score += delta;
}

int main() {
    Student stu = {1001, "Zhang", 80};
    addScoreWrong(stu, 5);   // Passing a copy
    printf("Score: %.1f\n", stu.score);
    return 0;
}

The output is still 80.0 because:

  • <span>addScoreWrong</span> modifies the “copy of s”
  • The outer <span>stu</span> remains unchanged

“This is like making a copy of a report card and making changes to the copy, while the original remains untouched.”

At this point, we should ask: How can I actually modify stu?

2. Using Pointer Parameters: Turning “Copy Operations” into “Original Operations”

We follow the logic of <span>scanf("%d", &a);</span>:

  • <span>scanf</span> can modify <span>a</span> because you provided it with <span>&a</span>
  • Similarly, to modify <span>stu</span>, we need to pass its address.

✅ Correct Implementation: Structure Pointer Parameter

#include <stdio.h>

typedef struct {
    int id;
    char name[20];
    float score;
} Student;

void addScore(Student *s, float delta) {
    s->score += delta;  // Equivalent to (*s).score += delta;
}

int main() {
    Student stu = {1001, "Zhang", 80};

    printf("Before adding points: %.1f\n", stu.score);
    addScore(&stu, 5);      // Pass the address
    printf("After adding points: %.1f\n", stu.score);

    return 0;
}

Output:

Before adding points: 80.0
After adding points: 85.0

🧠 Breaking it down into three steps:

  1. <span>addScore(&stu, 5);</span> → Passes the address of <span>stu</span> to the function
  2. <span>Student *s</span><span>s</span> is a pointer that receives this address
  3. <span>s->score += delta;</span> → Modifies the “real student’s” score through this address

Mnemonic:

To allow a function to modify the “original structure”: Pass the address (<span>&</span>) + Pointer Parameter (<span>*</span>) + Use <span>-></span> to modify.

3. Pointer + Structure Array: The Most Common Usage in Projects

You have encountered this scenario before 👇

Scenario: A group of students, operating together

Student stu[100];
int count;

We will write a function to add points uniformly to all students:

void bonusAll(Student *s, int n, float delta) {
    for (int i = 0; i < n; i++) {
        s[i].score += delta;
    }
}

In <span>main</span>:

int main() {
    Student stu[3] = {
        {1001, "Zhang", 80},
        {1002, "Li", 85},
        {1003, "Wang", 90}
    };

    bonusAll(stu, 3, 2.0);  // Directly pass stu (array name)

    // Print results omitted
}

There are two key points here (very suitable for classroom explanation):

  1. The actual parameter passed is <span>stu</span> → Essentially the “address of the first element”
  2. The formal parameter is written as <span>Student *s</span> → Use <span>s[i]</span> as a normal array

“We did not copy all this student data around; we simply passed the address to the function, allowing it to operate in place, saving memory and appearing professional.”

4. From the IoT Perspective: Upgrading the Sensor Monitoring System to the “Pointer Professional Version”

We will use the structure from your previous article:

typedef struct {
    int id;
    char type[16];
    char location[32];
    float value;
} Sensor;

1️⃣ Write a function to update the reading of a specified device

void updateSensor(Sensor *s, float newValue) {
    s->value = newValue;
}

Usage:

Sensor a = {101, "Temp", "101room", 26.5};
updateSensor(&a, 30.2);

2️⃣ Write a function to find and update by ID (array + pointer combination)

void updateById(Sensor *arr, int n, int id, float newValue) {
    for (int i = 0; i < n; i++) {
        if (arr[i].id == id) {
            arr[i].value = newValue;
            printf("Updated: id=%d new value=%.2f\n", id, newValue);
            return;
        }
    }
    printf("Device with ID %d not found.\n", id);
}

In <span>main</span>:

Sensor s[3] = {
    {101, "Temp", "101room", 26.5},
    {102, "Temp", "Lab", 25.0},
    {103, "Smoke", "Hall", 0.1}
};

updateById(s, 3, 102, 27.8);

The explanation points are very simple:

  • <span>s</span> as the array name → Essentially still an address
  • <span>Sensor *arr</span> receives it, used like a normal array with <span>arr[i]</span>
  • All modifications happen on the original array → The data in the system is truly updated

“The structure defines ‘what each piece of data looks like’, while the pointer is responsible for ‘passing this data to the function for processing without copying a bunch’.”

5. When is it necessary or recommended to use pointers? Provide students with a clear judgment standard

This section is very suitable for making a “mind map” at the end of your post.

✅ Recommended Scenarios for Using Pointers (Passing Addresses)

  1. When the function needs to modify external variables / structures / arrays

  • <span>swap(&x, &y)</span>
  • <span>addScore(&stu, 5)</span>
  • <span>updateSensor(&device, newValue)</span>
  • When the data being passed is large, copying it is wasteful

    • Large arrays
    • Structure arrays
  • When a function needs to return more than one result

    • For example, if you need to return both the average and the maximum value → you can use pointer parameters to output results

    ⛔ Scenarios Where Pointers Are Not Necessary

    1. When you just want to “use” a value without needing to modify it

    • For example: <span>int add(int a, int b);</span>
  • For simple small structures, passed in as read-only without modification

  • When pointers complicate the logic without significant benefit

  • You can say very straightforwardly:

    “Not all functions need to use pointers. Pointers are a professional tool when you need to modify original data and avoid large copies.”

    6. Concise Mnemonic for “Pointers + Structures + Arrays”

    1. To modify, pass the address

    • <span>func(&x);</span>
    • <span>func(&stu);</span>
    • <span>func(stuArray, n); // Array name is the address</span>
  • On the function side: use pointers to receive

    • <span>void func(int *p)</span>
    • <span>void func(Student *s)</span>
    • <span>void func(Student *s, int n)</span>
  • Access Methods

    • For ordinary variable pointers: <span>*p</span>
    • For structure pointers: <span>s->id</span> / <span>(*s).id</span>
    • For array pointers: <span>a[i]</span> or <span>*(a+i)</span> both work
  • One-sentence version

    Structures manage “data format”, arrays manage “a bunch of data”, and pointers manage “who modifies this data”.

  • Leave a Comment