C语言 char ** 和解引用指针

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4993076/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 07:47:47  来源:igfitidea点击:

char ** and dereferencing pointers

cpointers

提问by system

I would like to end my confusion with the char **

我想结束我对 char **

When once creates an array of character arrays(strings) how does char **actually accomplish this?

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

i get that char *is a pointer to a char and that char *array[]is an array of char pointers, but what exactly does char **do and how does it do it?

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

Also when I hear the word dereferences it makes me think the pointer is removed what exactly does dereference a pointer mean? Changing the value that the pointer points to?

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

Thanks

谢谢

回答by John Bode

"Dereferencing" a pointer means accessing the value the pointer points to. Assume the following declarations:

“取消引用”指针意味着访问指针指向的值。假设有以下声明:

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

acontains the integer value 10. pcontains the address of a(0x80001000). If we want to access the contents of athrough p, we dereferencepwith the indirection operator *. Thus, the expression *pis equivalent to the expression a. If we wrote

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

 *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:

下面是一段简短的代码片段,展示了如何使用类型对象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], "          "); 
  }
}

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, arrpoints to the first pointer to char, hence the type char **. Note that if you separated the declaration and the function call, it would look like

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

char **arr;
...
arr = malloc(sizeof *arr * N);

We want to assign the result of mallocto arr, not to what arrpoints to.

我们想要的结果分配mallocarr,没有什么arr

if (arr)

It's possible for mallocto fail, so we want to check the result before using it. In the event mallocfails it will return a NULL pointer value.

有可能malloc失败,所以我们想在使用它之前检查结果。如果malloc失败,它将返回一个 NULL 指针值。

{
  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 charvalue (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].

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

Since we allocate each string with a separate malloccall, it's unlikely that they are contiguous in memory. Here's another memory map showing a possibleresult of the code above:

由于我们使用单独的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??
             ...

回答by vmpstr

A pointer is a type that holds an address to a value, instead of holding the actual value.

指针是一种保存指向值的地址的类型,而不是保存实际值。

So, in the case of char *p, once allocated, p will contain an address A. Dereferencing that pointer means accessing the value that is stored at address A. The reason you can store strings in a char * is because memory that is allocated is contiguous. So, A is an address that stores the first character, A+1 is an address that stores the second character and so on.

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

In the case of char **pp, it stores an address of a char *. Call this address B. So, dereferencing pp means accessing value at address B, which happens to be a char *, which happens to hold a string. In the same way, B+1 (actually B + sizeof (char *)) stores the next value, which is another string.

在 char **pp 的情况下,它存储一个 char * 的地址。称这个地址为 B。所以,解引用 pp 意味着访问地址 B 处的值,它恰好是一个 char *,恰好保存了一个字符串。同理,B+1(实际上是B+sizeof(char *))存储下一个值,也就是另一个字符串。

Dereferencing pp twice (ie **pp) means you are first accessing value at address B, which for instance is A, and then dereferencing that once more to get the value at address A, which is some character.

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

回答by T33C

Diagrams are worth a 1000 words. Have a look here

图表价值 1000 字。看看这里

char, char* and char** are simply types describing what a variable (area of memory) contains.

char、char* 和 char** 只是描述变量(内存区域)包含的内容的类型。

Using dereferencing like *variable actually says to treat the value in the variable as a memory address and actually return the value at that address. This is indirection.

使用像 *variable 这样的解引用实际上表示将变量中的值视为内存地址并实际返回该地址处的值。这是间接的。

**variable is simply two levels of indirection. i.e. the value in the variable is a memory address of yet another memory address of the data that will be returned.

**变量只是两个间接级别。即变量中的值是将返回的数据的另一个内存地址的内存地址。

Addresses typically come from the address of operator, &or from a memory allocation function/operator like new

地址通常来自运算符的地址,&或来自内存分配函数/运算符,如new

回答by phihag

Dereferencing a pointer means accessing the value the pointer pointsto. 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:

直接使用指向 c 而不是 c 的指针的原因是指针允许您访问 1 个以上的值。拿这个例子:

char[4] str;
char c0 = 'a', c1 = 'b', c3 = 'c', c4 = '
str[1] /* or */ *(str+1)
'; 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 write

现在假设我们需要第二个字符。我们可以使用c1. 但是正如你所看到的,这个符号真的很麻烦。另外,如果我们从文件中读取字符串而不是写入它,我们将不得不做一些复杂的事情。相反,我们只写

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 != '##代码##') { // Loop while the copy does not point to a char '##代码##'
            res += 1; // We found a character
            p++; // Check next character in the next iteration
        }
        input++; // Check next string in the next iteration
    }
    return res;
}

Note that the first element has the index0, 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:

请注意,第一个元素的索引为0,第二个元素为1 - 这就是我们在这里使用 1 的原因。Achar**将其变为 11 - 我们有一个由字符数组组成的数组。假设我们有这样一个数组,我们称之为input,并且需要找出其中所有字符串的长度。这就是我们要做的:

##代码##