The && operator is a boolean and with short-circuit evaluation. This means that it only executes the second command if the first one is successful (i.e. it returns 0). A typical way it's used is something like this:
tar xf file.tar && rm file.tar
This only removes the file if the extraction is successful.
Your script also contains a good example of this:
gcc foo.c && ./a.out
will only try to run the program if gcc was successful.
If you want to display $? regardless of the success of a.out, you can write:
gcc foo.c && { ./a.out ; echo $? ; }
The {...} groups the command so they'll both be executed if the compilation is successful.