Because you do not pass the object's address (a pointer). You pass the object itself (via a reference). Ampersand in the declaration of function argument is the syntax to distinguish that you want the object itself rather than a copy.
// This will copy the pairs
void inpu_c(vector<vector<int>> pairs){
}
// This will work on the original object
void inpu_r(vector<vector<int>> &pairs){
}
The pointer can be used as a reference type, you can dereference it and use the original object itself.
// This will work on the pointer
void inpu_p(vector<vector<int>>* pairs){
 pairs->clear();
 (*pairs).clear();
 // You can even use a reference type inside, you have to dereference a pointer
 assert(pairs); //Some protection against invalid pointers
 // a reference type requires an object
 vector<vector<int>>& r = *pairs;
 // will clear object pointer by pairs
 r.clear(); 
}
Using pass-by-value and pass-by-copy semantics do not change the client syntax though. The client code looks the same. That is why you don't have to use get-address operator (&) on the call site.
Pointers are slightly different from references, those two are different data types. E.g. pointer is nullable, i.e. has a special designated invalid value, while reference is designed to always point to an object.