The Standard Library

The standard library is like a toolbox — you don't need to forge your own hammer and screwdriver, just pick them up and use them. Understanding what each tool does helps you choose the right one.

math.h Mathematical Operations

Using math functions requires including the header and linking the math library:

C
#include <math.h>

Compile with the -lm flag: gcc program.c -lm.

Common Math Functions

Function Purpose Example
fabs(x) Absolute value fabs(-3.5) → 3.5
sqrt(x) Square root sqrt(16.0) → 4.0
pow(x, y) x raised to the power y pow(2.0, 10.0) → 1024.0
ceil(x) Round up ceil(3.2) → 4.0
floor(x) Round down floor(3.8) → 3.0
round(x) Round to nearest round(3.5) → 4.0
fmod(x, y) Floating-point remainder fmod(7.5, 2.5) → 0.0
log(x) Natural logarithm log(2.718) → 1.0
log10(x) Common logarithm log10(100.0) → 2.0
sin(x) Sine sin(3.14/2) → 1.0
cos(x) Cosine cos(0.0) → 1.0
tan(x) Tangent tan(0.0) → 0.0
⚠️ Note: Trigonometric functions take radians, not degrees! To convert degrees to radians: rad = deg * 3.14159265 / 180.0.

Example

Calculate the distance between two points:

C
#include <stdio.h>
#include <math.h>

typedef struct {
    double x;
    double y;
} Point;

double distance(Point a, Point b) {
    double dx = a.x - b.x;
    double dy = a.y - b.y;
    return sqrt(dx * dx + dy * dy);
}

int main(void) {
    Point p1 = {3.0, 4.0};
    Point p2 = {0.0, 0.0};
    printf("Distance: %.2f\n", distance(p1, p2));
    return 0;
}
▶ Try it Yourself
TEXT
Distance: 5.00

stdlib.h General Utilities

Random Numbers

C
int rand(void);
void srand(unsigned int seed);

rand() returns a pseudo-random integer between 0 and RAND_MAX. Without calling srand, every run of the program produces the same sequence of random numbers.

C
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void) {
    srand((unsigned int)time(NULL));

    for (int i = 0; i < 5; i++) {
        printf("%d ", rand());
    }
    printf("\n");

    for (int i = 0; i < 5; i++) {
        printf("%d ", rand() % 100);
    }
    printf("\n");

    return 0;
}
TEXT
1804289383 846930886 1681692777 1714636915 1957747793
83 86 77 15 93
⚠️ Note: rand() % N doesn't provide good randomness in most implementations — lower bits may follow a pattern. For scenarios requiring high-quality randomness, use a more advanced random number generator.

Type Conversion

Function Purpose
atoi(str) String to int
atol(str) String to long
atof(str) String to double
strtol(str, &end, base) String to long (with base)
strtod(str, &end) String to double (with error detection)
C
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int a = atoi("42");
    double b = atof("3.14");
    long c = strtol("0xFF", NULL, 16);

    printf("a = %d\n", a);
    printf("b = %.2f\n", b);
    printf("c = %ld\n", c);

    char *end;
    long d = strtol("123abc", &end, 10);
    printf("d = %ld, Unconverted part: %s\n", d, end);

    return 0;
}
TEXT
a = 42
b = 3.14
c = 255
d = 123, Unconverted part: abc
💡 Tip: atoi cannot detect errors — invalid input returns 0, which is indistinguishable from a legitimate 0. Prefer strtol/strtod, which let you determine whether conversion succeeded via the end pointer.

Dynamic Memory Management

C
void *malloc(size_t size);
void *calloc(size_t count, size_t size);
void *realloc(void *ptr, size_t size);
void free(void *ptr);
C
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int *arr = calloc(5, sizeof(int));
    if (arr == NULL) {
        return 1;
    }

    for (int i = 0; i < 5; i++) {
        arr[i] = i * 10;
    }

    int *new_arr = realloc(arr, 10 * sizeof(int));
    if (new_arr == NULL) {
        free(arr);
        return 1;
    }
    arr = new_arr;

    for (int i = 5; i < 10; i++) {
        arr[i] = i * 10;
    }

    for (int i = 0; i < 10; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    free(arr);
    return 0;
}
TEXT
0 10 20 30 40 50 60 70 80 90
⚠️ Note: When realloc fails, it returns NULL but the original memory is not freed! So you must use a temporary variable to receive realloc's return value — on failure, you can still free the original memory.

Sorting and Searching

qsort

C
void qsort(void *base, size_t count, size_t size,
           int (*compare)(const void *, const void *));

Comparison function rules: return negative if a < b, 0 if equal, positive if a > b.

C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int cmp_int(const void *a, const void *b) {
    return *(const int *)a - *(const int *)b;
}

int cmp_str(const void *a, const void *b) {
    return strcmp(*(const char )a, *(const char )b);
}

int main(void) {
    int nums[] = {42, 17, 8, 95, 3, 61};
    int n = sizeof(nums) / sizeof(nums[0]);

    qsort(nums, n, sizeof(int), cmp_int);
    for (int i = 0; i < n; i++) {
        printf("%d ", nums[i]);
    }
    printf("\n");

    const char *names[] = {"Alice", "Bob", "Charlie", "Diana"};
    int m = sizeof(names) / sizeof(names[0]);

    qsort(names, m, sizeof(char *), cmp_str);
    for (int i = 0; i < m; i++) {
        printf("%s ", names[i]);
    }
    printf("\n");

    return 0;
}
TEXT
3 8 17 42 61 95
Alice Bob Charlie Diana

bsearch

C
void *bsearch(const void *key, const void *base, size_t count,
              size_t size, int (*compare)(const void *, const void *));

Performs binary search on a sorted array. Returns a pointer to the found element, or NULL if not found.

C
#include <stdio.h>
#include <stdlib.h>

int cmp_int(const void *a, const void *b) {
    return *(const int *)a - *(const int *)b;
}

int main(void) {
    int nums[] = {3, 8, 17, 42, 61, 95};
    int n = sizeof(nums) / sizeof(nums[0]);

    int key = 42;
    int *result = bsearch(&key, nums, n, sizeof(int), cmp_int);

    if (result != NULL) {
        printf("Found %d at index %ld\n", key, result - nums);
    } else {
        printf("%d not found\n", key);
    }

    return 0;
}
TEXT
Found 42 at index 3

time.h Time Handling

Time Functions

Function/Type Purpose
time_t Time type (usually seconds since 1970-01-01)
time(&t) Get current time
clock() Get CPU clock ticks used by program
localtime() Convert to local time struct
gmtime() Convert to UTC time struct
strftime() Format time as string
difftime() Calculate difference between two times (seconds)

struct tm

C
struct tm {
    int tm_sec;
    int tm_min;
    int tm_hour;
    int tm_mday;
    int tm_mon;
    int tm_year;
    int tm_wday;
    int tm_yday;
    int tm_isdst;
};

tm_mon ranges from 0-11 (0 = January), tm_year is the number of years since 1900, and tm_wday uses 0 for Sunday.

Example

C
#include <stdio.h>
#include <time.h>

int main(void) {
    time_t now = time(NULL);
    struct tm *local = localtime(&now);

    char buf[64];
    strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", local);
    printf("Current time: %s\n", buf);

    printf("Today is day %d of the week (0=Sun)\n", local->tm_wday);

    return 0;
}
▶ Try it Yourself
TEXT
Current time: 2025-03-15 14:30:22
Today is day 6 of the week (0=Sun)

Program Timing

C
#include <stdio.h>
#include <time.h>

int main(void) {
    clock_t start = clock();

    volatile long sum = 0;
    for (long i = 0; i < 100000000L; i++) {
        sum += i;
    }

    clock_t end = clock();
    double elapsed = (double)(end - start) / CLOCKS_PER_SEC;
    printf("Elapsed: %.3f seconds\n", elapsed);

    return 0;
}
TEXT
Elapsed: 0.235 seconds
⚠️ Note: clock() measures CPU time, not wall-clock time. If the program has sleep or I/O waits, that time is not counted. Use difftime to measure actual elapsed time.

ctype.h Character Handling

Function Test Condition
isalpha(c) Letter
isdigit(c) Digit
isalnum(c) Letter or digit
isupper(c) Uppercase letter
islower(c) Lowercase letter
isspace(c) Whitespace (space, tab, newline, etc.)
ispunct(c) Punctuation
isprint(c) Printable character
toupper(c) Convert to uppercase
tolower(c) Convert to lowercase

These functions require an unsigned char value or EOF as their argument. Passing a negative char value is undefined behavior.

Example

Count letters, digits, and other characters in a string:

C
#include <stdio.h>
#include <ctype.h>

int main(void) {
    char str[] = "Hello, World! 123";
    int letters = 0, digits = 0, others = 0;

    for (int i = 0; str[i] != '\0'; i++) {
        if (isalpha((unsigned char)str[i])) {
            letters++;
        } else if (isdigit((unsigned char)str[i])) {
            digits++;
        } else {
            others++;
        }
    }

    printf("Letters: %d, Digits: %d, Others: %d\n", letters, digits, others);
    return 0;
}
▶ Try it Yourself
TEXT
Letters: 10, Digits: 3, Others: 6

assert.h Assertions

C
void assert(int expression);

When the expression is false, the program terminates and prints an error message (file name, line number, expression). Defining the NDEBUG macro before #include <assert.h> disables all assertions.

C
#include <stdio.h>
#include <assert.h>

double safe_divide(double a, double b) {
    assert(b != 0 && "Divisor cannot be zero");
    return a / b;
}

int main(void) {
    printf("10 / 2 = %.1f\n", safe_divide(10.0, 2.0));
    printf("10 / 0 = %.1f\n", safe_divide(10.0, 0.0));
    return 0;
}
TEXT
10 / 2 = 5.0
Assertion failed: b != 0 && "Divisor cannot be zero", file main.c, line 5
💡 Tip: The string literal in assert gets printed, so writing "Divisor cannot be zero" is more effective than a comment — when the assertion fails, you can immediately see the reason.

❓ FAQ

Q Why does rand() produce the same sequence every run?
A No call to srand was made to set the random seed. The default seed is 1, so the sequence is fixed. Use srand(time(NULL)) to seed with the current time.
Q Why does qsort's comparison function use void pointers?
A qsort is a generic function that doesn't know what type it's sorting. void pointers can point to any type, and the comparison function casts them back to the specific type internally.
Q Why should ctype.h function arguments be cast to unsigned char?
A If char is signed, characters with the high bit set may be negative values, which is undefined behavior when passed to ctype functions. Casting to unsigned char ensures the value is in the 0-255 range.
Q What's the difference between assert and an if check?
A assert checks for things that should never happen (logic errors) during development, and disappears when NDEBUG is defined. if checks handle runtime errors that might occur and are always present.

📖 Summary

📝 Exercises

  1. Write a program that generates 100 random integers from 1 to 1000, sorts them with qsort, and outputs the maximum and minimum values
  2. Write a program that uses clock() to compare the time difference between bubble sort and qsort on 10,000 integers
  3. Write a function that uses ctype.h functions to implement string case conversion (input a string, output all-uppercase and all-lowercase versions)
100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏