| name | c |
| description | Language-specific super-code guidelines for c. |
| risk | safe |
| source | community |
| date_added | 2026-06-16 |
C: Idiomatic Efficiency Reference
Table of Contents
- Memory Management
- Pointers & Arrays
- Error Handling
- Strings
- Structs & Enums
- Preprocessor & Headers
- Anti-patterns specific to C
1. Memory Management {#memory}
char *buf = malloc(size);
strcpy(buf, src);
char *buf = malloc(size);
if (!buf) return -ENOMEM;
memcpy(buf, src, size);
int *p = (int *)malloc(n * sizeof(int));
int *p = malloc(n * sizeof *p);
free(ptr);
free(ptr);
ptr = NULL;
char *a = malloc(100);
char *b = malloc(200);
if (!b) return -1;
char *a = NULL, *b = NULL;
a = malloc(100);
if (!a) goto cleanup;
b = malloc(200);
if (!b) goto cleanup;
cleanup:
free(b);
free(a);
Use sizeof *ptr instead of sizeof(Type) — it stays correct when the type changes.
2. Pointers & Arrays {#pointers}
void process(int *arr, int len) { ... }
process(data, 10);
typedef struct { int *data; size_t len; } IntSlice;
*(arr + i) = value;
arr[i] = value;
int arr[n];
int *arr = malloc(n * sizeof *arr);
if (!arr) return -ENOMEM;
free(arr);
3. Error Handling {#errors}
if (do_thing() == -1) { ... }
#include <errno.h>
if (do_thing() < 0) {
perror("do_thing");
return errno;
}
int r1 = step1();
if (r1 == 0) {
int r2 = step2();
if (r2 == 0) {
int r3 = step3();
}
}
if (step1() < 0) goto fail;
if (step2() < 0) goto fail;
if (step3() < 0) goto fail;
return 0;
fail:
cleanup();
return -1;
goto cleanup is idiomatic C for resource teardown — don't avoid it out of principle.
4. Strings {#strings}
strcpy(dest, src);
strncpy(dest, src, sizeof(dest) - 1);
dest[sizeof(dest) - 1] = '\0';
if (str == "hello") { ... }
if (strcmp(str, "hello") == 0) { ... }
char result[1024] = "";
for (int i = 0; i < n; i++) {
strcat(result, items[i]);
}
char result[1024];
int pos = 0;
for (int i = 0; i < n && pos < (int)sizeof(result); i++) {
pos += snprintf(result + pos, sizeof(result) - pos, "%s", items[i]);
}
Prefer snprintf over sprintf — always.
5. Structs & Enums {#structs}
struct point { int x, y; };
struct point p = {1, 2};
typedef struct { int x, y; } Point;
Point p = {1, 2};
Point p;
use(p.x);
Point p = {0};
if (state == 3) { ... }
typedef enum { STATE_IDLE, STATE_RUNNING, STATE_DONE } State;
if (state == STATE_DONE) { ... }
6. Preprocessor & Headers {#preprocessor}
#define MAX(a, b) ((a) > (b) ? (a) : (b))
MAX(x++, y)
static inline int max_int(int a, int b) { return a > b ? a : b; }
struct Foo { int x; };
#ifndef MY_HEADER_H
#define MY_HEADER_H
struct Foo { int x; };
#endif
Keep macros for conditional compilation and constants. Use static inline for logic.
7. Anti-patterns specific to C {#antipatterns}
| Anti-pattern | Preferred |
|---|
sprintf | snprintf with buffer size |
gets | fgets (gets is removed in C11) |
Casting malloc result | let implicit void* conversion work |
sizeof(Type) in malloc | sizeof *ptr |
| VLA for large/runtime arrays | heap allocation |
void* callbacks without context param | pass void *ctx alongside function pointer |
| Global mutable state | pass state through struct pointers |
assert for runtime error handling | proper error return codes |
Missing const on read-only pointer params | const char *str |
| Mixing signed/unsigned in comparisons | use consistent types, cast explicitly |
Limitations
- These are language-specific guidelines and do not cover overall architectural decisions.
- Over-compression might reduce readability; apply judgement.