1.L-value and r-value
The symbol appearing on the left of an assignment is sometimes called an l-value (for "left-hand-side" or "locator" value), while a symbol on the right of an assignment is sometimes called an r-value (for "right-hand-side"). The compiler allocates an address (or l-value) to each variable. This address is known at compiletime, and is where the variable will be kept at runtime. In contrast, the value stored in a variable at runtime (its r-value) is not known until runtime. If the value stored in a variable is required, the compiler emits code to read the value from the given address and put it in a register.
The key point here is that the address of each symbol is known at compiletime. So if the compiler need s to do something with an address (add an offset to it, perhaps), it can do that directly and does not need to plant code to retrieve the address first. In contrast, the current value of a pointer must be retrieved at runtime be before it can be dereference(made part of a further look-up).Diagram A shows an array reference.
2. char *p
If you declare char *p, it tells the compiler that p is a pointer(a four-byte object on many contemporary machines), and the object pointed to is a character. To get the char, you have to get whatever is at address p, then use that as an address and get whatever is there. Pointer accesses are more flexible,but
at the cost of an extra fetch instruction, as show in Diagram B.
3. difference between char a[] and char *p
char *p = "abcdefg"; p[3]
char a[] = "abcdefg"; a[3]
they both get the 'd' character,but the way is rather difference.
The compiler has been told that p is a pointer to char.In contrast, an array definition tells the compiler that p is a sequence of chars.