In general, using pointer arithmetic works better than address arithmetic because pointer arithmetic is independent of the data model, whereas address arithmetic might not be. It usually leads to simpler code as well.
int *end; int *p; p = malloc(4 * NUM_ELEMENTS); end = (int *)((unsigned int)p + 4 * NUM_ELEMENTS); % warning: conversion of pointer loses bits
Suggested use:
int *end; int *p; p = malloc(sizeof (*p) * NUM_ELEMENTS); end = p + NUM_ELEMENTS;