Jonas's argument is good. Another proof is: given $f \in L^p$ (here $p=1,2$), take the convolution of $f$ with a sequence of mollifiers $\eta_\epsilon$. Using properties of convolutions, it's easy to check that $f * \eta_\epsilon$ is a smooth function, and that $f * \eta_\epsilon \to f$ in $L^p$ as $\epsilon \to 0$. This has the advantage of being a little more direct.
Edit: For a reference, see Folland's Real Analysis, section 8.2.
The smoothness of $f * \eta_\epsilon$ is Proposition 8.10 and comes from differentiating under the integral sign in the convolution (with justification!), and choosing to put the derivative on $\eta_\epsilon$. Intuitively, it comes from the idea that convolution is an "averaging" operation and tends to smooth, smear, or blur rough areas of $f$ together, and so should be a smoothing operation. (The wikipedia article has a nice animation illustrating this.)
The fact that $f * \eta_\epsilon \to f$ in $L^p$ is Folland's Theorem 8.14 (a), and it's pretty elementary. He also has Proposition 8.17 which proves that $C^\infty_c$ is dense in $L^p$, but it sort of inexplicably starts by using the fact that $C_c$ is dense in $L^p$. I suppose this is used to get a compactly supported function, so that you can approximate $f \in L^p$ by functions which are not only smooth (which $f * \eta_\epsilon$ is) but also compactly supported (which $f * \eta_\epsilon$ need not be, although $\eta_\epsilon$ is). But an easier argument would be to first approximate $f$ in $L^p$ norm by a function $g$ which is compactly supported but not necessarily continuous; for example, $g = f 1_{[-N,N]}$ for large $N$ (this works by dominated convergence), and then apply mollifiers to $g$. Unless, of course, there is some subtlety that I've missed.
Edit 2: Indeed there is. Folland's 8.14 (a) relies upon the fact that translation is strongly continuous in $L^p$, which uses the density of $C_c$. So apparently it is not so easy to bypass this step, and that destroys a lot of the "directness" of my argument.