Monte carlo simulation in C
Naming things
Naming things is one of the hard things in computer science. You should make sure names of functions and variables are clear and concise. In general, use nouns for variable names and verbs for function names. Looking at your choices of names in more detail:

LATTICE is not a lattice, it is the size of the lattice. So call it LATTICE_SIZE.
SWEEPS is the number of sweeps to perform, so maybe it is better to call it N_SWEEPS (N is a commonly used prefix meaning &quot;number of&quot;).
rates() is a function, so use a verb for the function name, for example calculate_rates().
rho_avg() is a function again, so use a verb for that as well, like calculate_rho_avg().

You should also be consistent in how you name things. Is it rho or density? Pick one and stick with it. I would also write beta instead of b, to match how you write down other greek letters like rho and theta.
Use array indexing notation where appropriate
In rates(), you are using pointer arithmetic when you could just have used standard array notation:
   for(int i = 0; i &lt; LATTICE; i++)
   {
        theta = rho[i] * (2 * b - rho[i]);
        death_rate[i] = exp(-LATTICE * theta);
   }

Similarly, in revive(), write:
    for(n = 0; cumsum &lt;= u_rand; n++)
    {
        cumsum += (double)distribution[n] / (double)norm;
    }

    return n - 1;

Terminology
Death rates? Revive? That sounds very morbid! Unless you are simulating some system that predicts cell death or pandemics, this is not terminology normally used in Monte Carlo simulations. Your code looks like it implements the Metropolis algorithm, where your death_rate would be equivalent to the transition probability, although I'm not sure what the equivalent of revive() would be. If it is the Metropolis algorithm you are implementing, then it doesn't look like you have detailed balance. What system are you simulating exactly? It might help to document that in the code as well.
Avoid global variables
It is good practice to avoid using global variables. That makes it easier if your program grows and becomes part of something larger. Or perhaps you want to run multiple simulations at the same time using threads. This should be easy; you already have the arrays distribution[] and death_rate[] inside monte_carlo(), just move rho[] there as well and pasas a pointer to rho to rates().
You might want to do this in a more organized way, and create a struct to hold all the information relevant to your simulation:
struct simulation_parameters {
    unsigned long long distribution[LATTICE];
    double death_rate[LATTICE];
    double rho[LATTICE];
};

...

double monte_carlo(float beta) {
    struct simulation_parameters params = {0}; // sets everything in params to zero
    calculate_rho(params.rho); // should do what initialize() did
    calculate_death_rates(params.death_rate, beta);

    for (unsinged long long i = 1; i &lt;= SWEEPS; i++) {
        distribution[n]++;
        if (uniform_rand() &lt; params.death_rate[n]) {
            n--;
            if (n == -1)
                n = revive(params.distribution, i);
        }
    }

    return calculate_rho_avg(distribution, SWEEPS);
}

int main(void) {
    srand(time(0)); // srand() should only be called once, so do it in main()
    printf(&quot;Average density is %lf\n&quot;, monte_carlo(BETA));
}