Each of the three lines triggers undefined behavior.  The key part of the C standard, that explains this, is section 6.3.2.1p2 regarding Conversions:
Except  when  it  is  the  operand  of  the sizeof operator,  the
_Alignof operator,  the unary & operator, the ++ operator, the
-- operator, or the left operand of the . operator or  an
assignment  operator,  an  lvalue  that  does  not  have  array  type
is  converted  to  the value  stored  in  the  designated  object
(and  is  no  longer  an  lvalue);  this  is  called lvalue
conversion. If the  lvalue  has  qualified  type,  the  value  has
the  unqualified  version  of  the type of the lvalue; additionally,
if the lvalue has atomic type, the value has the non-atomic version
of  the  type  of  the  lvalue;  otherwise,  the  value  has  the
type  of  the  lvalue.   If the lvalue has an incomplete type and does
not have array type, the behavior is undefined.  If the  lvalue
designates  an  object  of  automatic  storage  duration  that  could
have  been declared with the register storage class (never had its
address taken), and that object is  uninitialized  (not  declared
with  an  initializer  and  no  assignment  to  it  has  been
performed prior to use), the behavior is undefined.
In each of the three cases, an uninitialized variable is used as the right-hand side of an assignment or initialization (which for this purpose is equivalent to an assignment) and undergoes lvalue to rvalue conversion.  The part in bold applies here as the objects in question have not been initialized.
This also applies to the int i = i; case as the lvalue on the right side has not (yet) been initialized.
There was debate in a related question that the right side of int i = i; is UB because the lifetime of i has not yet begun. However, that is not the case.  From section 6.2.4 p5 and p6:
5 An  object  whose  identifier  is  declared  with  no  linkage  and  without  the  storage-class specifier static has automatic
storage  duration, as do some  compound  literals.  The result of
attempting to indirectly access an object with automatic storage
duration from a thread other than the one with which the object is
associated is implementation-defined.
6 For  such  an  object  that  does  not  have  a  variable  length  array  type,  its  lifetime  extends from entry into the block
with which it is associated until execution of that block ends in any
way.  (Entering  an  enclosed  block  or  calling  a  function
suspends,  but  does  not  end,execution of the current block.)  If
the block is entered recursively, a new instance of the object  is
created  each  time.   The  initial  value  of  the  object  is
indeterminate.   If  an initialization  is  specified  for  the
object,  it  is  performed  each  time  the  declaration  or compound
literal  is  reached  in  the  execution  of  the  block;  otherwise,
the  value  becomes indeterminate each time the declaration is reached
So in this case the lifetime of i begins before the declaration in encountered.  So int i = i; is still undefined behavior, but not for this reason.
The bolded part of 6.3.2.1p2 does however open the door for use of an uninitialized variable not being undefined behavior, and that is if the variable in question had it's address taken.  For example:
int a;
printf("%p\n", (void *)&a);
printf("%d\n", a);
In this case it is not undefined behavior if:
- The implementation does not have trap representations for the given type, OR
- The value chosen for ahappens to not be a trap representation.
In which case the value of a is unspecified.  In particular, this will be the case with GCC and Microsoft Visual C++ (MSVC) in this example as these implementations do not have trap representations for integer types.