βPractical Guide to C Language Pointers: Upgraded IoT Sensor Monitoring System (Menu + Structs + Pointers + Sorting + Alarms)
Author: IoT Smart Academy
This article skips the concepts and directly dives into the project: integrating “structs + arrays + pointers” to create an upgraded sensor monitoring system that can be demonstrated in class and easily replicated by students.
Features:
- All functionalities are implemented using pointer parameters for modifications
- Supports add/view/update/delete/filter/sort/statistics/batch calibration
- The code is single-file runnable, suitable for Dev-C++ / VS / Linux g++ environments
π§ Overview of System Functions (Menu)
- 1 Add Sensor
- 2 Show All
- 3 Query by ID
- 4 Update Reading by ID (Pointer Modification)
- 5 Delete Device by ID (Array Shift)
- 6 Filter by Type (Temp/Humi/Smokeβ¦)
- 7 Filter Alarms by Threshold (β₯threshold)
- 8 Sort by Reading in Descending Order (Pointer Swap Structs)
- 9 Statistics for Min/Max/Average
- 10 Batch Calibration (All Readings +offset)
- 0 Exit
π» Complete Runnable Code (Copy and Use)
#include <stdio.h>
#include <string.h>
#define MAX_SENSOR 200
typedef struct {
int id; // ID
char type[16]; // Type: Temp/Humi/Smoke/β¦
char location[32]; // Location: Room101/Lab/β¦
float value; // Current Reading
} Sensor;
typedef struct {
Sensor arr[MAX_SENSOR];
int count; // Current Device Count
} SensorDB;
/* ββ Function Declarations ββ */
void initDB(SensorDB *db);
void addSensors(SensorDB *db);
void showAll(const SensorDB *db);
Sensor* findById(SensorDB *db, int id);
void updateById(SensorDB *db);
void deleteById(SensorDB *db);
void filterByType(const SensorDB *db);
void filterByThreshold(const SensorDB *db);
void sortByValueDesc(SensorDB *db);
void statistics(const SensorDB *db);
void batchCalibrate(SensorDB *db);
int menu();
/* ββ Main Program ββ */
int main() {
SensorDB db;
initDB(&db);
while (1) {
switch (menu()) {
case 1: addSensors(&db); break;
case 2: showAll(&db); break;
case 3: {
int id;
printf("Please enter the ID to query:");
scanf("%d", &id);
Sensor *p = findById(&db, id);
if (p) {
printf("Found: id=%d type=%s loc=%s value=%.2f\n",
p->id, p->type, p->location, p->value);
} else {
printf("Device with ID %d not found.\n", id);
}
} break;
case 4: updateById(&db); break;
case 5: deleteById(&db); break;
case 6: filterByType(&db); break;
case 7: filterByThreshold(&db); break;
case 8: sortByValueDesc(&db); break;
case 9: statistics(&db); break;
case 10: batchCalibrate(&db); break;
case 0:
printf("System exited, goodbye!\n");
return 0;
default:
printf("Invalid option, please try again.\n");
}
}
}
/* ββ Menu ββ */
int menu() {
int c;
printf("\n===== Upgraded IoT Sensor Monitoring System =====\n");
printf("1. Add Sensor\n");
printf("2. Show All\n");
printf("3. Query by ID\n");
printf("4. Update Reading by ID\n");
printf("5. Delete Device by ID\n");
printf("6. Filter by Type\n");
printf("7. Filter Alarms by Threshold (>=)\n");
printf("8. Sort by Reading Descending\n");
printf("9. Statistics for Min/Max/Average\n");
printf("10. Batch Calibration (+offset)\n");
printf("0. Exit\n");
printf("=====================================\n");
printf("Please enter an option:");
scanf("%d", &c);
return c;
}
/* ββ Initialize Database ββ */
void initDB(SensorDB *db) {
db->count = 0;
}
/* ββ Add Sensors ββ */
void addSensors(SensorDB *db) {
int n;
printf("Please enter the number of sensors to add:");
scanf("%d", &n);
if (n <= 0) { printf("Number must be greater than 0.\n"); return; }
if (db->count + n > MAX_SENSOR) {
printf("Insufficient capacity, can add %d more.\n", MAX_SENSOR - db->count);
return;
}
for (int i = 0; i < n; i++) {
Sensor s;
printf("Please enter (id type location value):\n");
printf("Example: 101 Temp Room101 26.5\n");
scanf("%d %15s %31s %f", &s.id, s.type, s.location, &s.value);
db->arr[db->count++] = s;
}
printf("Added, current device count: %d\n", db->count);
}
/* ββ Show All (Read-Only, using const pointer) ββ */
void showAll(const SensorDB *db) {
if (db->count == 0) { printf("No data available.\n"); return; }
printf("\nID\tType\tLocation\t Value\n");
for (int i = 0; i < db->count; i++) {
printf("%d\t%-5s\t%-16s\t%.2f\n",
db->arr[i].id, db->arr[i].type, db->arr[i].location, db->arr[i].value);
}
}
/* ββ Find by ID (returns pointer for subsequent modification) ββ */
Sensor* findById(SensorDB *db, int id) {
for (int i = 0; i < db->count; i++) {
if (db->arr[i].id == id) return &db->arr[i];
}
return NULL;
}
/* ββ Update Reading (Pointer Modification of Original Data) ββ */
void updateById(SensorDB *db) {
int id; float v;
printf("Please enter ID and new reading (id value):");
scanf("%d %f", &id, &v);
Sensor *p = findById(db, id);
if (p) {
p->value = v; // Direct modification via pointer
printf("Updated: id=%d new value=%.2f\n", id, p->value);
} else {
printf("Device with ID %d not found.\n", id);
}
}
/* ββ Delete (by ID, subsequent elements shift) ββ */
void deleteById(SensorDB *db) {
if (db->count == 0) { printf("No data available.\n"); return; }
int id, pos = -1;
printf("Please enter the ID to delete:");
scanf("%d", &id);
for (int i = 0; i < db->count; i++) {
if (db->arr[i].id == id) { pos = i; break; }
}
if (pos == -1) { printf("ID %d not found.\n", id); return; }
for (int i = pos; i < db->count - 1; i++) db->arr[i] = db->arr[i + 1];
db->count--;
printf("Deleted ID %d, current device count: %d\n", id, db->count);
}
/* ββ Filter by Type (Read-Only) ββ */
void filterByType(const SensorDB *db) {
if (db->count == 0) { printf("No data available.\n"); return; }
char t[16]; int found = 0;
printf("Please enter type (e.g., Temp/Humi/Smoke):");
scanf("%15s", t);
printf("\n=== Devices of type %s ===\n", t);
for (int i = 0; i < db->count; i++) {
if (strcmp(db->arr[i].type, t) == 0) {
printf("%d\t%-5s\t%-16s\t%.2f\n",
db->arr[i].id, db->arr[i].type, db->arr[i].location, db->arr[i].value);
found = 1;
}
}
if (!found) printf("No devices of this type found.\n");
}
/* ββ Filter by Threshold (Read-Only) ββ */
void filterByThreshold(const SensorDB *db) {
if (db->count == 0) { printf("No data available.\n"); return; }
float th; int found = 0;
printf("Please enter threshold (show devices with >= threshold):");
scanf("%f", &th);
printf("\n=== Devices with >= %.2f ===\n", th);
for (int i = 0; i < db->count; i++) {
if (db->arr[i].value >= th) {
printf("%d\t%-5s\t%-16s\t%.2f\n",
db->arr[i].id, db->arr[i].type, db->arr[i].location, db->arr[i].value);
found = 1;
}
}
if (!found) printf("No devices above threshold.\n");
}
/* ββ Sort by Reading in Descending Order (Pointer Swap Structs) ββ */
void sortByValueDesc(SensorDB *db) {
if (db->count <= 1) { printf("Insufficient data, no need to sort.\n"); return; }
for (int i = 0; i < db->count - 1; i++) {
for (int j = 0; j < db->count - 1 - i; j++) {
if (db->arr[j].value < db->arr[j + 1].value) {
Sensor tmp = db->arr[j];
db->arr[j] = db->arr[j + 1];
db->arr[j + 1] = tmp;
}
}
}
printf("Sorted by reading in descending order.\n");
showAll(db);
}
/* ββ Statistics ββ */
void statistics(const SensorDB *db) {
if (db->count == 0) { printf("No data available.\n"); return; }
float min = db->arr[0].value, max = db->arr[0].value, sum = 0.0f;
for (int i = 0; i < db->count; i++) {
if (db->arr[i].value < min) min = db->arr[i].value;
if (db->arr[i].value > max) max = db->arr[i].value;
sum += db->arr[i].value;
}
printf("Device Count: %d\nMin: %.2f\nMax: %.2f\nAverage: %.2f\n",
db->count, min, max, sum / db->count);
}
/* ββ Batch Calibration (All Readings +offset) ββ */
void batchCalibrate(SensorDB *db) {
if (db->count == 0) { printf("No data available.\n"); return; }
float offset;
printf("Please enter calibration offset (e.g., +0.5 or -0.5):");
scanf("%f", &offset);
for (int i = 0; i < db->count; i++) {
db->arr[i].value += offset;
}
printf("Batch calibrated (offset=%.2f).\n", offset);
showAll(db);
}
πͺ How to Teach in Class, “Both Professional and Not Intimidating”
-
All functions that modify data: parameters are either pointers or wrapped “database” with pointers (
<span>SensorDB *db</span>)Memory Tip: To modify, you need to provide the address; functions use pointers to modify in place.
-
Read-only functions: parameters use
<span>const SensorDB *db</span>, clearly indicating “read-only, no modification”, more professional. -
Deletion Logic: after finding the position, “shift and cover”, no dynamic memory, suitable for introductory courses.
-
Sorting/Statistics: reuse previously learned bubble sort and max/min/avg templates, but change the objects to struct arrays.
-
**
<span>findById</span>returns<span>Sensor*</span>: can directly use<span>p->value=...</span>, experiencing the power of “direct modification via pointers”.
π§ͺ Suggested Test Cases for Class (Live Demonstration by Teacher)
1 Add Number=4
101 Temp Room101 26.5
102 Temp Lab 27.8
201 Humi Store 60.2
301 Smoke Hall 0.12
2 Show All
7 Threshold=27.0
6 Type=Temp
4 Update: id=201 New Value=65.0
8 Sort (Descending)
9 Statistics
10 Batch Calibration: offset=-0.5
5 Delete: id=301
2 Show All
Students can visually see:Data has indeed been “modified in place”.
π§± Homework (Step-by-Step, All Based on This Code)
- Add:Sort by ID (ascending) and display.
- Add:Filter by ID (location contains substring).
- Add:Export devices above threshold to array B (return count), experiencing “pointers + return count”.
- Add:Statistics for average value of each type (Temp/Humi/Smoke respectively).
- Consider: Saving/Loading
<span>SensorDB</span>to/from disk (text or simple binary), forming a “small system with persistence”.
π§© One-Screen Command Card (For Students)
- To modify, pass the address:
<span>func(&x)</span><span> / </span><code><span>func(db)</span><span> (struct pointer)</span> - Function uses pointers:
<span>void func(SensorDB *db)</span> - Access struct pointer:
<span>p->value</span><span> (equivalent to </span><code><span>(*p).value</span><span>)</span> - Array is base address:
<span>arr</span>can be passed, inside function<span>arr[i]</span>/<span>*(arr+i)</span><span> both work</span> - Read-only parameters add
<span>const</span><span>, comes with a "safety sign"</span>