Q:

String constants and arrays in C

In C, we can make a pointer to a constant string like 
char *s = "abc";

But since strings are basically null terminated character arrays, why isn't this allowed?
char *s = {'a', 'b', 'c' , '\0' };

A:

It's basically because the language doesn't allow it.
A string literal is an expression of type char[N+1], where N is the length of the literal. It refers to an anonymous array object with static storage duration, meaning that the object exists for the entire execution of the program.
(Note that, unlike in C++, it's not const char[N+1], but attempting to modify it has undefined behavior.)
And like any expression of array type, it's implicitly converted to a pointer to the array's first element in most contexts.
So in this declaration:
char *s = "abc";

the expression "abc" is implicitly converted to a pointer to the first character of the
array, which is used to initialize s.  But it's much safer to write it like this:
const char *s = "abc";

so that you don't accidentally attempt to modify the array.
So why doesn't this work?
char *s = { 'a', 'b', 'c', '\0' };

It's because { 'a', 'b', 'c', '\0' } is not an expression. It's an initializer, and can be used to initialize an array object, but it can't be used to initialize a pointer object. If you instead write:
char arr[] = { 'a', 'b', 'c', '\0' };

then the initializer is used to initialize the array object; it doesn't create an array object. For the char *s version to work, it would have to create an object for the pointer s to point to. Brace-enclosed initializer lists just don't do that.
C99 added a new feature, compound literals, that are in some ways similar to string literals but more general. For example, this:
(char[]){ 'a', 'b', 'c', '\0' }

is an expression of type char[4] -- and again, like any expression of array type, it's implicitly converted to a pointer in most contexts. So this:
char *arr = (char[]){ 'a', 'b', 'c', '\0' };

is valid and makes arr point to the first element of the anonymous array object created by the compound literal.
There is one significant difference: the lifetime of that array object is not necessarily static. If a compound literal appears outside any function, the array object does exist for the entire execution of the program; otherwise, it acts like a local object with automatic storage duration.
If you're using a compiler that doesn't support C99 (*cough*Microsoft*cough*), you can always declare an array object first:
const char arr[] = { 'a', 'b', 'c', '\0' };
const char *s = arr;

See also section 6 of the comp.lang.c FAQ, which discusses arrays and pointers (and does an excellent job of clearing up some of the common misconceptions about them).

A:

This is because a pointer is not an array. (You can have an array decay to a pointer that points to the address of the first element, but that doesn't make a pointer an array.)
You can do this:
   char s[] = {'a', 'b', 'c', '\0'};
// ^^^^^^^^   ^^^^^^^^^^^^^^^^^^^^^
// array      valid initializer for char[]

But not this:
   char* s = {'a', 'b', 'c', '\0'};
// ^^^^^^^   ^^^^^^^^^^^^^^^^^^^^^
// pointer   invalid initializer for char*

A:

You can code this:
 char s[] = { 'a', 'b', 'c', '\0` };

which is the same as
 char s[] = "abc";

However, string literals are actually read only (since in the text segment). So you should understand a string literal as a const char s[] (even if it is not exactly that, if you care precisely about the C standard). In particular coding "abc"[1] = 'X'; is undefined behavior (and would probably crash with a segmentation violation on Linux).
Recent compilers (e.g. Clang/LLVM 3.2 or GCC 4.8) would probably warn you if you enable all warnings e.g. with gcc -Wall
Of course, pointers and arrays are not the same in C (arrays can decay to pointers), as this answer explains.

