String literals have types of character arrays. For example the string literal "John" has type char[5] (string literals include the terminating zero).
Used in expressions arrays with rare exceptions are converted to pointers to their first elements.
You can imagine this declaration
char *names[] = { "John", "Paul", "George", "Ringo" };
like
char *names[] = { &"John"[0], &"Paul"[0], &"George"[0], &"Ringo"[0] };
Thus the array names is initialized by valid addresses of first characters of the string literals.
As for this declaration
int *numbers[] = { 11, 12, 13, 14 };
then the array numbers is initialized by invalid addresses values like 11, 12 and so on that do not point to actual objects.
You could write for example
int i = 11, j = 12, k = 13, l = 14;
and then
int *numbers[] = { &i, &j, &k, &l };
In this case the array would be initialized by valid addresses.
As for the printf calls then the function is designed such a way that when the conversion specifier s is encountered the function considers the corresponding argument as an address of a zero-terminating string and tries to output this string.
While the conversion specifier d serves to output objects of the type int. So for example if you want to output the integer pointed to by numbers[0] then you should write
printf("%d\n", *numbers[0] );