๐ 24. C Standard Library Essentials
Use the standard library for common tasks such as converting text, sorting values, copying bytes, and reading files. Each example below shows the required header, a complete program, and the result to check.
24.1 The C Standard Library Map
A header supplies the declarations, types, and macros for a group of facilities. Include the header that specifies the function you use; knowing its name is not enough. Library function definitions are supplied by the C implementation.
Important points:
- stdio.h โ streams and formatted I/O; stdlib.h โ allocation, conversion, sorting and utilities; string.h โ byte strings; ctype.h โ character classification; math.h โ mathematics; time.h โ dates and clocks; errno.h โ error codes; assert.h โ checks; limits.h, stdint.h and inttypes.h โ integer properties.
24.2 Math Functions with math.h
Use sqrt for a square root, fabs for floating-point absolute value, and floor or ceil for downward or upward rounding. The unsuffixed versions shown use double. Versions such as sqrtf and sqrtl work with float and long double. Some toolchains also need -lm when linking.
Complete C program:
#include <stdio.h>
#include <math.h>
int main(void)
{
printf("sqrt(81) = %.1f\n", sqrt(81.0));
printf("ceil(2.3) = %.1f\n", ceil(2.3));
printf("fabs(-5.5) = %.1f\n", fabs(-5.5));
return 0;
}
Expected output:
sqrt(81) = 9.0
ceil(2.3) = 3.0
fabs(-5.5) = 5.5
Step-by-step explanation:
- sqrt finds the nonnegative square root.
- ceil(2.3) gives the floating-point value 3.0; it does not return an int. floor(2.3) would give 2.0.
- fabs computes the absolute magnitude of a floating value.
24.3 Character Classification with ctype.h
Classify one byte value at a time with functions such as isdigit or isspace. If a value comes from a char variable, cast it to unsigned char before passing it. An int returned by fgetc must retain its EOF check before being treated as a character.
Complete C program:
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char text[] = "C Lab 7";
for (int i = 0; text[i] != '\0'; ++i)
if (isdigit((unsigned char)text[i]))
printf("Digit: %c\n", text[i]);
return 0;
}
Expected output:
Digit: 7
Step-by-step explanation:
- The loop visits each character until the null terminator.
- isdigit tests each byte.
- Only the digit is printed.
24.4 Conversions with strtol and strtod
strtol converts a numeric prefix to long, while strtod converts one to double. Both supply an end pointer showing where they stopped. Use that pointer and the documented range-error checks to decide whether the whole input is acceptable.
Complete C program:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char *end;
double amount = strtod("12.50kg", &end);
printf("Amount = %.2f\n", amount);
printf("Unit = %s\n", end);
return 0;
}
Expected output:
Amount = 12.50
Unit = kg
Step-by-step explanation:
- strtod converts the initial numeric portion of the string.
- end points to the unconverted suffix kg.
- This demonstration deliberately keeps the suffix kg. A parser that expects only a number should also reject an unwanted suffix, detect no conversion, and check the documented range errors.
24.5 Sorting Arrays with qsort
qsort sorts an array using a comparison function you supply. Give it the array address, element count, and size of one element. The comparison resultโs sign indicates less, equal, or greater. Equal elements are not guaranteed to keep their original relative order.
Complete C program:
#include <stdio.h>
#include <stdlib.h>
int compareInts(const void *pa, const void *pb)
{
int a = *(const int *)pa, b = *(const int *)pb;
return (a > b) - (a < b);
}
int main(void)
{
int nums[] = {9, 2, 7, 1};
qsort(nums, 4, sizeof nums[0], compareInts);
for (size_t i = 0; i < 4; ++i) printf("%d ", nums[i]);
putchar('\n');
return 0;
}
Expected output:
1 2 7 9
Step-by-step explanation:
- qsort invokes compareInts to compare elements.
- The comparator avoids subtraction, which could overflow.
- The expression (a > b) - (a < b) produces -1, 0, or 1 without the overflow that a - b can cause for large opposite-signed values.
24.6 Searching a Sorted Array with bsearch
Before calling bsearch, sort the elements into the order used by its comparison function. It returns a pointer to a match or NULL. Searching unsorted data with it does not give a reliable answer.
Complete C program:
#include <stdio.h>
#include <stdlib.h>
int cmp(const void *a, const void *b)
{
int x = *(const int *)a, y = *(const int *)b;
return (x > y) - (x < y);
}
int main(void)
{
int sorted[] = {2, 4, 6, 8, 10};
int target = 8;
int *found = bsearch(&target, sorted, 5, sizeof sorted[0], cmp);
printf("Found = %s\n", found ? "yes" : "no");
return 0;
}
Expected output:
Found = yes
Step-by-step explanation:
- The sorted array satisfies the precondition of bsearch.
- The search uses cmp to establish the keyโs order relative to elements.
- A non-NULL pointer indicates a match.
24.7 Assertions and Defensive Programming
assert checks an assumption when assertions are enabled. Defining NDEBUG before including assert.h disables those checks. A user entering bad data is an expected input case, so handle it explicitly rather than relying on assert.
Complete C program:
#include <stdio.h>
#include <assert.h>
int squareNonnegative(int n)
{
assert(n >= 0);
return n * n;
}
int main(void)
{
printf("Square = %d\n", squareNonnegative(5));
return 0;
}
Expected output:
Square = 25
Step-by-step explanation:
- The assert condition is true for n = 5.
- The function computes and returns 25.
- A false assertion normally terminates the program with a diagnostic when assertions are enabled.
24.8 Error Reporting with errno and perror
First check the functionโs documented success or failure result. Inspect errno only when the function documents how it uses that value. For conversions such as strtol, clear errno before the call so an earlier error is not mistaken for a new one.
Complete C program:
#include <stdio.h>
int main(void)
{
FILE *fp = fopen("missing_codebhavya_example_48301.txt", "r");
if (fp == NULL) {
puts("File could not be opened");
return 0;
}
fclose(fp);
return 0;
}
Expected output:
File could not be opened
Step-by-step explanation:
- The file name is intended as an illustrative missing file.
- fopen returns NULL if opening fails.
- A real application can call perror("fopen") before returning an error status.
24.9 Random Numbers with rand โ and Limitations
rand generates repeatable pseudorandom values; srand chooses the starting seed. It is suitable for a simple classroom simulation, but not for passwords or secret tokens.
Complete C program:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
srand(123U);
int dice = rand() % 6 + 1;
printf("Dice between 1 and 6: %s\n",
dice >= 1 && dice <= 6 ? "yes" : "no");
return 0;
}
Expected output:
Dice between 1 and 6: yes
Step-by-step explanation:
- srand(123) selects a deterministic seed for a given implementation.
- rand generates a pseudorandom integer.
- The modulo expression produces a value between 1 and 6.
24.10 Date and Time Basics with time.h
time obtains calendar time, and difftime compares two calendar-time values in seconds. clock reports processor time used by the program, rather than a portable stopwatch for elapsed real time. Check each functionโs documented failure result.
Complete C program:
#include <stdio.h>
#include <time.h>
int main(void)
{
time_t now = time(NULL);
if (now == (time_t)-1) return 1;
double seconds = difftime(now, now);
printf("Difference = %.0f seconds\n", seconds);
return 0;
}
Expected output:
Difference = 0 seconds
Step-by-step explanation:
- time(NULL) requests the current calendar time.
- The code checks the documented failure representation.
- difftime applied to equal times gives zero.
24.11 Memory and Byte Operations
memcpy and memmove copy a specified number of bytes. Use memmove when source and destination overlap. memset fills bytes with a selected byte value. None of these functions adds a string terminator for you.
Complete C program:
#include <stdio.h>
#include <string.h>
int main(void)
{
char text[16] = "ABCDE";
memmove(text + 2, text, 3);
puts(text);
return 0;
}
Expected output:
ABABC
Step-by-step explanation:
- The source contains A, B and C.
- memmove copies those three bytes to positions 2, 3 and 4, even though source and destination overlap.
- The original terminating null character at position 5 remains.
24.12 Safe C Coding Checklist
Before reusing a library example, check its input assumptions, array capacities, valid object lifetimes, and error paths. Passing the right arguments matters as much as choosing the right function.
Important points:
- Check input results and handle invalid records.
- Keep array indices inside their bounds; allow space for null terminators.
- Check allocation success and arithmetic overflow before allocating.
- Never dereference NULL, dangling or uninitialized pointers.
- Use format specifiers matching the actual argument types.
- Avoid signed integer overflow and invalid shifts.
- Close files and free allocated memory on every relevant exit path.
- Compile with warnings enabled and test edge cases.
24.13 Quick Revision
math.h, ctype.h, string.h, stdlib.h, time.h, errno.h and assert.h.
Check return values, bounds, types, conversions and lifetime.
24.14 Quick MCQs
- Which function searches an already sorted array? bsearch().
- What is the important difference between memcpy and memmove? memmove permits overlapping regions.
- Which header declares isdigit()? ctype.h.
- Should rand() create passwords? No.
- What should you check after calling malloc()? The returned pointer is not NULL.
24.15 Practice Problems
- Read a line and safely convert it to an integer with strtol.
- Sort five numbers using qsort and a correct comparator.
- Use strchr and strstr to search a string.
- Count letters and digits using ctype.h.
- Write a program that uses perror to explain why a file failed to open.