为什么我需要使用类型**指向类型*?

Nog*_*enn 7 c pointers

几天来,我一直在阅读"学习艰难的道路",但这是我想要真正理解的东西.作者Zed写道,这char **是一个"指向(指向char的指针)",并说这是必需的,因为我试图指向二维的东西.

这是在网页上写的内容

char*已经是"指向char的指针",所以这只是一个字符串.但是你需要2个级别,因为名称是2维的,这意味着你需要char**作为"指向(指向char的指针)"类型的指针.

这是否意味着我必须使用一个可以指向二维的变量,这就是为什么我需要两个**

只是一点点跟进,这也适用于n维吗?

这是相关的代码

char *names[] = { "Alan", "Frank", "Mary", "John", "Lisa" };
char **cur_name = names;
Run Code Online (Sandbox Code Playgroud)

Lun*_*din 24

不,那个教程质量有问题.我不建议继续阅读它.

A char**是指向指针的指针.它不是2D阵列.它不是指向数组的指针.它不是指向2D数组的指针.

本教程的作者可能会感到困惑,因为有一个广泛的错误和不正确的做法,说你应该像这样分配动态2D数组:

// BAD! Do not do like this!
int** heap_fiasco;
heap_fiasco = malloc(X * sizeof(int*));
for(int x=0; x<X; x++)
{
  heap_fiasco[x] = malloc(Y * sizeof(int));
}
Run Code Online (Sandbox Code Playgroud)

然而,这不是2D数组,它是在整个堆中分配的缓慢,碎片化的查找表.访问查找表中的一个项目的语法heap_fiasco[x][y]看起来就像数组索引语法一样,因此很多人出于某种原因相信这是你分配二维数组的方式.

动态分配2D数组的正确方法是:

// correct
int (*array2d)[Y] = malloc(sizeof(int[X][Y]));
Run Code Online (Sandbox Code Playgroud)

您可以告诉第一个不是数组,因为如果您这样做memcpy(heap_fiasco, heap_fiasco2, sizeof(int[X][Y])),代码将崩溃并刻录.项目未在相邻内存中分配.

同样memcpy(heap_fiasco, heap_fiasco2, sizeof(*heap_fiasco))也会崩溃和刻录,但由于其他原因:你得到的指针大小不是数组.

虽然memcpy(array2d, array2d_2, sizeof(*array2d))会起作用,因为它是一个2D阵列.


non*_*kle 6

指针花了一些时间来理解.我强烈建议绘制图表.

请阅读并理解C++教程的这一部分(至少关于图表确实帮助我的指针).

告诉你你需要一个指向二维数组char的指针的谎言.你不需要它,但它是一种方法.

记忆是连续的.如果你想在单词hello中添加 5个字符(字母),你可以定义5个变量并始终记住使用它们的顺序,但是当你想用6个字母保存单词时会发生什么?你定义了更多变量吗?如果你只是按顺序将它们存储在内存中会不会更容易?

所以你要做的就是向操作系统询问5个字符(并且每个字符恰好是一个字节),然后系统返回一个存储器地址,其中5个字符序列开始.你把这个地址存储在一个我们称之为指针的变量中,因为它指向你的记忆.

指针的问题在于它们只是地址.你怎么知道那个地址存储的是什么?它是5个字符还是8字节的大二进制数?或者它是您加载的文件的一部分?你怎么知道的?

这就是像C这样的编程语言试图通过为您提供类型来帮助的地方.类型告诉你变量存储的内容和指针也有类型,但它们的类型告诉你指针指向的是什么.因此,char *是一个指向内存位置的指针,该内存位置包含单个char或一个序列chars.可悲的是,关于你有多少人char的部分,你需要记住自己.通常,您将该信息存储在您保留的变量中,以提醒您有多少个字符.

所以当你想要一个二维数据结构时,你如何表示?

最好用一个例子来解释.我们做一个矩阵:

1  2  3  4
5  6  7  8
9 10 11 12
Run Code Online (Sandbox Code Playgroud)

它有4列3行.我们如何存储?

好吧,我们可以制作3个序列,每个序列有4个数字.第一个序列是1 2 3 4,第二5 6 7 8个序列是第三个和最后一个序列9 10 11 12.因此,如果我们想要存储4个数字,我们将要求系统为我们保留4个数字并给我们指向它们的指针.这些将成为数字的指针.但是,由于我们需要其中的3个,我们将要求系统给出指针数字的 3个指针.

这就是你最终得到的建议解决方案......

另一种方法是认识到你需要4次3个数字,并且只需要系统将12个数字存储在一个序列中.但那么如何访问第2行和第3列中的数字呢?这是数学的来源,但让我们在我们的例子中尝试:

1  2  3  4
5  6  7  8
9 10 11 12
Run Code Online (Sandbox Code Playgroud)

如果我们将它们彼此相邻存储,它们将如下所示:

offset from start:  0  1  2  3    4  5  6  7    8   9  10  11   
numbers in memory: [1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]
Run Code Online (Sandbox Code Playgroud)

所以我们的映射是这样的:

row | column | offset | value
 1  |   1    |   0    |   1
 1  |   2    |   1    |   2
 1  |   3    |   2    |   3
 1  |   4    |   3    |   4
 2  |   1    |   4    |   5
 2  |   2    |   5    |   6
 2  |   3    |   6    |   7
 2  |   4    |   7    |   8
 3  |   1    |   8    |   9
 3  |   2    |   9    |  10
 3  |   3    |  10    |  11
 3  |   4    |  11    |  12
Run Code Online (Sandbox Code Playgroud)

我们现在需要制定一个简单的公式,将行和列转换为偏移...当我有更多时间时,我会回到它...现在我需要回家(对不起). ..

编辑:我有点晚了,但让我继续.要查找行和列中每个数字的偏移量,可以使用以下公式:

offset = (row - 1) * 4 + (column - 1)
Run Code Online (Sandbox Code Playgroud)

如果你注意到这两个-1并想一想,你会明白这是因为我们的行和列编号从1开始,我们必须这样做,这就是为什么计算机科学家更喜欢基于零的偏移(因为这个公式) ).但是,使用C语言中的指针,当您使用多维数组时,语言本身会为您应用此公式.因此,这是另一种方式.