int a = 10;
int *p = &a;
Here's a hypothetical memory map of the two variables:Item Address 0x00 0x01 0x02 0x03
---- ------- ---- ---- ---- ----
a 0x80001000 0x00 0x00 0x00 0x0A
p 0x80001004 0x80 0x00 0x10 0x00
a
contains the integer value 10. p
contains the address of a
(0x80001000). If we want to access the contents of a
through p
, we dereference p
with the indirection operator *
. Thus, the expression *p
is equivalent to the expression a
. If we wrote *p = 16;
that's the same as writing a = 16;
Here's a short snippet of code showing how to use an object of type char **
to create an array of strings:#include
#define N 20 // For this example, we will allocate 20 strings
#define LENGTH 10 // of 10 characters each (not counting 0 terminator)
...
char **arr = malloc(sizeof *arr * N);
if (arr)
{
size_t i;
for (i = 0; i < N; i++)
{
arr[i] = malloc(sizeof *arr[i] * (LENGTH + 1));
strcpy(arr[i], " ");
}
}
Going through it line by line,char **arr = malloc(sizeof *arr * N);
allocates a block of N elements, each large enough to store a pointer to char (sizeof *arr
== sizeof (char *)
since type of *arr
== char *
), and assigns the resulting pointer value to arr
. IOW, arr
points to the first pointer to char
, hence the type char **
. Note that if you separated the declaration and the function call, it would look likechar **arr;
...
arr = malloc(sizeof *arr * N);
We want to assign the result of malloc
to arr
, not to what arr
points to. if (arr)
It's possible for malloc
to fail, so we want to check the result before using it. In the event malloc
fails it will return a NULL pointer value. {
size_t i;
for (i = 0; i < N; i++)
{
arr[i] = malloc(sizeof *arr[i] * (LENGTH + 1));
For each character pointer arr[i]
, we allocate a block of memory large enough for LENGTH+1 elements, each large enough to hold a char
value (sizeof *arr[i] == sizeof (char)
, since type of *arr[i] == char
; note that sizeof (char)
is always 1) and assign the result to arr[i]
. Since we allocate each string with a separate
malloc
call, it's unlikely that they are contiguous in memory. Here's another memory map showing a possible result of the code above:Item Address 0x00 0x01 0x02 0x03
---- ------- ---- ---- ---- ----
arr 0x80001000 0xA0 0xCC 0x00 0x00
...
arr[0] 0xA0CC0000 0xA0 0xCC 0x20 0x00
arr[1] 0xA0CC0004 0xA0 0xCC 0x20 0x40
arr[2] 0xA0CC0008 0xA0 0xCC 0x21 0x28
...
arr[19] 0xA0CC0014 0xA0 0xCC 0x23 0x10
...
arr[0][0] 0xA0CC2000 ' ' ' ' ' ' ' '
arr[0][4] 0xA0CC2004 ' ' ' ' ' ' ' '
arr[0][8] 0xA0CC2008 ' ' ' ' 0x00 0x??
...
arr[1][0] 0xA0CC2040 ' ' ' ' ' ' ' '
arr[1][4] 0xA0CC2044 ' ' ' ' ' ' ' '
arr[1][8] 0xA0CC2048 ' ' ' ' 0x00 0x??
-------------------------------------------------
Dereferencing a pointer means accessing the value the pointer points to. For example,
char c = 'c'; // This is a primitive value. You cannot dereference it.
char* p1 = &c; // A pointer to the address of c
char** p2 = &p1; // A pointer to the address of p1
/* Now, the following is true:
*p1 == c, i.e. dereferencing p1 allows us to read from/write to c.
*p2 == p1
**p2 == *(*p2) == *p1 = c - dereferencing p2 twice is c, too */
The reason why you use a pointer to c instead of c directly is that a
pointer allows you to access more than 1 value. Take this example:char[4] str;
char c0 = 'a', c1 = 'b', c3 = 'c', c4 = '\0';
str[0] = c0; str[1] = c1; str[2] = c2; str[3] = c3;
str = "abc"; // Same as the above line
Now suppose we need the second character. We could access it with c1
.
But as you can see, this notation is really cumbersome. Plus, if we
read the string from a file instead of writing it, we'd have to do
complicated things. Instead, we just writestr[1] /* or */ *(str+1)
Note that the first element has the index 0, the second 1 - that's why we're using 1 here. A char**
turns this up to eleven - we have an array of an array of chars. Suppose we have such an array, let's call it input
, and need to find out the length of all the strings in it. This is how we would do it:int lensum(char **input) {
int res = 0;
while (*input) { // This loops as long as the value input points to is not 0.
char* p = *input; // Make a copy of the value input currently points to
while (*p != '\0') { // Loop while the copy does not point to a char '\0'
res += 1; // We found a character
p++; // Check next character in the next iteration
}
input++; // Check next string in the next iteration
}
return res;
} ...
沒有留言:
張貼留言