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