char**和解除引用指针

jar*_*ryd 11 c pointers

我想结束与此混淆 char **

当一次创建一个字符数组(字符串)数组时,char **实际上如何实现这一目标?

我得到的char *是一个指向char *array[]char的指针,这是一个char指针数组,但究竟是做char **什么的,它是如何做到的?

此外,当我听到dereferences这个词时,它会让我认为指针被删除了指针取消引用究竟是什么意思?更改指针指向的值?

谢谢

Joh*_*ode 13

"解除引用"指针意味着访问指针指向的值.假设以下声明:

int a = 10;
int *p = &a;
Run Code Online (Sandbox Code Playgroud)

这是两个变量的假设记忆图:

Item      Address      0x00  0x01  0x02  0x03
----      -------      ----  ----  ----  ----
   a      0x80001000   0x00  0x00  0x00  0x0A
   p      0x80001004   0x80  0x00  0x10  0x00

a包含整数值10. p包含地址a(0x80001000).如果我们想访问athrough 的内容p,我们使用间接运算符取消引用 .因此,表达式等同于表达式.如果我们写的p**pa

 *p = 16;
Run Code Online (Sandbox Code Playgroud)

这和写作一样

  a = 16;
Run Code Online (Sandbox Code Playgroud)

这是一段简短的代码片段,展示了如何使用类型的对象char **来创建字符串数组:

#include <stdlib.h>
#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], "          "); 
  }
}
Run Code Online (Sandbox Code Playgroud)

逐行完成,

char **arr = malloc(sizeof *arr * N); 
Run Code Online (Sandbox Code Playgroud)

分配N个元素,每个大到足以存储一个字符指针(块sizeof *arr== sizeof (char *)因为类型*arr== char *),并分配所得到的指针值到arr.IOW,arr指向第一个指针char,因此指向类型char **.请注意,如果将声明和函数调用分开,它看起来就像

char **arr;
...
arr = malloc(sizeof *arr * N);
Run Code Online (Sandbox Code Playgroud)

我们要分配的结果mallocarr,没有什么arr 指向.

if (arr)
Run Code Online (Sandbox Code Playgroud)

malloc失败是可能的,因此我们希望在使用之前检查结果.如果malloc失败,它将返回NULL指针值.

{
  size_t i;
  for (i = 0; i < N; i++)
  {
    arr[i] = malloc(sizeof *arr[i] * (LENGTH + 1));
Run Code Online (Sandbox Code Playgroud)

对于每个字符指针arr[i],我们为LENGTH + 1个元素分配一个足够大的内存块,每个元素足够大以容纳一个char值(sizeof *arr[i] == sizeof (char)因为类型为*arr[i] == char;注意sizeof (char)总是为1)并将结果赋值给arr[i].

由于我们使用单独的malloc调用分配每个字符串,因此它们在内存中不太可能是连续的.这是另一个显示上述代码可能结果的内存映射:

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??
             ...

  • 对不起,我是新手,所以我可能错了,但是要在分配后彻底清理,你必须循环遍历字符串总数和free arr [i]以及释放整个数组(arr),是对的吗?或者只是'自由(arr);`这就足够了吗? (2认同)

vmp*_*str 8

指针是一种将地址保存到值的类型,而不是保存实际值.

因此,在char*p的情况下,一旦分配,p将包含地址A.解除引用该指针意味着访问存储在地址A的值.您可以在char*中存储字符串的原因是因为分配的内存是连续的.因此,A是存储第一个字符的地址,A + 1是存储第二个字符的地址,依此类推.

在char**pp的情况下,它存储char*的地址.调用此地址B.因此,解除引用pp意味着访问地址B处的值,该值恰好是char*,恰好包含字符串.以同样的方式,B + 1(实际上是B + sizeof(char*))存储下一个值,这是另一个字符串.

取消引用pp两次(即**pp)意味着您首先访问地址B处的值,例如A,然后再次解除引用以获取地址A处的值,这是某个字符.