Cairo is a language that lets you prove that a certain computation was done correctly (computational integrity). A Cairo program is stateless. In particular, you don’t have native access to storage, to other Caoro programs, or to L1 state (although you can use those things, as explained below).
A Cairo program is sent to the SHARP system (Shared Prover) and then a fact attesting to the correctness of the computation is registered on-chain. Then an L1 contract can query this fact and use it as if it did the computation itself. You can read more here:
StarkNet is a system where you can write & deploy contracts (written in the Cairo programming language, with some StarkNet-related modification). Unlike Cairo programs, StarkNet contracts do have access to contract storage, can interact with other contracts, and send/receive messages to/from L1. You can read more here:
https://www.cairo-lang.org/docs/hello_starknet/index.html