I have a homework assignment with a number of questions. One is asking why the strcpy() function doesn't need the call by reference operator for CStrings. I've looked through the book numerous times and I can't, for the life of me, find the answer. Can anyone help explain this to me?
It is an array of sorts so I would think you would need the call by reference.
strcpy() takes a pointer to char.
Thus you don't pass the "string" as a parameter but only the address of its first character.
So basically you have something like this:
void func(const char* str);
const char* str = "abc";
func(str); // Here str isn't passed by reference but since str is a pointer to the first character ('a' here), you don't need a reference.
Passing a pointer is fast. On a 32 bits architecture, a pointer takes 32 bits, whatever the length of the pointed string.
If you mean class CString, then in other words the question asks you:
Why does this compile?
CString sExample;
char buffer[LARGE_ENOUGH];
strcpy(buffer, sExample);
The answer is, because class CString defines an operator const char* and therefore can be converted to the type of strcpy's second argument.
I 'm not sure if this is what you mean though.
This a problem of terminology, mostly.
An "object" (I use the term as designing "a chunk of RAM") is passed by value when the called function gets a copy of the chunk. It is passed by reference when the called function gets a way to access the one and only chunk.
Consider this:
void f(int x)
{
x = 42;
}
void g()
{
int y = 54;
f(y);
// here "y" still has value 54
}
Here, the function f() modifies x, but that is its own x, a variable which contains a copy of the contents of the y variable of g(). What f() does with its x does not impact what the y of g() contains. The variable is then passed by value.
C++ has a notion of reference which goes like this:
void f(int& x)
{
x = 42;
}
void g()
{
int y = 54;
f(y);
// here "y" now has value 42
}
Here, the special construction (with the "&") instructs the C++ compiler to play some hidden tricks so that the x known by f() is actually a kind of alias on the y variable used by g(). There is only one variable: the x and the y designate the same chunk of RAM. The variable is here passed by reference.
Now, consider a "C string". In C (and C++), a string is just a bunch of char values, the last of which having value 0 (this is the conventional string terminator). The code does not handle strings directly; it uses pointers. A pointer is a value which actually designates an emplacement in RAM. The pointer is not the string; the pointer is a kind of number (usually on 32 or 64 bits, it depends on the processor type and the operating system) which tells where in RAM is the first char of the string. So when you call strcpy() you actually give it pointers (one for the destination buffer, one for the source string). Those pointers are unmodified: the source string and the destination buffers are not moved in the process; only the contents of the string are copied into the destination buffer.
Hence, strcpy() needs not have access to the variables which contain the pointers in the caller code. strcpy() only needs to know where the destination buffer and the source strings are in RAM. Giving a copy of the pointer values to strcpy() is enough. Hence, those pointers are passed by value.
Note that in the presence of pointers, there are two objects to consider: the variable which contains the pointer, and the chunk of RAM which is pointed to. The pointer itself is passed by value (strcpy() receives its own copy of the variable which contains the pointer to the destination buffer). We can say that the pointed-to chunk of RAM (the destination buffer) is "passed by reference" since it is not duplicated in the process and the called function (strcpy()) can modify it. The point here is that the term "reference" has two distinct meanings:
The C++ syntax meaning: "reference" designates the special construction with the "&" that I have described above.
The language theory formal meaning: "reference" designates a way by which a value is indirectly designated, so that caller and callee may access the same chunk of RAM under distinct names. With that meaning, passing by value a pointer to a called function is equivalent to passing by reference the chunk of RAM to which the pointer points.
A C++ "reference" (first meaning) is a syntaxic way to pass "by reference" (second meaning) a variable.
Well in the case you mean c-strings (char*) you don't need a call by reference because the string itself is a pointer. So string copy knows where to/from where to copy the string.
Because strcpy works with char* which are pointers. The pointer is passed by value, and strcpy uses that pointer to access the indiviual characters in the target string and change them. Compare that to passing an integer by value - the function can't change the original integer.
Understanding how char* strings are not like integers is vital to you not going crazy during your C++ course. Well done for your prof making you face it.
Because in C when calling functions, arrays are passed as the address of the first element, which is equivalent of calling by reference.
See Peter Van Der Linden Expert C programming, Deep secrets book.
automatic type conversion, is the answer I guess they're looking for. Looking that turn up might give you some help.
Related
I am reading a book about c and the following paragraph is a bit unclear for me:
Surprisingly, passing the pointer is not efficient in the above example! That's because of the fact that the int type is 4 bytes and copying it is more efficient than copying 8 bytes of its pointer. But this is not the case regarding structures and arrays. Since copying structures and arrays is done byte-wise, and all of the bytes in them should be copied one by one, it is usually better to pass pointers instead.
as I know all the operations in CPU are limited to arithmetic(plus or minعس) or bit-wise kind of operation so
What does the writer mean about copying array and structure, isn't an int copying a bit shifting operation?
Second: are pointers array?
NOTE: the book name is Extreme C and published by packT
and following example is what the author is referring to:
#include <stdio.h>
void func(int* a) {
int b = 9;
*a = 5; a = &b;
}
int main(int argc, char** argv) {
int x = 3;
int* xptr = &x;
printf("Value before call: %d\n", x);
printf("Pointer before function call: %p\n", (void*)xptr); func(xptr);
printf("Value after call: %d\n", x);
printf("Pointer after function call: %p\n", (void*)xptr);
return 0;
}
'''
The book is not clear and it's also wrong.
The assumption seem to be that an 8 byte pointer is "harder" to copy than a 4 byte integer. That's wrong for nearly all modern CPUs.
Further, the part about copying an array is just plain wrong. That is not what C does. Passing an array in C does not involve an copy. It's actually just like passing a pointer.
The part about structs is however correct... as long as the struct isn't just a simple integer or char but "something bigger".
What does the writer mean about copying array
Sounds like rubbish... as C doesn't pass array by doing a copy
What does the writer mean about copying ... structure,
Structs are copied by value. So passing a struct to a function involves copying every byte of the struct. That is rather expensive if the struct is large.
are pointers array?
No. Pointers are pointers. But... Under the correct circumstances a pointer can be used as an array because *(p + i) is the same as p[i]
What does the writer mean about copying array and structure?
Let's compare two functions taking a large amount of data (e.g. a struct with lots of data members):
void f(const big_type_t* p_big_type);
void g(const big_type_t big_type);
Both can effectively read the values from the caller-specified big_type_t object, but in the former case f() need only be passed a pointer (which is typically 8 bytes on modern everyday hardware) to tell it where the caller has a big_type_t object for it to use. In the latter case g() pass-by-value argument asks the compiler to make a complete copy of the caller's big_type_t argument and copy it to a location on the stack where g() implicitly knows to find it. Every byte of the data in the struct must be copied (unless the compiler's smart enough to optimise under the as-if rule, but that's a bit of a distraction - it's generally best to write code so it's not unnecessarily inefficient if not optimised well).
For built-in arrays, the situation is different. C and C++ implicitly pass arrays by pointer, so...
void h(const int* my_array);
void i(const int my_array[]);
...are both called the same way, with the my_array argument actually being a pointer to the first int the caller specifies.
In C++ there are also std::array<>s, which are effectively struct/classes with a static-sized array data member (i.e. template <typename T, size_t N> struct array { T data_[N]; ... }). They can be passed by-value, the same as structs. So, for large std::array objects, access via a pointer or reference is more efficient than doing a full copy.
Sometimes a function really does want a copy though, as it may need to do something like sort it without affecting the caller-specified variable passed to that argument. In that case, there's not much point passing by pointer or reference.
isn't an int copying a bit shifting operation?
No... the term "bit shifting" has a very specific meaning in programming. Consider an 8-bit integer - say 0x10010110. If we shift this value one bit to the right, we get 0x01001011 - a 0 is introduced on the left, and a 0 is discarded on the right. If we shift the new value to the right again, we could get either 0x00100101 (add 0 at left; discard at right) or - what's called a circular shift or rotation - 0x100100101`, where the right-most bit is moved to become the left-most bit. Bit-shifting happens to CPU registers, and the shifted values can be stored back into the memory where a variable is located, or used in some calculation.
All that's quite unrelated to memory copying, which is where the bits in one value are (at least notionally, without optimisation) copied into "another" value. For large amounts of data, this usually does mean actually copying the bits in a value read from memory to another area of memory.
Second: are pointers array?
No they're not. But, when you have an array, it easily "decays" to a pointer to its first element. For example:
void f(const char* p);
f("hello");
In C++, "hello" is a string literal of type char[6] (as there's implicitly a null character at the end. When calling f, it decays from array form to a pointer to the first character - 'h'. That's usually desirable to give the called function access to the array data. In C++, you can also do this:
template <size_t N> void f(const char(&arr)[N]);
f("hello");
The call above does not involve decay from an array to a pointer - arr is bound to the string literal array and N is derived as 6.
What does the writer mean about copying array and structure, isn't an int copying a bit shifting operation?
When you pass an object of struct type as a parameter in a function, the contents of that structure are copied into the formal parameter:
struct foo {
...
};
void do_something_with( struct foo arg )
{
// do something with arg
}
int main( void )
{
struct foo f = { 1, 2.0, "three" };
...
do_something_with( f );
...
}
The objects main:f and do_something_with:arg are two separate instances of struct foo - when you pass f as an argument, its contents are copied into arg. Any changes you make to the contents of arg do not affect the contents of f.
The thing is, the author of the book is wrong about arrays - when you pass an array expression as an argument to a function, what you are actually passing is a pointer to the first element, not the whole array.
Second: are pointers array?
Arrays are not pointers - however, unless it is the operand of the sizeof or unary & operators, an expression of type "N-element array of T" will be converted, or "decay", to an expression of type "pointer to T" and the value will be the address of the first element of the array.
When you pass an array expression as an argument to a function, what the function actually receives is a pointer to the first element of the array - no copy of the array is made like it is for the struct above.
Finally - while runtime efficiency does matter, correctness, clarity, and maintainability matter more. If it makes sense to pass an argument as a pointer (such as you want the function to modify the argument), then by all means do so. But don't start passing everything as a pointer because it might speed things up. Start by making things clear and correct - then, measure the performance of your code and take action based on that. Most of your runtime performance gains come from using the right data structures and algorithms, not how you pass arguments.
While the sample code has much to be desired and some bugs, I think that the gist of what the author is saying is that for a small data type it is more efficient to directly pass a parameter to a function by value (int) rather than by passing by pointer (int *). When a function is called, parameters are pushed onto the stack and and a type of int would require 2 bytes, but an int *parameter may require 4 or 8 bytes depending on the system.
When passing a struct as a parameter, the overall size of the struct will typically be greater than 4 or 8 bytes, so passing a pointer to thr struct may be more efficient, since only 4 or 8 bytes would need to be copied to the stack.
I am not sure why the author mentioned arrays, since an array cannot be passed to a function by value unless it is contained in a struct.
Is passing pointer argument, pass by value in C++? Since i see that any change to the pointer as such is not reflected outside the method. The changes i do by dereferencing the pointer is reflected though.
In that case, is it acceptable/standard procedure to use pointer to pointer as argument to a function to modify the pointer value as such within a function?
Yes to both.
Pointers are passed by value as anything else. That means the contents of the pointer variable (the address of the object pointed to) is copied. That means that if you change the value of the pointer in the function body, that change will not be reflected in the external pointer that will still point to the old object. But you can change the value of the object pointed to.
If you want to reflect changes made to the pointer to the external pointer (make it point to something else), you need two levels of indirection (pointer to pointer). When calling functions it's done by putting a & before the name of the pointer. It is the standard C way of doing things.
When using C++, using references is preferred to pointer (henceforth also to pointer to pointer).
For the why references should be preferred to pointers, there is several reasons:
references introduce less syntaxic noise than pointers in function body
references keep more informations than pointers, than can be useful for compiler
Drawbacks of references are mostly:
they break the simple pass-by-value rule of C, what makes understanding the behavior of a function regarding of parameters (will they be changed ?) less obvious. You also need function prototype to be sure. But that is not really worse than the multiple pointer levels necessary when using C.
they are not supported by C, that can be a problem when you write code that should work with both C and C++ programs (but that's not the most usual case).
In the specific case of pointer to pointer, the difference is mostly simplicity, but using reference it may also be easy to remove both levels of pointers and pass only one reference instead of a pointer to pointer.
I understand the confusion here. The concepts of "pass by value" and "pass by reference" are not so clear even if they seem to be so.
Bear in mind that the computer does not know these concepts and does not behave according to it.
The computer does not know about the types. Hence it does not make a distinction of pointers and values.
Let me try to explain by and example:
void func1(int x) //copy some value to local variable x (of type int)
{
x = 5; //modify local variable. lost after function call
}
void func2(int *x) //copy some value to local variable x (of type int*)
{
int a;
x = &a; //modify local variable. lost after function call.
}
void func3(int *x) //copy some value to local variable x(of type int*)
{
*x = 10; //x is local but *x is not! change is saved after function call!
}
func1 and func2 are identical. Both modify a local variable. Modification is lost after function is popped off the stack.
func3 has ability to change another memory location (a variable which is not local to the function).
basically, every function call is "call by value". But in the case of a pointer type, we have a way to change the content of a remote address in memory.
Pass by value using Pointers
I'll explain it by example:
void f(int *ptr)
{
cout<<*ptr;
}
int main ()
{
int a=10;
int *aptr=&a;
f(aptr);
return 0;
}
Here, in main function a is an integer variable whose content is 10 and address is 00F8FB04 (assume).
aptr is pointer to integer, that store the address of integer variable a, so aptr content is address of integer variable a that is 00F8FB04. When we pass aptr as the function argument only content of aptr (that is address) are copies to function parameter.
So, ptr will receive the copy of content of aptr (that is address 00F8FB04)
Either a pointer to a pointer, or a reference to a pointer, is what you would use if you wanted to potentially change the pointer itself. To your original question, technically, yes, all parameters are passed by value.
Yes it is, as it is in C.
In that case, is it acceptable/standard procedure to use pointer to pointer as argument to a function to modify the pointer value as such within a function?
In which case? What do you want? You can use real references with the & modifier.
void func(type &ref);
When declaring a function, what is the difference between the parameters string* and string&? I know that string s would make a copy of the string s and pass it by value, but it seems that on many websites, they refer to string* s and string& s as both passing by reference. I am new to C++ and this is the only thing that i have not been able to figure out myself. Thanks in advance :)
Decent explanation here:
http://www.cprogramming.com/tutorial/references.html
(Hint: there is more to it than "it looks different")
Passing by pointer string* s passes in an address, so s is not of type string, it's an address. If you dereferenced it, that is used some expression including *s, then *s is of string type.
When passing by reference string& s, s is of type string, so no dereferencing is necessary.
Lots of almost right answers. Many are right for particular implementations but rely on unspecified behavior on the part of a compiler.
Aside from the . vs ->:
pointers are first class objects and references are not. You can take the address of a pointer but you cannot take the address of a reference (you'll get the address of the referenced object)
references always refer to the same object for the duration of their lifetime. Non-const pointers can change.
References cannot be to a "null object". You can write code that does this but you're relying on unspecified compiler behavior
You can do arithmetic on pointers
In general, the language spec says very little about references, purposefully giving compiler writers a lot of latitude in implementaiton. The fact that they operate a lot like const pointers is not guaranteed by the spec.
I find pointer parameters quite useful in two ways:
The caller has to pass a pointer which could very well be the address of an automatic variable. This makes it obvious to the person reading the calling code that the variable whose address is being passed is likely to change.
Pointers can have a NULL value, which acts like a sentinel. References cannot do that. For example, in your own example of string & versus string *, an empty string could be an acceptable value for the variable and hence useless as a sentinel. However, a NULL value for the pointer parameter tells your function that the string * argument was not set by the caller. The function that receives a string & has no way to determine if the caller has not set the value or is content with the default initialized value.
The main difference is how the function will be called. Consider these examples:
void f(string *s)
{}
int main() {
string s;
f(&s);
}
and the reference version:
void f(string &s) { }
int main() {
string s;
f(s);
}
So the function call looks different...
`
I'm coming from C# and I'm learning C++ (with this tutorial) so I have a relatively insubstantial amount of knowledge on memory, but the only use I see in pointers is "saving space" and iterating through arrays. So why do functions like the scanf function take pointers as parameters? For instance:
printf("What's your name?: ");
and then:
scanf("%s",&userName). Wouldn't it make more sense to just pass the variable itself as an argument? The C book I was looking at said that using the variable itself would produce unexpected results, but I don't see why. Could anyone please enlighten me in a C++ fashion? I switched from learning C because I realized how much I love OOP.
There are 3 different ways of passing a variable to a function in C++, pass by copy, pass by reference and pass by pointer.
#include <iostream>
void passByCopy(int a)
{
a += 1;
}
void passByReference(int &a)
{
a += 1;
}
void passByPointer(int *a)
{
(*a) += 1; // De-reference then increment.
}
int main()
{
int a = 0;
// Passing by copy, creates a copy of the 'a' object, then sends it to the function.
passByCopy(a);
std::cout << a << std::endl; // Outputs 0
// Passing by reference, causes the 'a' object in the function to reference the 'a'
// object at this scope. The value of 'a' will change.
passByReference(a);
std::cout << a << std::endl; // Outputs 1
// Passing by pointer, does almost the same thing as a pass by reference, except a
// pointer value can by NULL, while a reference can't.
passByPointer(&a);
std::cout << a << std::endl; // Outputs 2
}
With scanf, the purpose of the function is to pass values to variables in the current scope, so it can't use pass by copy. It doesn't use pass by reference for two reasons, one is that it is an old C function, so pass by reference didn't exist when it was written. The second is that it is a variadic function, which means that internally the function receives a list of pointers rather than a series of arguments.
C and C++ pass variables by value; the formal parameter is a different object in memory from the actual parameter. Thus, if the formal parameter is modified in the function, the value of the actual parameter isn't changed.
By passing a pointer, the function can modify the contents of the actual parameter:
void swap(int *a, int *b)
{
int t = *a;
*a = *b;
*b = t;
}
...
swap(&x, &y);
Thus, writing to *a in swap is equivalent to writing to x in the caller.
Pointers in C serve three main purposes:
Faking pass-by-reference semantics, as above (as Karl notes in the comments, C++ has a mechanism that supports true pass-by-reference);
Tracking dynamically-allocated memory (the memory allocation functions malloc, calloc, and realloc and the C++ new operator return pointer values);
Building dynamic data structures (trees, lists, queues, stacks, etc.).
All parameters are passed by value in C. If you want to pass by reference, you need to explicitly pass the address of the variable in question. Passing by reference is important when you want the function to modify the variable passed in.
C++ has references, but since C++ code often calls C library functions, you still see the same syntax used in C++ sometimes.
In your specific example, scanf is part of the C standard library. C does not have a string class, so strings are represented as arrays of characters.
In C, the address of the first character is usually passed when strings are required. This can either be &str[0] or str. I'm not sure it's correct to have &username if it's expecting a char *, I guess it depends on username.
C has no concept of passing by reference and can return only a single value. The traditional purpose of passing by pointer is therefore to allow the called function to write to a variable so that the caller can read what has been written.
C++ has the ability to pass by reference, but scanf and printf are C functions that are also available when building as C++ so that isn't available to them.
EDIT: to explain further, even putting beside the variable arguments issue, in the following code:
void calledFunction(int var1, int var2)
{
var1 = 23;
var2 = 19;
}
void callingFunction(void)
{
int v1 = 9, v2 = 18;
calledFunction(v1, v2);
printf("%d %d", v1, v2);
}
The output is "9 18". calledFunction gets local copies of v1 and v2 because C passes by value, meaning that the values of v1 and v2 were passed in, but no other link was kept to the originals. So the fact that it modifies its copies has no effect on the originals.
In C there are no references, all the arguments are passed by value.
If scanf would be in C# then its parameters would be preceded by out or ref keyword and no pointers would be needed. Passing pointers allow the scanf function to write some values to whatever place the pointers point to.
In C++ however there are references, though different from what you know from C#. Nonetheless if you'd use iostream library and not stdio which was inherited to C++ from C, then you wouldn't have to use pointers in this way. You'd just write:
String username;
cin >> username;
One other use of pointers that I don't see mentioned in the other anwers here is that it's one of only two ways that a C function can return multiple values. A C function is defined to return a single object, but it can receive many arguments. If your multi-valued function always returns the same set of values, it's a question of convenience whether to wrap the values in a struct and have the function return the struct or have the function receive pointers through which it can write the values.
The pointer-parameter option becomes much more attractive if the function also needs to return a status or error code (because it's silly to write that through a pointer, forcing the caller to allocate another variable and obstructing standard idioms like if(f()==ERROR)...). And if the set of values is not predictable at compile time (like scanf, which must interpret the format string at runtime), then pointer-parameters become the only (sensible) option.
Edit: In your example, scanf("%s",&username); assuming username is an array type or a pointer to storage suitable for holding a character string, you don't need to pass the address. If it's an array, it will be passed as a pointer implicitly. And if it already is a pointer, taking the address yields a pointer-to-pointer, which is not suitable to hold a string. So drop the & here.
scanf is a C function. C doesn't have references, so it has to use pointers in order to write to arguments. Also, scanf is a varargs function, so it takes variable numbers of arguments. And varargs functions can only take built-in types: pointers (to anything), integers, doubles.
I'm currently reading through Accelerated C++ and I realized I don't really understand how & works in function signatures.
int* ptr=#
means that ptr now holds the address to num, but what does that mean?
void DoSomething(string& str)
from what I understand that is a pass by reference of a variable (which means passing the address) but when I do
void DoSomething(string& str)
{
string copy=str;
}
what it creates is a copy of str. What I thought it would do is raise an error since I'm trying to assign a pointer to a variable.
What is happening here? And what is the meaning of using * and & in function calls?
A reference is not a pointer, they're different although they serve similar purpose.
You can think of a reference as an alias to another variable, i.e. the second variable having the same address. It doesn't contain address itself, it just references the same portion of memory as the variable it's initialized from.
So
string s = "Hello, wordl";
string* p = &s; // Here you get an address of s
string& r = s; // Here, r is a reference to s
s = "Hello, world"; // corrected
assert( s == *p ); // this should be familiar to you, dereferencing a pointer
assert( s == r ); // this will always be true, they are twins, or the same thing rather
string copy1 = *p; // this is to make a copy using a pointer
string copy = r; // this is what you saw, hope now you understand it better.
The & character in C++ is dual purpose. It can mean (at least)
Take the address of a value
Declare a reference to a type
The use you're referring to in the function signature is an instance of #2. The parameter string& str is a reference to a string instance. This is not just limited to function signatures, it can occur in method bodies as well.
void Example() {
string s1 = "example";
string& s2 = s1; // s2 is now a reference to s1
}
I would recommend checking out the C++ FAQ entry on references as it's a good introduction to them.
https://isocpp.org/wiki/faq/references
You shouldn't know anything about pointers until you get to chapter 10 of Accelerated C++ !
A reference creates another name, an alias, for something that exists elsewhere. That's it. There are no hidden pointers or addresses involved. Don't look behind the curtain!
Think of a guy named Robert
guy Robert;
Sometimes you may want to call him Bob
guy& Bob = Robert;
Now Bob and Robert both refer to the same guy. You don't get his address (or phone number), just another name for the same thing.
In your function
void DoSomething(string& str)
{
string copy=str;
}
it works exactly the same, str is another name for some string that exists somewhere else.
Don't bother with how that happens, just think of a reference as a name for some object.
The compiler has to figure out how to connect the names, you don't have to.
In the case of assigning variables (ie, int* ptr = &value), using the ampersand will return the address of your variable (in this case, address of value).
In function parameters, using the ampersand means you're passing access, or reference, to the same physical area in memory of the variable (if you don't use it, a copy is sent instead). If you use an asterisk as part of the parameter, you're specifying that you're passing a variable pointer, which will achieve almost the same thing. The difference here is that with an ampersand you'll have direct access to the variable via the name, but if you pass a pointer, you'll have to deference that pointer to get and manipulate the actual value:
void increase1(int &value) {
value++;
}
void increase2(int *value) {
(*value)++;
}
void increase3(int value) {
value++;
}
Note that increase3 does nothing to the original value you pass it because only a copy is sent:
int main() {
int number = 5;
increase1(number);
increase2(&number);
increase3(number);
return 0;
}
The value of number at the end of the 3 function calls is 7, not 8.
It's a reference which allows the function to modify the passed string, unlike a normal string parameter where modification would not affect the string passed to the function.
You will often see a parameter of type const string& which is done for performance purposes as a reference internally doesn't create a copy of the string.
int* ptr=#
1st case: Since ptr is a memory and it stores the address of a variable. The & operator returns the address of num in memory.
void DoSomething(string& str)
2nd case: The ampersand operator is used to show that the variable is being passed by reference and can be changed by the function.
So Basically the & operator has 2 functions depending on the context.
While pass by reference may be implemented by the compiler by passing the address as a pointer, semantically it has nothing to do with addresses or pointers. in simple terms it is merely an alias for a variable.
C++ has a lot of cases where syntax is reused in different contexts with different semantics and this is one of those cases.
In the case of:
int* ptr=#
you are declaring a variable named ptr with a type of an int * (int pointer), and setting its value to the "address of the variable num" (&num). The "addressof" operator (&) returns a pointer.
In the case of:
void DoSomething(string& str)
you are declaring the first parameter of the DoSomething() method to be of type "reference to string". Effectively, this is the C++ way of defining "pass-by-reference".
Note that while the & operator operates similarly in these cases, it's not acting in the same way. Specifically, when used as an operator, you're telling the compiler to take the address of the variable specified; when used in a method signature, you're telling the compiler that the argument is a reference. And note as well, that the "argument as a reference" bit is different from having an argument that is a pointer; the reference argument (&) gets dereferenced automatically, and there's never any exposure to the method as to where the underlying data is stored; with a pointer argument, you're still passing by reference, but you're exposing to the method where the variable is stored, and potentially exposing problems if the method fails to do a dereference (which happens more often than you might think).
You're inexplicitly copy-constructing copy from str. Yes, str is a reference, but that doesn't mean you can't construct another object from it. In c++, the & operator means one of 3 things -
When you're defining a normal reference variable, you create an alias for an object.
When you use it in a function paramater, it is passed by reference - you are also making an alias of an object, as apposed to a copy. You don't notice any difference in this case, because it basically is the object you passed to it. It does make a difference when the objects you pass contain pointers etc.
The last (and mostly irrelevent to your case) meaning of & is the bitwise AND.
Another way to think about a reference (albeit slightly incorrect) is syntactic sugar for a dereferenced pointer.