They have different adresses, because they are different objects. From cppreference about throw :
throw expression  
[...]
- First, copy-initializes the exception object from expression
[...]
The reason to catch by reference is not so much to avoid a copy, but to correctly catch exceptions that inherit from others. For an int it does not matter.
Just as a curiosity, this is how you can get a reference to a in the catch block:
#include <iostream> 
struct my_exception {
    int& x;
};
int main() {
    int a = 3;
    std::cout << "Address of a = " << &a << '\n';
    try {
        throw my_exception{a};
    } catch(my_exception& s) { 
        std::cout << "Address of s = " << &s.x << '\n';
    }
}
Possible output:
Address of a = 0x7ffd76b7c2d4
Address of s = 0x7ffd76b7c2d4
PS: Just in case you wonder, I changed more on your code, because Why is “using namespace std;” considered bad practice?, "std::endl" vs "\n", and because return 0 is redundant in main.