What is the difference between char array vs char pointer in C?
I am trying to understand pointers in C but I am currently confused with the following:
char *p = "hello"
This is a char pointer pointing at the character array, starting at h.
char p[] = "hello"
This is an array that stores hello.
What is the difference when I pass both these variables into this function?
void printSomething(char *p)
{
printf("p: %s",p);
}
char*
and char[]
are different types, but it's not immediately apparent in all cases. This is because arrays decay into pointers, meaning that if an expression of type char[]
is provided where one of type char*
is expected, the compiler automatically converts the array into a pointer to its first element.
Your example function printSomething
expects a pointer, so if you try to pass an array to it like this:
char s[10] = "hello";
printSomething(s);
The compiler pretends that you wrote this:
char s[10] = "hello";
printSomething(&s[0]);
Let's see:
#include <stdio.h>
#include <string.h>
int main()
{
char *p = "hello";
char q[] = "hello"; // no need to count this
printf("%zun", sizeof(p)); // => size of pointer to char -- 4 on x86, 8 on x86-64
printf("%zun", sizeof(q)); // => size of char array in memory -- 6 on both
// size_t strlen(const char *s) and we don't get any warnings here:
printf("%zun", strlen(p)); // => 5
printf("%zun", strlen(q)); // => 5
return 0;
}
foo* and foo[] are different types and they are handled differently by the compiler (pointer = address + representation of the pointer's type, array = pointer + optional length of the array, if known, for example, if the array is statically allocated), the details can be found in the standard. And at the level of runtime no difference between them (in assembler, well, almost, see below).
Also, there is a related question in the C FAQ:
Q : What is the difference between these initializations?
char a[] = "string literal";
char *p = "string literal";
My program crashes if I try to assign a new value to p[i].
A : A string literal (the formal term for a double-quoted string in C source) can be used in two slightly different ways:
Some compilers have a switch controlling whether string literals are writable or not (for compiling old code), and some may have options to cause string literals to be formally treated as arrays of const char (for better error catching).
See also questions 1.31, 6.1, 6.2, 6.8, and 11.8b.
References: K&R2 Sec. 5.5 p. 104
ISO Sec. 6.1.4, Sec. 6.5.7
Rationale Sec. 3.1.4
H&S Sec. 2.7.4 pp. 31-2
C99 N1256 draft
There are two completely different uses of array literals:
Initialize char[]
:
char c[] = "abc";
This is "more magic", and described at 6.7.8/14 "Initialization" :
An array of character type may be initialized by a character string literal, optionally enclosed in braces. Successive characters of the character string literal (including the terminating null character if there is room or if the array is of unknown size) initialize the elements of the array.
So this is just a shortcut for:
char c[] = {'a', 'b', 'c', ' '};
Like any other regular array, c
can be modified.
Everywhere else: it generates an:
So when you write:
char *c = "abc";
This is similar to:
/* __unnamed is magic because modifying it gives UB. */
static char __unnamed[] = "abc";
char *c = __unnamed;
Note the implicit cast from char[]
to char *
, which is always legal.
Then if you modify c[0]
, you also modify __unnamed
, which is UB.
This is documented at 6.4.5 "String literals" :
5 In translation phase 7, a byte or code of value zero is appended to each multibyte character sequence that results from a string literal or literals. The multibyte character sequence is then used to initialize an array of static storage duration and length just sufficient to contain the sequence. For character string literals, the array elements have type char, and are initialized with the individual bytes of the multibyte character sequence [...]
6 It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined.
6.7.8/32 "Initialization" gives a direct example:
EXAMPLE 8: The declaration
char s[] = "abc", t[3] = "abc";
defines "plain" char array objects s
and t
whose elements are initialized with character string literals.
This declaration is identical to
char s[] = { 'a', 'b', 'c', ' ' },
t[] = { 'a', 'b', 'c' };
The contents of the arrays are modifiable. On the other hand, the declaration
char *p = "abc";
defines p
with type "pointer to char" and initializes it to point to an object with type "array of char" with length 4 whose elements are initialized with a character string literal. If an attempt is made to use p
to modify the contents of the array, the behavior is undefined.
GCC 4.8 x86-64 ELF implementation
Program:
#include <stdio.h>
int main() {
char *s = "abc";
printf("%sn", s);
return 0;
}
Compile and decompile:
gcc -ggdb -std=c99 -c main.c
objdump -Sr main.o
Output contains:
char *s = "abc";
8: 48 c7 45 f8 00 00 00 movq $0x0,-0x8(%rbp)
f: 00
c: R_X86_64_32S .rodata
Conclusion: GCC stores char*
it in .rodata
section, not in .text
.
If we do the same for char[]
:
char s[] = "abc";
we obtain:
17: c7 45 f0 61 62 63 00 movl $0x636261,-0x10(%rbp)
so it gets stored in the stack (relative to %rbp
).
Note however that the default linker script puts .rodata
and .text
in the same segment, which has execute but no write permission. This can be observed with:
readelf -l a.out
which contains:
Section to Segment mapping:
Segment Sections...
02 .text .rodata
链接地址: http://www.djcxy.com/p/79204.html
上一篇: 了解std :: hardware
下一篇: 字符数组与char指针在C中有什么区别?