关于 C 中的指针

Posted

技术标签:

【中文标题】关于 C 中的指针【英文标题】:About pointers in C 【发布时间】:2013-03-20 21:55:08 【问题描述】:

我开始阅读一些关于 C 中指针的文章,但我有一个我不理解的例子。

示例来自这里:http://en.wikibooks.org/wiki/C_Programming/Pointers_and_arrays

这里是:

让我们看一个稍微不同的问题。我们想要一个二维数组,但我们不需要所有的行都具有相同的长度。我们要做的是声明一个指针数组。下面的第二行将 A 声明为一个指针数组。每个指针都指向一个浮点数。以下是一些适用的代码:

float  linearA[30];
 float *A[6];

 A[0] = linearA;              /*  5 - 0 = 5 elements in row  */
 A[1] = linearA + 5;          /* 11 - 5 = 6 elements in row  */
 A[2] = linearA + 11;         /* 15 - 11 = 4 elements in row */
 A[3] = linearA + 15;         /* 21 - 15 = 6 elements        */
 A[4] = linearA + 21;         /* 25 - 21 = 4 elements        */
 A[5] = linearA + 25;         /* 30 - 25 = 5 elements        */

 A[3][2] = 3.66;          /* assigns 3.66 to linearA[17];     */
 A[3][-3] = 1.44;         /* refers to linearA[12];           
                             negative indices are sometimes useful.
                             But avoid using them as much as possible. */

我的问题是为什么A[0] 是一个仅指向五个元素而不是所有linearA 的指针,因为数组的名称是指向其第一个成员的指针。

A[1] = linearA + 5; 是连续 6 个元素——出于同样的原因? A[1]不应该是指向linearA的第6个成员的指针吗?

谁能解释我的错误在哪里?

【问题讨论】:

A[0] 用作指向由五个floats 组成的数组的第一个元素的指针是预期用途。您还可以将它用作指向 30 个floats 数组的第一个元素的指针,因为这是linearA 提供的。这一切都只是解释。 指针没有关于它们所指向的元素数量的信息。指向大小为 42 的数组的第一个元素的指针与它们所指向的 元素数 完全相同,就像指向大小为 12000 的数组的第一个元素的指针一样。您的示例,A[0] 是指向 30 个元素的数组的第一个元素的指针......但它不关心 元素的数量程序员在进行其他分配之前将其解释为 5 个元素 @pmg:指针的 type 确实表明了它所指向的大小(和其他信息)。该信息通常不会在运行时存储。 推荐阅读:comp.lang.c FAQ第6节 @DanielFischer 啊。我也被这个例子弄糊涂了。现在很有意义,他们只是将一维数组划分为多个部分。指向每个部分开头的指针是 A 的元素。我更喜欢为 A 的每个指针分配单独的数组,但我认为这提供了连续内存的额外好处。 【参考方案1】:

除了少数例外,在 C 中,数组名被转换为指向数组第一个元素的指针。 linearAfloat 的数组 30,在表达式中:

A[0] = linearA;

它被转换为指向float的指针。

A 是指向float 的指针数组6。 A 的元素是指向float 的类型指针。所以A[0] 是指向float 的指针,而不是指向数组的指针。

C 中的A[i][j] 等价于*(A[i] + j),所以A[i][j]float(取消引用指向float 的指针会产生float)。

【讨论】:

我同意你所说的一切,但我不明白他们的 cmets:A[0] = linearA; /* 5 - 0 = 行 中的 5 个元素/ A[1] = linearA + 5; / 11 - 5 = 6 个元素在行 */ @Farseer 因为(linearA + 5) - linearA == 5(linearA + 11) - (linearA + 5) == 6【参考方案2】:

A[0] 是指向linearA 的第一个元素的指针。由于linearA 是一个连续数组,因此该指针实际上允许通过添加适当的偏移量来访问linearA 30 个元素中的任何一个。但是,在这段代码中,您通过指向linearA 数组中的不同偏移量来模拟二维数组。结果是二维数组寻址:A[n] 将您带到第 n 行的位置(即linearA 中的偏移量),A[n][m] 将您带到该行内的第 m 个元素。

【讨论】:

不,A[0]float* 类型,它指向一个 float 对象,恰好是 linearA 的第 0 个元素。 @KeithThompson 这就是我的意思,我会重新表述清楚。【参考方案3】:

我的问题是为什么 A[0] 是仅指向五个元素而不是指向 ALL 的 linearA,因为数组的名称是指向它的第一个的指针 会员。

您将A[0] 设置为指向linearA,这是数组中的第一个浮点数,A[0] 是一个指针,因此不知道它指向的地址是什么。所以A[0] 不是只指向五个元素的指针,它指向数组的开始位置,并且不知道数组的结束位置。

而 A[1] = 线性A + 5;是连续 6 个元素 - 出于同样的原因? A[1] 不应该是指向 linearA 的第 6 个成员的指针吗?

是的A[1] 指向第六个元素,但如前所述,它是一个起始地址。

【讨论】:

【参考方案4】:

这是因为这一行设置了一个由 6 个指向 float 的指针组成的数组:

float *A[6];

这一行将这些指针中的第一个设置为 30 个中的 第一个元素

A[0] = linearA; 

因此 A 的每个元素都指向原始数组的一个子部分。不过,您必须分配它们 - 它们最初会指向随机地址。

第一个是初始地址(&linearA[0]),接下来的五个是下面的。这些可以通过A[0][0]A[0][5] 访问。因为数组对应指针的方式,可以一直往上走,只要不超过30号。

但是您可以将A[n] 分配给您喜欢的数组的任何部分。只要它是原始数组的一部分,它就会指向该成员,以及接下来的 5 个(或任意多个)。

例如,通过将A[1] 指向&linearA[6],您实际上是在设置一个二维数组(它类似于一个,但不像一个)。

【讨论】:

【参考方案5】:

您发布的示例显示了一种称为 Iliffe vector 的有点深奥的技术,这是在 C 中实现 锯齿状数组 的一种可能方法。锯齿状数组是一个矩阵,其中每一行都有不同的长度.

由于数组在 C 中是一维的,因此您正在创建一个包含所有元素的数组linearA,它被解释为一系列行,每个行的大小不同。指针数组A 包含指向每行第一个元素的指针,允许您使用行和列索引访问元素。

代码展示了 C 指针和数组的几个有趣的特性:

linearA + 5

指针算术:将整数添加到指针(或数组)会得到一个指针,该指针指向原始指针之后的 n 个元素。

A[3][2] = 3.66;

这种漂亮的语法让您可以将此结构视为二维矩阵。

另外,这可能是示例的要点,指针和数组是可以互换的。这里,A[3] 是一个指向浮点数的指针,因为A 被定义为一个浮点数指针数组;附加[2] 为我们提供了在原始指针指向的元素之后2 个位置的元素。这类似于上面的指针算法,只是在这种情况下指针被取消引用。实际上,数组访问是根据指针定义的,所以X[5] 等价于*(X+5)

A[3][-3]

这表明没有什么可以阻止您访问给定行之外的元素。在这种情况下,您正在访问元素 3 个位置A[3] 指向的位置之前。这是很少需要的东西,它只在这种情况下有效,因为您将矩阵构建为具有连续元素。通常,访问数组分配范围之外的元素会导致程序崩溃。

最后,回答你的问题:

A[1] = linearA + 5; 是连续 6 个元素——出于同样的原因? A[1]不应该是指向linearA的第6个成员的指针吗?

由于指针和数组是可互换的,A[1]都是指向linearA中第六个元素的指针一个从@987654338中第六个元素开始的数组@。语言中没有说后者有 6 个元素长,您必须在代码中实现该逻辑。

【讨论】:

以上是关于关于 C 中的指针的主要内容,如果未能解决你的问题,请参考以下文章

关于JAVA调用C的DLL库中的函数问题,传入一个含有指针的结构体指针

C语言指针的内存分配和Java中的引用

关于c++中的this指针

C 和 C++ 中的指针

关于C语言free函数的问题

c语言关于指针引用的问题