#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Opaque structs prevent modification because the caller cannot see the fields
// const variable — prevents modification of a value
// pointer to const — data immutable
// const pointer — pointer immutable
// fully immutable pointer — both immutable
// opaque structs — strongest immutability
// const in APIs (functions) — enforce read‑only access
// Forward declaration (opaque type)
typedef struct User User;
// Only allow creation, read-only access, and freeing
const User* create_user(int id, const char *name);
int get_user_id(const User *u);
const char* get_user_name(const User *u);
void free_user(const User *u);
// Internal struct definition (hidden from user)
struct User {
int id;
char name[16];
};
const User* create_user(int id, const char *name) {
User *u = malloc(sizeof(User));
if (!u) {
return NULL; // allocation failed
}
u->id = id;
// Copy name safely into fixed-size buffer
strncpy(u->name, name, sizeof(u->name) - 1);
u->name[sizeof(u->name) - 1] = '\0'; // ensure null-termination
return u; // returned as const pointer (immutable to caller)
}
int get_user_id(const User *u) {
return u->id;
}
const char* get_user_name(const User *u) {
return u->name;
}
void free_user(const User *u) {
// Cast away const because we know we allocated it internally
free((void*)u);
}
int main() {
const User *u = create_user(42, "Tom");
if (!u) {
printf("Memory allocation failed\n");
return 1;
}
printf("User ID: %d\n", get_user_id(u));
printf("User Name: %s\n", get_user_name(u));
// u->id = 123; // ERROR: incomplete type prevents access
// u = NULL; // allowed: pointer itself is not const here
free_user(u); // free memory safely
return 0;
}
/*
run:
User ID: 42
User Name: Tom
*/