C# has two different types of variables: value types and reference types. While in C and C++ primitive types can contain values or references and certain complex types (arrays, objects) can only be used via reference, in C# the line between the two types is very clear. Numeric types(int, decimal, double, etc.), bool and structs access the values directly. Class, object, interface, delegate string and dynamic are only accessed and used via reference. Because of all the awkwardness with referencing and dereferencing in C and C++, C# uses the 'ref' keyword only for those cases where you want to modify a value type outside of your current scope.
If you've worked with C# a bit you're probably used to always working with copies in any situation outside of simple assignment (=). If you loop over a collection, inside the loop you're working with copies. If you pass something to a function, that something is a copy. However the difference between value types and reference types often means a copy isn't always a copy. Knowing when this is not the case can help you spot troublesome bugs, and easily solve problems that might have taken you much longer.
Here are a few example cases:
Example class:

class MyClass
    public int Value;
    public MyClass(int value) { this.Value = value; }
    public static void Increment1(int i) { i++; }
    public static void Increment2(ref int i) { i++; }
    public static void Increment3(MyClass o) { o.Value++; }


int i = 9;
int j = i; //j stores a copy of the value of i
var myObject = new MyClass(9);
var myObject2 = myobject; // myObject2 stores a copy of the reference to myObject so any
                          // modifications to myObject2 will be reflected in myObject as well

Looping over a list:

List myList = new List{1, 2, 3};
List myObjectList = new List { new MyClass(1), new MyClass(2), new MyClass(3) };
foreach(var i in myList)
    i++; //doesn't change anything in the original list since i is a copy
foreach(var o in myObjectList)
    o.Value++; // o is a copy of the reference to each o object, so any operations on its interior
               // values change the original object
foreach(var o in myObjectList)
    o = new MyClass(o.Value++); // doesn't change anything since you're assigning a new reference
                                // to a variable that contains a copy of the reference to the

// original object
Method calls:

int i = 9;
var o = new MyClass(9);
MyClass.Increment1(i); // does nothing since it's working on a copy of i
MyClass.Increment2(ref i); // works since i is passed by reference
MyClass.Increment3(o); // works since a copy of the reference to o is passed so any work on o's
                       // members changes the location in memory o refers to, not o itself