为什么需要使用type **指向type *?

我已经读了几天《学习C的艰难方法》,但这是我要真正理解的东西。作者Zed写道这char **是为了“指向(指向char的指针)的指针”,并说这是必需的,因为我正试图指向二维的东西。


这是网页上的确切内容


一个char *已经是“指向char的指针”,因此这只是一个字符串。但是,您需要2个级别,因为名称是二维的,这意味着您需要char **作为“指向(指向char的指针)”类型的指针。


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


只需稍作跟踪,这是否也适用于n维?


这是相关的代码


char *names[] = { "Alan", "Frank", "Mary", "John", "Lisa" };

char **cur_name = names;


侃侃尔雅
浏览 313回答 3
3回答

慕村9548890

不,该教程的质量值得怀疑。我不建议继续阅读它。A char**是指针到指针。它不是二维数组。它不是指向数组的指针。它不是指向2D数组的指针。本教程的作者可能会感到困惑,因为存在广泛的错误和错误做法,说您应该分配动态2D数组,如下所示:// BAD! Do not do like this!int** heap_fiasco;heap_fiasco = malloc(X * sizeof(int*));for(int x=0; x<X; x++){&nbsp; heap_fiasco[x] = malloc(Y * sizeof(int));}但是,这不是2D数组,它是一个缓慢的,碎片化的查找表,分配给整个堆。访问查找表中一项的语法heap_fiasco[x][y]类似于数组索引语法,因此许多人出于某种原因认为这是分配2D数组的方式。动态分配2D数组的正确方法是:// correctint (*array2d)[Y] = malloc(sizeof(int[X][Y]));您可以说第一个不是数组,因为如果这样做memcpy(heap_fiasco, heap_fiasco2, sizeof(int[X][Y])),代码将崩溃并燃烧。这些项目未分配在相邻的存储器中。同样memcpy(heap_fiasco, heap_fiasco2, sizeof(*heap_fiasco))也会崩溃和烧毁,但是由于其他原因:您得到的是指针的大小而不是数组的大小。虽然memcpy(array2d, array2d_2, sizeof(*array2d))会起作用,因为它是2D数组。

心有法竹

指针花了我一段时间来理解。我强烈建议绘制图表。请阅读并理解C ++教程的这一部分(至少在指针方面,图表确实对我有所帮助)。告诉您对于二维数组,您需要一个指向char的指针是一个谎言。您不需要它,但这是实现它的一种方法。内存是顺序的。如果您想像单词hello那样连续放置5个字符(字母),则可以定义5个变量,并始终记住使用它们的顺序,但是如果要保存6个字母的单词会怎样呢?您是否定义更多变量?如果只按顺序将它们存储在内存中会不会更容易?因此,您要做的就是向操作系统请求5个字符(每个字符恰好是一个字节),然后系统将向您返回一个内存地址,该地址开始您的5个字符的序列。您使用此地址并将其存储在变量中,我们将其称为指针,因为它指向您的内存。指针的问题在于它们只是地址。您怎么知道该地址存储了什么?是5个字符还是8个字节的大二进制数字?还是它是您加载的文件的一部分?你怎么知道的?这是像C这样的编程语言试图通过提供类型来帮助您的地方。类型告诉您变量存储的内容,而指针也具有类型,但是其类型告诉您指针指向的内容。因此,char *是指向存储位置的指针,该存储位置包含单个char或一系列chars。可悲char的是,您需要记住自己有关多少个数字的部分。通常,您将这些信息存储在一个变量中,以提醒您有多少个字符。那么,当您想要拥有二维数据结构时,该如何表示呢?最好用一个例子来解释。让我们做一个矩阵:1&nbsp; 2&nbsp; 3&nbsp; 45&nbsp; 6&nbsp; 7&nbsp; 89 10 11 12它具有4列和3行。我们如何存储它?好吧,我们可以制作3个序列,每个序列有4个数字。第一个序列为1&nbsp; 2&nbsp; 3&nbsp; 4,第二个序列为,5&nbsp; 6&nbsp; 7&nbsp; 8第三个和最后一个序列为9 10 11 12。因此,如果我们要存储4个数字,我们将要求系统为我们保留4个数字并为它们提供一个指针。这些将是指向数字的指针。但是,由于我们需要3个指针,因此我们将要求系统给3个指针指向指针编号。这就是您最终得到建议的解决方案的方式...另一种方法是认识到您需要4乘3的数字,然后要求系统按顺序存储12个数字。但是,您如何访问第2行和第3列中的数字?这是数学的用武之地,但让我们在示例中进行尝试:1&nbsp; 2&nbsp; 3&nbsp; 45&nbsp; 6&nbsp; 7&nbsp; 89 10 11 12如果我们将它们彼此相邻存储,它们将如下所示:offset from start:&nbsp; 0&nbsp; 1&nbsp; 2&nbsp; 3&nbsp; &nbsp; 4&nbsp; 5&nbsp; 6&nbsp; 7&nbsp; &nbsp; 8&nbsp; &nbsp;9&nbsp; 10&nbsp; 11&nbsp; &nbsp;numbers in memory: [1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]所以我们的映射是这样的:row | column | offset | value&nbsp;1&nbsp; |&nbsp; &nbsp;1&nbsp; &nbsp; |&nbsp; &nbsp;0&nbsp; &nbsp; |&nbsp; &nbsp;1&nbsp;1&nbsp; |&nbsp; &nbsp;2&nbsp; &nbsp; |&nbsp; &nbsp;1&nbsp; &nbsp; |&nbsp; &nbsp;2&nbsp;1&nbsp; |&nbsp; &nbsp;3&nbsp; &nbsp; |&nbsp; &nbsp;2&nbsp; &nbsp; |&nbsp; &nbsp;3&nbsp;1&nbsp; |&nbsp; &nbsp;4&nbsp; &nbsp; |&nbsp; &nbsp;3&nbsp; &nbsp; |&nbsp; &nbsp;4&nbsp;2&nbsp; |&nbsp; &nbsp;1&nbsp; &nbsp; |&nbsp; &nbsp;4&nbsp; &nbsp; |&nbsp; &nbsp;5&nbsp;2&nbsp; |&nbsp; &nbsp;2&nbsp; &nbsp; |&nbsp; &nbsp;5&nbsp; &nbsp; |&nbsp; &nbsp;6&nbsp;2&nbsp; |&nbsp; &nbsp;3&nbsp; &nbsp; |&nbsp; &nbsp;6&nbsp; &nbsp; |&nbsp; &nbsp;7&nbsp;2&nbsp; |&nbsp; &nbsp;4&nbsp; &nbsp; |&nbsp; &nbsp;7&nbsp; &nbsp; |&nbsp; &nbsp;8&nbsp;3&nbsp; |&nbsp; &nbsp;1&nbsp; &nbsp; |&nbsp; &nbsp;8&nbsp; &nbsp; |&nbsp; &nbsp;9&nbsp;3&nbsp; |&nbsp; &nbsp;2&nbsp; &nbsp; |&nbsp; &nbsp;9&nbsp; &nbsp; |&nbsp; 10&nbsp;3&nbsp; |&nbsp; &nbsp;3&nbsp; &nbsp; |&nbsp; 10&nbsp; &nbsp; |&nbsp; 11&nbsp;3&nbsp; |&nbsp; &nbsp;4&nbsp; &nbsp; |&nbsp; 11&nbsp; &nbsp; |&nbsp; 12现在,我们需要制定一个简单易行的公式,将行和列转换为偏移量……如果我有更多时间,我会回到它的位置上……现在我需要回家(抱歉)。 ..编辑:我有点晚了,但让我继续。要查找行和列中每个数字的偏移量,可以使用以下公式:offset = (row - 1) * 4 + (column - 1)如果您注意到-1这里的两个数字,您会发现这是因为我们的行号和列号以1开头,所以我们必须这样做,这就是计算机科学家偏爱基于零的偏移量的原因(由于该公式) )。但是,对于C语言中的指针,当您使用多维数组时,语言本身会为您应用此公式。因此,这是另一种方式。

烙印99

从您的问题中,我了解的是您在问为什么要为声明为* names []的变量使用char **。因此,答案是当您只写names []时,它就是array的语法,而array本质上是一个指针。因此,当您编写* names []时,这意味着您要指向一个数组。而且因为数组基本上是一个指针,所以这意味着您有一个指向指针的指针,这就是为什么如果您编写的话编译器不会抱怨的原因char ** cur_name =名称;在上面的代码行中,您声明了一个指向字符指针的指针,然后使用指向数组的指针初始化它(记住数组也是指针)。
打开App,查看更多内容
随时随地看视频慕课网APP