Generally speaking, if you pass in a pointer or a reference to a function, you’re assuming that the function is going to potentially access and modify your object (especially if you pass by reference). You can prevent this with using the “const” keyword, which sort of creates a contract between the function developer and the function user (like, “I promise I won’t change this value if you give it to me”).
If you pass a variable by “value” instead, the app will create a copy of the object and all of its values and then pass in the copy. The original will not be touched. If you have an array of 1,000,000 elements, it obviously becomes a pretty expensive memory copy to duplicate an array of 1m objects, so commonly people will just pass in the memory address of the object instead of the object itself. A memory address is only 4 bytes on a 32bit system, 8 bytes on a 64 bit system, so it is much lighter to pass that around, right? Pointers and references kind of go hand in hand with each other. You can say that a reference is really just an “address” to an object, but not the object itself. To use the address, you need to know what kind of data it represents. Whether you have an address to an integer or a massive array, or a class, the address is always the same size. Commonly you’ll dereference an address (such as with a pointer), which means that you’re working with the address data instead of the address itself.
So in theory, you could pass in pointers or references to a function and the function can do a bunch of logic to read or modify the data, and in theory it would be a processed “output”. If you want to see multiple output nodes in a blueprint node, you can either pass in function parameters by reference, or pass in a struct which contains your variables. For reference, look at the “LineTrace()” function and how it passes an FHitResult struct as an output.