Assign pointer type to string type - c

I'm expecting a compile error , taking into account that a pointer has to be assigned in %p, but the codes below doesn't give me error when i intentionally assign a pointer to %s. By adding an ampersand &, by right it should generate the address of the array and assign the memory address into %p, instead of giving the value of the string. Unless I dereference the pointer, but I don't dereference the pointer at all, I never put an asterisk * in front of my_pointer in printf.
#include <stdio.h>
int main()
{
char words[] = "Daddy\0Mommy\0Me\0";
char *my_pointer;
my_pointer = &words[0];
printf("%s \n", my_pointer);
return 0;
}
please look at this :
printf("%s \n", my_pointer);
My understanding is , *my_pointer (with asterisk *)should give me the value of the string.
But my_pointer (without asterisk) shouldn't give me the value of the string, but it should give me only the memory address,but when I run this code, I get the value of string eventhough I didn't put the asterisk * at the front. I hope I'm making myself clear this time.

Here:
printf("%s \n", my_pointer);
%s, expects a char* and since my_pointer is a char* which points to an array holding a NUL-terminated string, the printf has no problems and is perfectly valid. Relevant quote from the C11 standard (emphasis mine):
7.21.6.1 The fprintf function
[...]
The conversion specifiers and their meanings are:
[...]
s - If no l length modifier is present, the argument shall be a pointer to the initial
element of an array of character type. 280) Characters from the array are
written up to (but not including) the terminating null character. If the
precision is specified, no more than that many bytes are written. If the
precision is not specified or is greater than the size of the array, the array shall
contain a null character.
[...]
IMO, You are being confused here:
taking into account that a pointer has to be assigned in %p, but the codes below doesn't give me error when i intentionally assign a pointer to %s
First of all, %s, %p etc are conversion specifiers. They are used in some functions like printf, scanf etc.
Next, you are the one specifying the type of the pointers. So here:
my_pointer = &words[0];
&words[0] as well as my_pointer is of type char*. Assigning these two is therefore perfectly valid as both are of the same type.

The compiler is treating your code exactly as it is required to.
The %s format specifier tells printf() to expect a const char * as the corresponding argument. It then deems that pointer to be the address of the first element of an array of char and prints every char it finds until it encounters one with value zero ('\0').
Strictly speaking, the compiler is not even required to check that my_pointer is, or can be implicitly converted to, a const char *. However, most modern compilers (assuming the format string is supplied at compile time) do that.

In c, array name is also pointer to the first element, means in your case words and &words[0] when as a pointer, they have the same value.
And, you assign it to another pointer of the same type, so this is legal.
About string in c, it's just an array of chars ending with '\0', with its name pointer to the first char.

Related

Dereferencing char pointer returns int ? why? [duplicate]

This question already has answers here:
Char pointers and the printf function
(6 answers)
Closed 1 year ago.
For example, the following code returns an error and a warning when compiled and an int when changed to %d
Warning:
format %s expects argument of type char *, but argument 2 has type int
void stringd() {
char *s = "Hello";
printf("derefernced s is %s", *s);
}
*s is an expression of type char since it's the dereference operator applied to a pointer-to-char1. As a result, it gets promoted to an int when passed to printf; in order to print a null-terminated string, you need to pass the pointer to the first character (i.e. just s).
1 even though s is not a const pointer, you should not try to modify the characters it points to as they may be placed in read-only memory where string literals are stored on some architectures/environments; see this discussion for more details.
The variable s is a pointer to the first out of a series of characters which are consecutive in memory (colloquially referred to as a "string", though it's not quite the same). It's a pointer to a character, thus char *.
Dereferencing s (by doing *s) gives you the first of those characters, h, whose type is now just char. One layer of indirection was stripped away.
Thus, the issue is that you're trying to pass a character (char), where a string (char *) was expected. char * was expected because you used the %s type character in your format string to printf. Instead, you should use %c, which expects single, simple char.
The mistake here is actually quite grave. If you were allowed to pass this 'h' where a char * was expected, you would end up with the ASCII code of 'h' (0x68) being passed where a pointer was expected. printf would be none-the-wiser, and would try to dereference that value, treating 0x68 like a pointer to the beginning of a string. Of course, that's probably not a valid memory location in your program, so that should seg-fault pretty reliability, if it were allowed to happen.

What is different between array String and common array in C?

#include<stdio.h>
int main()
{
char str[7];
scanf("%s",&str);
for(i=0; i<7; i++)
{
printf("%x(%d) : %c\n",&str[i], &str[i], str[i]);
}
printf("\n\n%x(%d) : %c or %s",&str, &str, str, str);
return 0;
}
I'm confused about pointer of C Array because of Array with String.
Actually I want to save each character for single line input.
It is worked but I found something strange...
The main issue is &str and &str[0] have same address value.
But str have String Value with %s..
str[0] have Char Value with %c..
I used str with %c then it has first two numbers of str's address.
What is going on in Array..?
Where is real address for Stirng value??
And how can scanf("%s",&str) distribute String to each char array space?
Input : 123456789
62fe40(6487616) : 1
62fe41(6487617) : 2
62fe42(6487618) : 3
62fe43(6487619) : 4
62fe44(6487620) : 5
62fe45(6487621) : 6
62fe46(6487622) : 7
62fe40(6487616) : # 123456789
This is result window of my code.
You are confused because the string and the array are the same thing. - In the memory there are only data (and pointers to that data)
When you allocate an integer or a buffer for a string you reserve some of this memory. Strings in c is defined as a sequence of bytes terminated by one byte with the value 0 - The length is not known. With the fix length array you have a known size to work with.
The real value to the string is the pointer to the first character.
When you print with %c it expects a char - str[0] not the pointer - When you print with %s it expects a pointer to a sequence of chars.
printf("\n\n%x(%d) : %c or %s",&str, &str, str[0], str);
What is different between array String and common array in C?
An array is a contiguous sequence of objects of one type.1
A string is a contiguous sequence of characters terminated by the first null character.2 So a string is simply an array of characters where we mark the end by putting a character with value zero. (Often, strings are temporarily held in larger arrays that have more elements after the null character.)
So every string is an array. A string is simply an array with two extra properties: Its elements are characters, and a zero marks the end.
&str and &str[0] have same address value.
&str is the address of the array. &str[0] is the address of the first element.
These are the same place in memory, because the first element starts in the same place the array does. So, when you print them or examine them, they will often appear the same. (Addresses can have different representations, the same way you might write “200” or “two hundred” or “2•102” for the same number. So the same address might sometimes look different. In most modern systems, an address is just a simple number for a place in memory, and you will not see differences. But it can happen.)
printf("%x(%d) : %c\n",&str[i], &str[i], str[i]);
This is not a correct way to print addresses. To print an address properly, convert it to void * and use %p3:
printf("%p(%p) : %c\n", (void *) &str[i], (void *) &str[i], str[i]);
printf("\n\n%x(%d) : %c or %s",&str, &str, str, str);
…
I used str with %c then it has first two numbers of str's address.
In the above printf, the third conversion specification is %c, and the corresponding argument is str. %c is intended to be used for a character,4 but you are passing it an argument that is a pointer. What may have happened here is that printf used the pointer you passed it as if it were an int. Then printf may have used a part of that int as if it were a character and printed that. So you saw part of the address shown as a character. However, it is a bit unclear when you write “it has the first two numbers of str's address”. You could show the exact output to clarify that.
Although printf may have used the pointer as if it were an int, the behavior for this is not defined by the C standard. Passing the wrong type for a printf conversion is improper, and other results can occur, including the program printing garbage or crashing.
And how can scanf("%s",&str) distribute String to each char array space?
The proper way to pass str to scanf for %s is to pass the address of the first character, &str[0]. C has a special rule for arrays like str: If an array is used in an expression other than as the operand of sizeof or the address-of operator &, it is converted to a pointer to its first element.5 So, you can use scanf("%s", str), and it will be the same as scanf("%s", &str[0]).
However, when you use scanf("%s",&str), you are passing the address of the array instead of the address of the first character. Although these are the same location, they are different types. Recall that two different types of pointers to the same address might have different representations. Because scanf does not have knowledge of the actual argument type you pass it, it must rely on the conversion specifier. %s tells scanf to expect a pointer to a character.6 Passing it a pointer to an array is improper.
C has this rule because some machines have different types of pointers, and some systems might pass different types of pointers in different ways. Nonetheless, often code that passes &str instead of str behaves as the author desired because the C implementation uses the same representation for both pointers. So scanf may actually receive the pointer value that it needs to make %s work.7
Footnotes
1 C 2018 6.2.5 20. (This means the information comes from the 2018 version of the C standard, ISO/IEC 9899, Information technology—Programming Languages—C, clause 6.2.5, paragraph 20.)
2 C 2018 7.1.1 1. Note that the terminating null character is considered to be a part of the string, although it is not counted by the strlen function.
3 C 2018 7.21.6.1 8.
4 Technically, the argument should have type int, and printf converts it to unsigned char and prints the character with that code. C 2018 7.21.6.1 8.
5 C 2018 6.3.2.1 3. A string literal used to initialize an array, as in char x[] = "Hello";, is also not converted to a pointer.
6 C 2018 7.21.6.2 12.
7 Even if a C implementation uses the same representations for different types of pointers, that does not guarantee that using one pointer type where another is required will work. When a compiler optimizes a program, it relies on the program’s author having obeyed the rules, and the optimizations may change the program in ways that would not break a program that followed the rules but that do break a program that breaks the rules.
String is only some kind of the shorthand of the zero terminated char array. So there is no difference between the string and the "normal" array.
Where is real address for Stirng value??
Arrays are not pointers and they only decay to pointers. So there is no physical space in the memory where the address of the first element of the array is stored.
The main issue is &str and &str[0] have same address value.
It is not the issue - array is the chunk of memory. So the address of this chunk is the same as the address of its first element. The types are different.

Pointers and Characters Variables in C

I'm trying to store the memory location of the evil variable in the ptr variable, but instead of the memory location, the variable prints out the value within the variable and not it's location. Both the ptr variable and the &evil syntax print the same result which is the value of the variable and not it's location in memory. Could someone please nudge me in the right direction, and help me determine the syntax needed to store the memory location of a string/char variable in C?
int main()
{
char *ptr;
char evil[4];
memset(evil, 0x43, 4);//fill evil variable with 4 C's
ptr = &evil[0];//set ptr variable equal to evil variable's memory address
printf(ptr);//prints 4 C's
printf(&evil);//prints 4 C's
return 0;
}
That's normal, because the first parameter to printf is a format specifier, which is basically a char* pointing to a string. Your string will be printed as-is because it does not contain any format specifiers.
If you want to display a pointer's value as an address, use %p as a format specifier, and your pointer as subsequent parameter:
printf("%p", ptr);
However, note that your code invokes Undefined Behavior (UB) because your string is not null-terminated. Chances are it was null-terminated "out-of-luck".
Also notice that to be "correct code", cast the pointer to void* when sending it to printf, because different types of pointers may differ on certain platforms, and the C standard requires the parameter to be pointer-to-void. See this thread for more details: printf("%p") and casting to (void *)
printf("%p", (void*)ptr); // <-- C standard requires this cast, although it migh work without it on most compilers and platforms.
You need #include <stdio.h> for printf, and #include <string.h> for memset.
int main()
You can get away with this, but int main(void) is better.
{
char *ptr;
char evil[4];
memset(evil, 0x43, 4);//fill evil variable with 4 C's
This would be more legible if you replaced 0x43 by 'C'. They both mean the same thing (assuming an ASCII-based character set). Even better, don't repeat the size:
memset(evil, 'C', sizeof evil);
ptr = &evil[0];//set ptr variable equal to evil variable's memory address
This sets ptr to the address of the initial (0th) element of the array object evil. This is not the same as the address of the array object itself. They're both the same location in memory, but &evil[0] and &evil are of different types.
You could also write this as:
ptr = evil;
You can't assign arrays, but an array expression is, in most contexts, implicitly converted to a pointer to the array's initial element.
The relationship between arrays and pointers in C can be confusing.
Rule 1: Arrays are not pointers.
Rule 2: Read section 6 of the comp.lang.c FAQ.
printf(ptr);//prints 4 C's
The first argument to printf should (almost) always be a string literal, the format string. If you give it the name of a char array variable, and it happens to contain % characters, Bad Things Can Happen. If you're just printing a string, you can use "%s" as the format string:
printf("%s\n", ptr);
(Note that I've added a newline so the output is displayed properly.)
Except that ptr doesn't point to a string. A string, by definition, is terminated by a null ('\0') character. Your evil array isn't. (It's possible that there just happens to be a null byte just after the array in memory. Do not depend on that.)
You can use a field width to determine how many characters to print:
printf("%.4s\n", ptr);
Or, to avoid the error-prone practice of having to write the same number multiple times:
printf("%.*s\n", (int)sizeof evil, evil);
Find a good document for printf if you want to understand that.
(Or, depending on what you're doing, maybe you should arrange for evil to be null-terminated in the first place.)
printf(&evil);//prints 4 C's
Ah, now we have some serious undefined behavior. The first argument to printf is a pointer to a format string; it's of type const char*. &evil is of type char (*)[4], a pointer to an array of 4 char elements. Your compiler should have warned you about that (the format string has a known type; the following arguments do not, so getting their types correct is up to you). If it seems to work, it's because &evil points to the same memory location as &evil[0], and different pointer types probably have the same representation on your systems, and perhaps there happens to be a stray '\0' just after the array -- perhaps preceded by some non-printable characters that you're not seeing.
If you want to print the address of your array object, use the %p format. It requires an argument of the pointer type void*, so you'll need to cast it:
printf("%p\n", (void*)&evil);
return 0;
}
Putting this all together and adding some bells and whistles:
#include <stdio.h>
#include <string.h>
int main(void)
{
char *ptr;
char evil[4];
memset(evil, 'C', sizeof evil);
ptr = &evil[0];
printf("ptr points to the character sequence \"%.*s\"\n",
(int)sizeof evil, evil);
printf("The address of evil[0] is %p\n", (void*)ptr);
printf("The address of evil is also %p\n", (void*)&evil);
return 0;
}
The output on my system is:
ptr points to the character sequence "CCCC"
The address of evil[0] is 0x7ffc060dc650
The address of evil is also 0x7ffc060dc650
Using
printf(ptr);//prints 4 C's
causes undefined behavior since the first argument to printf needs to be a null terminated string. In your case it is not.
Could someone please nudge me in the right direction
To print an address, you need to use the %p format specifier in the call to printf.
printf("%p\n", ptr);
or
printf("%p\n", &evil);
or
printf("%p\n", &evil[0]);
See printf documentation for all the ways it can be used.
if you want to see the address of a char - without all the array / pointer / decay oddness
int main()
{
char *ptr;
char evil;
evil = 4;
ptr = &evil;
printf("%p\n",(void*)ptr);
printf("%p\n",(void*)&evil);
return 0;
}

Type of a pointer?

There are countless questions about pointers here on SO, and countless resources on the internet, but I still haven't been able to understand this.
This answer quotes A Tutorial on Pointers and Arrays in C: Chapter 3 - Pointers and Strings:
int puts(const char *s);
For the moment, ignore the const. The parameter passed to puts() is a pointer, that is the value of a pointer (since all parameters in C are passed by value), and the value of a pointer is the address to which it points, or, simply, an address. Thus when we write puts(strA); as we have seen, we are passing the address of strA[0].
I don't understand this, at all.
Why does puts() need a pointer to a string constant? puts() doesn't modify and return its argument, just writes it to stdout, and then the string is discarded.
Ignoring the why, how is it that puts()'s prototype, which explicity takes a pointer to a string constant, accepts a string literal, not a pointer to one? That is, why does puts("hello world"); work when puts()'s prototype would indicate that puts() needs something more like char hello[] = "hello world"; puts(&hello);?
If you give, for instance, printf() a pointer to a string constant, which is apparently what it wants, GCC will complain and your program will segfault, because:
error: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[6]’
But giving printf() a string constant, not a pointer to a string, works fine.
This Programmers.SE question's answers make a lot of sense to me.
Going off that question's answers, pointers are just numbers which represent a position in memory. Numbers for memory addresses are unsigned ints, and C is written in (native) C and assembly, so pointers are simply architecture-defined uints.
But this is not the case, since the compiler is very clear in its errors about how int, int * and int ** are not the same. They are a pathway that eventually points to something in memory.
Why do functions that need a pointer accept something which is not a pointer, and reject a pointer?
I'm aware a "string constant" is actually an array of characters but I'm trying to simplify here.
The expression "hello world" has type char[12].
In most contexts, use of an array is converted to a pointer to its first element: in the case of "hello world" it is converted to a pointer to the 'h', of type char*.
When using puts("Hello world"), the array is converted to char*.
Note that the conversion from array of specific size, loses the size information.
char array[42];
printf("size of array is %d\n", (int)sizeof array);
printf("size of pointer is %d\n", (int)sizeof &array[0]);
puts() doesn't need a pointer to a string, it needs a pointer (*) to a character (char). It happens that in C, a pointer to a character (char *) can be assimilated to a string (an array of chars), provided that the end of the string is a null character \0.
Why does puts() need a pointer to a string constant? puts() doesn't modify and return its argument, just writes it to stdout, and then the string is discarded.
puts receives a pointer to the first character in a string; it will then "walk" down that string until it sees a 0 terminator. A naive implementation would look something like this:
void puts( const char *ptr )
{
while ( *ptr ) // loop until we see a 0-valued byte
putchar( *ptr++ ); // write the current character, advance the pointer
// to point to the next character in the string.
putchar( '\n' );
}
Ignoring the why, how is it that puts()'s prototype, which explicity takes a pointer to a string constant, accepts a string literal, not a pointer to one? That is, why does puts("hello world"); work when puts()'s prototype would indicate that puts() needs something more like char hello[] = "hello world"; puts(&hello);?
Except when it is the operand of the sizeof or unary & operator, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array.
String literals are stored as arrays of char (const char in C++); thus, the string literal "hello world" is an expression of type "12-element array of char". When you call puts( "hello world" );, the string literal is not the operand of the sizeof or unary & operators, so the type of the expression is converted to "pointer to char", and the value of the expression is the address of the first character in the string.
If you give, for instance, printf() a pointer to a string constant, which is apparently what it wants, GCC will complain and your program will segfault, because:
error: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[6]’
Remember above where I said an array expression is converted to a pointer type except when it is the operand of the sizeof or unary & operators or used to initialize another array in a declaration. Assume the declaration
char hello[] = "hello world";
Like above, the expression "hello world" has type 12-element array of char; however, because it is being used to initialize another array of char in a declaration, it is not converted to a pointer expression; instead, the contents of the string literal are copied to the hello array.
Similarly, if you call printf as follows:
printf( "%s", &hello );
then the expression hello is not converted to a pointer to char; instead, the type of the expression &hello is "pointer to 12-element array of char", or char (*)[12]. Since the %s conversion specifier expects a char *, you should just pass the array expression as
printf( "%s", hello );
and with string literals, just use the literal:
printf( "%s", "hello world" );
Going off that question's answers, pointers are just numbers which represent a position in memory. Numbers for memory addresses are unsigned ints, and C is written in (native) C and assembly, so pointers are simply architecture-defined uints.
But this is not the case, since the compiler is very clear in its errors about how int, int * and int ** are not the same. They are a pathway that eventually points to something in memory.
C is a (more or less) strongly-typed language; types matter. Even though an int, int *, and int ** may take up the same amount of space in memory1, semantically they are very different things and are (usually) not interchangable. A pointer to an int is a distinct type from a pointer to float, which is a distinct type from a pointer to an array of char, etc. This matters for things like pointer arithmetic; when you write
T *p = some_address();
p++;
The expression p++ advances p to point to the next object of type T. If sizeof (T) is 1, then p++ advances a single byte; if sizeof (T) is 4, then p++ advances 4 bytes (assuming a byte-addressed architecture, which most of us work on).
1. Or not. There is no guarantee that pointers to different types have the same size or representation as each other, nor is it guaranteed that they're just unsigned integers; on a segmented architecture, they may have a more complicated page:offset representation.
Several questions in there, but hopefully I can illustrate how pointers to pointers work.
The reason puts need a pointer, is that C really does not have a built in type for a string. A string is just a bunch of char one after another. Hence, puts needs a pointer to the first of the chars.
The string literal, "degrades gracefully" to a pointer. This is fancy compiler speak meaning that a string literal actually is a string of chars and is represented by a pointer to the first of the chars.
You need a pointer to a pointer to a type, for instance, if you want to "return" an array from a function, like so:
bool magic_super_function(int frob, int niz, char** imageptr /* pointer to pointer */)
{
char* img = malloc(frob * niz * IMAGE_DEPTH);
if (NULL == ptr) {
return false;
}
*imageptr = img;
return true;
}
Sometimes an example (even contrived) can illustrate a point. You would call
this function like so:
char* img; /* pointer to char */
if (true == magic_super_function(12, 8, &img /* pointer to pointer (to char)*/ )) {
/* Here img is valid and allocated */
/* Do something with img */
} else {
/* img has no valid value here. Do not use it. */
/* Something failed */
}
An int is different from int* because of how it will be used in the code. You can expect to access the memory location that int* points to and find an integer value. This is called 'strong typing' and the language does this so that there are strict rules for how you use your variables. So even though an int and int* might both be the same size, an int cannot be used as a pointer. Similarly an int** is a pointer to a pointer, so would have to be dereferenced twice to find the actual integer value it refers to.
In the example of puts(const char*) the definition of the function tells you that the function expects a memory location (pointer) to a null-terminated set of char values. When doing the operation, puts will dereference the location you give it, and print the characters found there. The const part tells you it won't be changing the values either so that it's safe to send a const array of char to it. When you send a literal string like puts("hello"), the compiler turns that into a pointer to "hello" for you as a convenience, so a pointer is still sent (not a copy of the string).
Regarding your question about printf, note that char* and char*[6] are different. The first indicates a pointer to a null-terminated string, where the second is a pointer to a set of exactly six char values which may not be null-terminated. The compiler complains because if puts(&hello) tried to treat the input parameter as a null-terminated string, it would not stop after then length of the array, and would access memory that it should not.
int **r = 90; r is a double pointer and you are assigning 90 to the pointer. When you dereference, it will try to dereference address 0x90.
Why does puts() need a pointer to a string constant?
puts() is defined in such a way so that it can make use of the actual parameter instead of copying it and reusing it. Because it improves performance. Moreover it takes a const pointer so it can't change the content pointed by the pointer. It is call by reference.
How is it that puts()'s prototype, which explicitly takes a pointer to
a string constant, accepts a string literal, not a pointer to one?
When you pass a string literal, first the string literal is stored in read only memory and then a pointer to that memory is actually passed. So you can call puts() with any literal like puts("abcd"), puts("xyz"). It will work.
error: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[6]’
Here your are actually passing a pointer to an array of 6 chars not a char *. So the compiler will complain this error.

How does an array act like a pointer in C?

I know this question has been answered several times but am not able to make sense of the following script. I am new to C by the way.
As I get it, if an array used as a value it represents the address of first character aka pointer.
if I run this:
int main (){
char quote[] = "C is great"
printf ("The quote: %s\n",quote);
printf ("The address of quote is %p\n",quote);
printf ("Size of quote is %lu\n",sizeof(quote));
}
I get:
The quote: C is great
The address of quote is 0x7fff06fa0d90
Size of quote is 11
So my question is in all printf cases, I have used used the same variable quote, but by changing print type how does it change from value to pointer and where is the pointer representation stored because sizeof gives me length of the string.
Thanks!
The pointer representation is not stored in a designated location. It has the same "storage" as the result of 2 + 2. (Usually, this will be a register). These are called values officially in C; sometimes called rvalues for discussion purposes.
The conversion happens for both of the cases where you give quote as argument to printf. The %s or the %p tells printf whether to output a representation of the pointer received, or whether to follow that pointer and print out the characters at the other end.
The rvalue is formed whenever it is needed. The sizeof operator does not perform lvalue-to-rvalue conversion on its operand, so sizeof(quote) does not generate or do any operation on a pointer.
Array type conversion to pointer type has some exceptions.
C11: 6.3.2.1 (p3):
Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type "array of type" is converted to an expression with type "pointer to type" that points to the initial element of the array object and is not an lvalue.
Note that the statement
printf ("The address of quote is %p\n",quote);
prints the address of first element of quote, not the address of quote although you will get the same address value on printing the address of quote.
Note that _Alingof is mentioned in draft is an error.
Internally, a pointer is an integer value that holds an address. So in all cases you are passing this pointer value to printf().
But the format specifier determines what printf() will do with that pointer. In one case, it reads the characters that are at the address contained in the pointer. In another case, it simply prints the pointer value.
All variables are pointers to memory locations in C. There is nothing else. The compiler keeps track of the variables by their pointers. It also keeps track of the variable type and size but these are not strict. Every variable is guaranteed to have a pointer, but type and consequently size can be changed.
The type and size is what determines what value is represented when a variable is used in your program but as far as your program is concerned, it actually has no idea what is stored at each pointer, except that the compiler has specifically written it into your compiled program.
You can use casting to override the type (even read memory out of bounds if you are not careful). If you have an array of 12 chars, you can read the values as an array of 3 ints if you want, for example.
In the case of static arrays (like your example), either when you define the size of the array or when you assign the value to the array, the compiler allocates the memory it needs.
It knows the length either because you told it explicitly in your definition (char quote[11]) or because it knows what has been stored in the array ("C is great" = 10). Since a char type variable is 1 byte, then 10 of them must be 10 bytes.
Your array is actually 11 bytes. This is because of how and what you assigned to it. In C, when the compiler finds a string literal, it automatically appends a NULL char on the end. If it didn't do this, functions like printf wouldn't know how long the string is. It wouldn't know because the size and type are not stored with the variable.
If you wrote your array as:
char quote[] = {'C',' ','i','s',' ','g','r','e','a','t'};
The compiler wouldn't know that it's a string and your array would be 10 bytes instead of 11. It might also behave strangely when you try to printf as a string in this case, since printf relies on the NULL byte to know when it reached the end of the string.
printf ("The quote: %s\n",quote);

Resources