Skip to content
Volume C · The TensorCore.si Library

C

The language underneath everything.

C is small, fast and close to the hardware. Operating systems, databases, embedded devices and the runtimes of Python and PyTorch are written in it, and llama.cpp's core ggml library is C.

Prologue

Why learn C?

Learning C teaches you how computers really work: memory, pointers and how data is laid out. That knowledge makes you better in every other language and is essential for GPU and AI performance work.

  • Understand the machine: memory, pointers and the stack, with nothing hidden.
  • Speed: C is the baseline other languages are measured against.
  • AI runtimes: ggml, llama.cpp and many inference engines use C at their core.
Prologue

Set up and run your first program

Install a compiler: GCC or Clang on Linux and macOS, or MSVC / MinGW on Windows.

terminal
gcc --version
gcc -O2 -Wall hello.c -o hello
./hello
hello.c
#include <stdio.h>

int main(void) {
    const char *name = "Ada";
    printf("Hello, AI! Welcome to C, %s.\n", name);
    return 0;
}
TipAlways compile with -Wall to see warnings; they often point to real bugs.
Chapter 1

Variables and types

C has a few built-in types: int, long, float, double, char. Sizes depend on the platform; use <stdint.h> types like int64_t when size matters.

types.c
#include <stdio.h>
#include <stdint.h>
int main(void) {
    int layers = 32;
    double lr = 3e-4;
    int64_t params = 8030000000LL;
    float fp16_gb = params * 2 / 1e9f;
    printf("%d layers, lr %g, %.1f GB\n", layers, lr, fp16_gb);
    return 0;
}
Chapter 2

Control flow and functions

if, for, while and switch work like in most C-family languages. Functions must be declared before use.

control.c
#include <stdio.h>
double params(int layers, int d) { return 12.0 * layers * d * d; }
int main(void) {
    for (int i = 0; i < 3; i++) printf("epoch %d\n", i);
    int bits = 8;
    switch (bits) {
        case 16: puts("FP16"); break;
        case 8:  puts("FP8");  break;
        default: puts("other");
    }
    printf("%.2e params\n", params(32, 4096));
    return 0;
}
Chapter 3

Arrays and pointers

An array is a block of memory; a pointer holds a memory address. Passing a pointer lets a function work on data without copying it, which is how fast numeric code is written.

pointers.c
#include <stdio.h>
void scale(float *v, int n, float k) {
    for (int i = 0; i < n; i++) v[i] *= k;   // modifies the caller's array
}
int main(void) {
    float w[4] = {0.5f, -1.0f, 2.0f, 0.25f};
    scale(w, 4, 2.0f);
    for (int i = 0; i < 4; i++) printf("%.2f ", w[i]);
    printf("\naddress of w[0]: %p\n", (void *)&w[0]);
    return 0;
}
Chapter 4

Dynamic memory

Use malloc to allocate memory at runtime and free to release it. Forgetting free leaks memory; using memory after freeing it is a serious bug.

memory.c
#include <stdio.h>
#include <stdlib.h>
int main(void) {
    size_t n = 1 << 20;                       // one million floats
    float *buf = malloc(n * sizeof *buf);
    if (!buf) { perror("malloc"); return 1; }
    for (size_t i = 0; i < n; i++) buf[i] = 1.0f;
    printf("allocated %.1f MB\n", n * sizeof *buf / 1e6);
    free(buf);
    return 0;
}
Chapter 5

Structs

A struct groups related values. Combined with pointers, structs are how C models tensors, network layers and devices.

structs.c
#include <stdio.h>
typedef struct { const char *name; int vram_gb; float tflops_fp16; } Gpu;
int main(void) {
    Gpu gpus[] = {{"H100", 80, 989.0f}, {"RTX 5090", 32, 419.0f}};
    for (int i = 0; i < 2; i++)
        printf("%-9s %3d GB %6.0f TFLOPS\n", gpus[i].name, gpus[i].vram_gb, gpus[i].tflops_fp16);
    return 0;
}
Part II · AI with C

AI with C

C is the language of fast inference. llama.cpp's ggml tensor library, many embedded ML runtimes and the low-level kernels behind Python libraries are written in C. Knowing C lets you read and optimise that code.

The essential libraries

ggmlThe tensor library behind llama.cpp and whisper.cpp.
ONNX Runtime C APIRun ONNX models from C.
TensorFlow Lite MicroML on microcontrollers.
cJSON + libcurlCall LLM APIs over HTTP.

Gradient descent from scratch

Learn y = 3x + 0.5 using arrays and loops.

gradient.c
#include <stdio.h>
#include <stdlib.h>
int main(void) {
    enum { N = 100 };
    double xs[N], ys[N], w = 0, b = 0, lr = 0.1;
    for (int i = 0; i < N; i++) {
        xs[i] = -1 + 2.0 * i / (N - 1);
        ys[i] = 3 * xs[i] + 0.5 + 0.1 * ((double)rand() / RAND_MAX - 0.5);
    }
    for (int step = 0; step < 500; step++) {
        double gw = 0, gb = 0;
        for (int i = 0; i < N; i++) {
            double err = w * xs[i] + b - ys[i];
            gw += 2 * err * xs[i] / N; gb += 2 * err / N;
        }
        w -= lr * gw; b -= lr * gb;
    }
    printf("w = %.2f, b = %.2f\n", w, b);
    return 0;
}
Part III · Build an AI agent

Call an LLM from C

A full agent in C needs an HTTP library (libcurl) and a JSON parser (such as cJSON). This example sends one chat request to a local model; an agent repeats it, parsing tool_calls from the reply and sending tool results back.

Your goal→Model plans→Tool call→Your code runs the tool→Result back to model→Final answer
chat.c
// gcc chat.c -lcurl -o chat
#include <stdio.h>
#include <curl/curl.h>
int main(void) {
    const char *body =
        "{\"model\":\"llama3.1\",\"messages\":[{\"role\":\"user\","
        "\"content\":\"Explain a pointer in one sentence.\"}]}";
    CURL *c = curl_easy_init();
    if (!c) return 1;
    struct curl_slist *h = curl_slist_append(NULL, "Content-Type: application/json");
    curl_easy_setopt(c, CURLOPT_URL, "http://localhost:11434/v1/chat/completions");
    curl_easy_setopt(c, CURLOPT_HTTPHEADER, h);
    curl_easy_setopt(c, CURLOPT_POSTFIELDS, body);
    CURLcode rc = curl_easy_perform(c);   // prints the JSON reply to stdout
    if (rc != CURLE_OK) fprintf(stderr, "error: %s\n", curl_easy_strerror(rc));
    curl_slist_free_all(h);
    curl_easy_cleanup(c);
    return 0;
}

For the full agent loop, parse the reply with cJSON, check choices[0].message.tool_calls, run the matching C function and append a tool message before calling again.

Run it locallyInstall Ollama, run ollama pull llama3.1, and keep it running. The code talks to its OpenAI-compatible API at http://localhost:11434/v1, so the same program also works with vLLM, llama.cpp server or a cloud API by changing the URL, model name and adding an API key.
Part IV · Your path

C learning roadmap

Tick items off as you go. Your progress is saved in this browser.

Beginner

Intermediate

Advanced

Part IV · Your path

Projects to build

Matrix multiplyWrite and time a naive vs cache-friendly matmul.
Tiny tokenizerSplit text into tokens and count them.
LLM CLIA terminal chat client using libcurl.
Reference

C cheat sheet

TaskSyntax
Printprintf("%d\n", x);
Arrayint a[4] = {1,2,3,4};
Pointerint *p = &x;
Allocatep = malloc(n * sizeof *p);
Structtypedef struct { int x; } P;
Loopfor (int i = 0; i < n; i++)
Reference

Common mistakes

  • Reading or writing past the end of an array is undefined behaviour and may not crash right away.
  • Every malloc needs exactly one free.
  • Strings need room for the terminating \0.
Reference

Where to go next

On TensorCore.si: C++ volume, CUDA volume.

Keyboard: [ previous language · ] next language · / search the library