Going from your comment to Evan Li ("string is also kind of an array, and it is initialized with a pointer. Thus, arrays should be also initialized this way."). If the instructor actually told you this, I'd seriously think about finding a new instructor, because he's confused about things.
A string literal is an array expression; the literal "Hello" is a 6-element array of char (const char in C++). String literals are stored in such a way that their memory is allocated over the lifetime of the program; this memory may or may not be read-only, depending on the platform. The behavior on attempting to modify the contents of a string literal is undefined, meaning you may get a segfault, or the string may get modified, or something else happens.
When an array expression appears in a context other than as an operand to the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration, then the type of the expression is converted ("decays") from "N-element array of T" to "pointer to T", and the value of the expression is the address of the first element of the array.
That's why you can write something like
char *foo = "This is a test";
The string literal "This is a test" is an array expression of type "15-element array of char"; since it isn't the operand of the sizeof or & operators, and isn't being used to initialize another array of char, the type of the expression becomes "pointer to char", and the address of the first character is assigned to foo. By comparison,
char foo[] = "This is a test";
declares foo as an array of char; the size is computed from the size of the initializer string (15 characters), and the contents of the string literal are copied to foo.
A string is an array expression; a brace-enclosed list of values is not.
int *foo = {1, 2, 3};
won't create a 3-element array of int and assign the address of the first element to foo; instead, this should be a constraint violation if I'm reading this right:
6.7.9 Initialization
Constraints
2 No initializer shall attempt to provide a value for an object not contained within the entity
being initialized.
As of C99, you can use what are known as compound literals, like so:
int *foo = (int []) {1, 2, 3};
The cast-expression (int []) is required. This does create a new 3-element array of int and assigns the address of the first element to foo. Unlike string literals, compound literals like this only exist for the duration of the enclosing block1; IOW, if you did something like
int *foo = NULL;
if (condition())
{
foo = (int []){1, 2, 3};
// do stuff
}
// do more stuff
the anonymous array object pointed to by foo only exists within the if block; once the if block exits, the array no longer exists, and the value of foo is no longer valid.
1. If the compound literal is defined at file scope (outside of any function), then it has static duration and exists for the lifetime of the program.
int *arr = (int []){2, 3, 4};'