I would add to Mehdi's excellent answer, that Value types also differ from "reference" types in terms of the way they are stored in memory: value types are allocated on a Stack (or, as in the case of Constants, or Struct, can be allocated in-line by the compiler, depending).
Value types also all derive from System.ValueType, their immediate "ancestor," which derives from "Object." ValueType over-rides some methods in Object to provide more tightly-coupled functionality for value types.
And when we use many value-types, like 'int,' in our code, we are really using an alias: 'int' is expanded by the compiler to 'System.Int32.' Value types that have these 'aliases' (to save us typing ?) are called by MS "Simple Types."
Assigning one value-type to another actually copies the value.
While this usage is not seen very often (in my experience) you can use the 'new' operator to initialize a value-type:
int someInt = new Int(); // valid: value will be set to default which is #0
int someOtherInt = 0; // equally valid as an 'initializer
So, why is it that so many times you observe no explicit setting of value-types, or creation by use of 'new' ... but they still 'work' (i.e., have default values): the answer is because they are defined in some structure (struct, class, etc.) that when initialized by 'new sets its internal value-type variables to their default values.
An example:
public class someClass
{
public int someInt;
public string someString;
}
When you create a new instance of 'someClass: 'someInt is set to #0, and 'someString is set to 'null : they are immediately 'usable.'