Skip to main content
This guide introduces the fundamental concepts and patterns for using the Z3 Theorem Prover from C.

Basic Workflow

A typical Z3 C program follows this pattern:
  1. Create a configuration and context
  2. Declare variables and constraints
  3. Create a solver and add assertions
  4. Check satisfiability
  5. Extract results (models, proofs, etc.)
  6. Clean up resources

Hello Z3

Let’s start with a simple example:
Always delete the config after creating the context, and delete the context when done to prevent memory leaks.

Configuration and Context

The context manages all Z3 objects. The configuration sets parameters before creating the context.

Error Handling

Creating Variables and Expressions

Boolean Variables

Helper function for convenience:

Integer Variables

Integer Constants

Building Formulas

Logical Operations

Arithmetic Operations

Using Solvers

Creating and Using a Solver

Complete Example: De Morgan’s Law

This example proves De Morgan’s law: ¬(x ∧ y) ⟺ (¬x ∨ ¬y)

Complete Example: Finding a Model

Find values for x and y such that x + y > 5 and x - y < 2:

Memory Management

Z3 uses reference counting. Always increment references for long-lived objects and decrement when done.

Reference Counting

AST Reference Counting

Most AST nodes are automatically managed by the context, but if you need to keep them across multiple solver calls:

Printing and Debugging

Best Practices

  1. Always create a fresh context for each independent solving task
  2. Enable model generation in the config if you need to extract solutions
  3. Use reference counting properly to avoid memory leaks
  4. Check error codes or set up error handlers for production code
  5. Clean up resources in reverse order of creation

Next Steps

API Reference

Explore the complete C API

Examples

View more C examples on GitHub