char array comparison
PubSubClient::setServer(const char * domain, uint16_t port) just saves the pointer, it doesn't copy the string (probably because it expects a static string literal).
(Source)
In your case, when ip goes out of scope, the pointer is no longer valid, so it won't work.

Just use the PubSubClient::setServer(IPAddress ip, uint16_t port) function instead.
(Source)

Always read the API documentation, most libraries have one, even though it can be hard to find. The ReadMe and GitHub Wiki pages are a good place to start.
If that's insufficient (not uncommon for open source projects), read the header files, which list all functions of the library.
If you still have doubts about what a function does, refer to the actual implementation files.