@@ -4,12 +4,18 @@ name: C Flashcards
44
55---
66
7- Give a local variable a local lifetime.
7+ Infer a variable's type from its initializer (C23).
8+ Previously a no-op storage-class specifier for automatic lifetime.
89
910. . .
1011
1112` auto `
1213
14+ ``` c
15+ auto x = 5 ; // C23: x is int
16+ auto y = 3.14 ; // C23: y is double
17+ ```
18+
1319---
1420
1521Exit out of a compound statement.
@@ -148,7 +154,9 @@ A long integer data type.
148154
149155---
150156
151- Declare a variable to be stored in a CPU register.
157+ Hint that a variable should be stored in a CPU register.
158+ Vestigial: modern compilers ignore this and decide register allocation
159+ themselves. Its only remaining effect is forbidding ` & ` on the variable.
152160
153161. . .
154162
@@ -268,19 +276,24 @@ How does it look?
268276The ` main ` function.
269277
270278``` c
271- int main () {
279+ int main (void ) {
272280 // some code
273281}
274282```
275283
276- Or, more correctly (recent standard) :
284+ Or, when accepting command-line arguments :
277285
278286```c
279287int main(int argc, char *argv[]) {
280288 // some code
281289}
282290```
283291
292+ Note: write ` (void) ` rather than ` () ` for the no-argument form.
293+ In C17 and earlier, ` () ` means "unspecified parameters", not "no
294+ parameters". C23 finally makes them equivalent, but ` (void) ` is portable
295+ across all standards.
296+
284297---
285298
286299How is a variable declared?
@@ -296,6 +309,112 @@ double number;
296309char letter;
297310```
298311
312+ For integers where the exact width matters, prefer the fixed-width
313+ types from ` <stdint.h> ` (covered in a later card).
314+
315+ ---
316+
317+ When should I use ` <stdint.h> ` types like ` int32_t ` instead of ` int ` / ` long ` ?
318+
319+ . . .
320+
321+ The plain types (` int ` , ` long ` , ` long long ` ) have implementation-defined
322+ widths. On most 64-bit Unix systems ` long ` is 64 bits; on 64-bit Windows
323+ it's 32 bits. Use the fixed-width types when that difference matters:
324+
325+ - Binary protocols, file formats, wire formats
326+ - Hardware registers, memory-mapped I/O
327+ - Hashing, checksums, anywhere overflow semantics depend on exact width
328+ - Cross-platform code that must behave identically everywhere
329+
330+ ``` c
331+ #include < stdint.h>
332+
333+ int32_t signed_32bit;
334+ uint64_t unsigned_64bit;
335+
336+ // "at least N bits" — smallest type with ≥ N bits
337+ int_least16_t at_least_16;
338+
339+ // "fastest type with ≥ N bits" — often wider than asked, picked for speed
340+ int_fast32_t fast_counter;
341+ ```
342+
343+ Don't reach for them for ordinary loop counters or arithmetic — plain
344+ ` int ` is idiomatic and matches stdlib APIs. Overusing ` uint32_t ` is
345+ noise; using it for an array index on a 64-bit system is worse than
346+ ` size_t ` because it forces a truncation.
347+
348+ ---
349+
350+ What type should I use for sizes, array indices, and the result of ` sizeof ` ?
351+
352+ . . .
353+
354+ ` size_t ` (from ` <stddef.h> ` , also pulled in by ` <stdio.h> ` , ` <stdlib.h> ` ,
355+ ` <string.h> ` ). It's an unsigned type wide enough to represent the size
356+ of any object the platform supports — 32 bits on 32-bit systems, 64 bits
357+ on 64-bit systems.
358+
359+ ``` c
360+ #include < stddef.h>
361+ #include < string.h>
362+
363+ size_t len = strlen(" hello" ); // strlen returns size_t
364+ size_t n = sizeof (int ); // sizeof yields size_t
365+
366+ int arr[100 ];
367+ for (size_t i = 0 ; i < sizeof (arr) / sizeof (arr[0 ]); i++) {
368+ arr[ i] = 0;
369+ }
370+ ```
371+
372+ Related:
373+
374+ - ` ptrdiff_t ` — signed type for the difference between two pointers
375+ - ` ssize_t ` — POSIX signed counterpart to ` size_t ` (e.g. ` read ` , ` write `
376+ return values)
377+
378+ Don't substitute ` int ` , ` unsigned ` , or ` uint64_t ` here — APIs like
379+ ` strlen ` , ` memcpy ` , ` fread ` already use ` size_t ` , and mismatches cause
380+ warnings or silent truncation.
381+
382+ ---
383+
384+ How do I ` printf ` / ` scanf ` a fixed-width integer type portably?
385+
386+ . . .
387+
388+ You can't hardcode ` %d ` or ` %lld ` — the right specifier depends on
389+ what ` int64_t ` actually maps to on the target platform.
390+
391+ ` <inttypes.h> ` provides format-string macros: ` PRI ` for printf, ` SCN `
392+ for scanf, followed by the conversion letter (` d ` , ` i ` , ` u ` , ` x ` , ` o ` )
393+ and the width.
394+
395+ ``` c
396+ #include < inttypes.h>
397+ #include < stdint.h>
398+ #include < stdio.h>
399+
400+ int64_t big = 1234567890123 ;
401+ uint32_t small = 42 ;
402+
403+ printf ("big = %" PRId64 ", small = %" PRIu32 "\n", big, small);
404+
405+ uint64_t parsed;
406+ scanf("%" SCNu64, &parsed);
407+ ```
408+
409+ The macros are string literals, so adjacent-string-literal concatenation
410+ glues them into the format string at compile time. Common ones:
411+
412+ - `PRId32`, `PRIu32`, `PRIx64`, `PRIo16`
413+ - `SCNd32`, `SCNu64`
414+
415+ Including `<inttypes.h>` also includes `<stdint.h>`, so you don't need
416+ both.
417+
299418---
300419
301420How can the value of a variable be changed/stored?
@@ -319,9 +438,13 @@ Which function prints to the output screen (stdout)?
319438` printf `
320439
321440``` c
322- printf ("Hello World");
441+ printf ("Hello World\n ");
323442```
324443
444+ Include the trailing `\n` — without it, output may not be flushed
445+ before the program exits (stdout is line-buffered when attached to a
446+ terminal).
447+
325448---
326449
327450Why declare a function instead of just defining/implementing it?
@@ -360,15 +483,26 @@ How do I assign a new value to a char array/buffer?
360483
361484. . .
362485
363- Use ` strcpy(char *dest, char *src) ` .
364- Make sure ` dest ` has enough space to contain the source string.
486+ Prefer a bounded copy. ` strcpy ` doesn't check that ` dest ` has enough
487+ space and is a frequent source of buffer overflows — static analyzers
488+ and security guidelines (CERT, MISRA) flag unchecked uses.
489+
490+ Safer options:
365491
366492``` c
367- char bufArray[251 ];
368- char *oriText = " the quick fox" ;
369- strcpy (bufArray, oriText);
493+ char bufArray[256 ];
494+ const char *oriText = " the quick fox" ;
495+
496+ // snprintf is portable and always null-terminates:
497+ snprintf (bufArray, sizeof(bufArray), "%s", oriText);
498+
499+ // strlcpy (BSD, glibc 2.38+) also truncates safely:
500+ strlcpy(bufArray, oriText, sizeof(bufArray));
370501```
371502
503+ Avoid `strncpy` for this — it doesn't guarantee null-termination
504+ and pads with zeros up to the size limit.
505+
372506---
373507
374508What does the following code do?
@@ -418,6 +552,9 @@ Common operators:
418552Examples:
419553
420554``` c
555+ #include < stdbool.h> // needed for true/false/bool pre-C23
556+ // (C23 makes them keywords)
557+
421558if (true || false ) { … }
422559if (a == b) { … }
423560if (a != b) { … }
@@ -444,7 +581,7 @@ struct Person {
444581};
445582
446583struct Person myself; // uses Person as datatype
447- strcpy (myself.Name, "John");
584+ snprintf (myself.Name, sizeof(myself.Name), "%s" , "John");
448585myself.Age = 31;
449586```
450587
@@ -470,7 +607,7 @@ typedef struct Person FBProfile;
470607MyInteger a = 5 ;
471608
472609FBProfile guy;
473- strcpy (guy.Name, "Jack");
610+ snprintf (guy.Name, sizeof(guy.Name), "%s" , "Jack");
474611guy.Age = 15;
475612```
476613
@@ -482,19 +619,25 @@ How do I read a file?
482619
483620Include `stdio.h` and call `fopen` with the filename and read (`"r"`) mode
484621as parameters.
485- `fopen` returns a pointer to a `FILE` datatype.
486- Use this pointer to read or write.
622+ `fopen` returns a pointer to a `FILE` datatype, or `NULL` on failure.
487623
488- Use `fgets` to read a line.
489- Use `feof` to check if the end of the file has been reached.
624+ Loop on the return value of `fgets` — don't loop on `!feof(...)`.
625+ `feof` only becomes true *after* a failed read, so `while (!feof(fp))`
626+ runs the body one extra time with stale data. Checking `fgets` directly
627+ handles both EOF and read errors.
490628
491629```c
492- FILE *filepointer = fopen("C:\\input.txt", "r");
493- char tmpBuffer[251];
630+ FILE *filepointer = fopen("/tmp/input.txt", "r");
631+ if (filepointer == NULL) {
632+ perror("fopen");
633+ return 1;
634+ }
635+
636+ char tmpBuffer[256];
494637
495- while (!feof(filepointer)) { // loop while not end-of-file
496- // read 250 chars into tmpBuffer, or until a newline or end-of-file
497- fgets(tmpBuffer, 250, filepointer);
638+ // fgets returns NULL on EOF or error
639+ while (fgets(tmpBuffer, sizeof( tmpBuffer), filepointer) != NULL) {
640+ // process tmpBuffer
498641}
499642
500643fclose(filepointer); // close the file nicely for other applications
0 commit comments