5

在第 页。109 的 K&R,我们看到:

void writelines(char *lineptr[], int nlines)
{
  while (nlines -- > 0) printf("%s\n", *lineptr++);
}

我对 *lineptr++ 究竟做了什么感到困惑。据我了解,printf 需要一个 char 指针,因此我们使用 *lineptr 提供它。然后我们将 lineptr 增加到数组中的下一个 char 指针?这不是违法的吗?

在第 99 页,K&R 写道:“数组名称不是变量;像 a=pa [其中 a 是数组,pa 是指向数组的指针] 和 a++ 这样的结构是非法的。”

4

5 回答 5

7

继续阅读!在 p 的最底部。99

作为函数定义中的形参,

 char s[];

 char *s;

是等价的;我们更喜欢后者,因为它更明确地说参数是一个指针。

即,您永远不能将数组(不是变量)传递给函数。如果你声明的函数看起来像一个数组,它实际上是一个指针(它一个变量)。这是有道理的。函数参数不是变量会很奇怪——每次调用函数时它都可以有不同的值,所以它肯定不是常量!

于 2009-05-08T03:21:06.030 回答
6

lineptr不是真正的数组;它是指向指针的指针。请注意,后增量运算符++的优先级高于取消引用运算符*,因此发生的情况lineptr++是:

  1. lineptr递增以指向数组中的下一个元素
  2. 的结果lineptr++是 的旧值lineptr,即指向数组中当前元素的指针
  3. *lineptr++取消引用,所以它是数组中当前元素的值

因此,while 循环遍历数组中的所有元素lineptr(每个元素都是 a char*)并将它们打印出来。

于 2009-05-08T02:57:37.520 回答
5

可能更容易想象*lineptr++如下:

*(lineptr++)

在那里,指向char*s 数组的指针被移动到数组的下一个元素,即从lineptr[0],我们移动到lineptr[1]。(由于指针的后缀增量,指针的增量发生在取消引用之后。)

所以基本上,会发生以下事情:

  1. lineptr[0](类型char*)通过延迟检索。
  2. 指针递增到数组的下一个元素。(通过指针上的后缀增量lineptr。)
  3. 指针现在指向lineptr[1],再次从步骤 1 重复该过程。
于 2009-05-08T02:58:18.830 回答
4

Adam Rosenfield 选择的答案是错误的。coobird的答案也是如此。出于这个原因,我对这两个答案都投了反对票。

Adam Markowitz 的解释*lineptr++是正确的,但他没有回答主要问题这是否是合法的 C99 代码。只有 Tom Future 能做到;不幸的是,他没有解释*lineptr++。我给他们每人一分。

所以简而言之,lineptr是一个变量,可以作为指针进行操作。因此,增加指针是合法的。

lineptr是指向字符序列的指针序列的指针。换句话说,它是指向字符串数组的第一个字符串的指针。根据代码,我们可以假设字符串是空('\0')终止的字符序列。 nlines是数组中的字符串数。

while 测试表达式是nlines-- > 0. nlines--是后减量(因为--在变量的右侧)。因此,它在执行测试之后执行,无论测试结果如何,在任何情况下都是如此。

因此,如果nlines作为参数给出的值是0,则首先执行测试并返回false; 循环中的指令不被执行。请注意,因为nlines无论如何都会递减,所以nlinesafterwhile循环的值将是-1.

如果nlines == 1,则测试将返回truenlines递减;循环中的指令将执行一次。请注意,在执行这些指令时, 的nlines值为0。再次执行测试时,我们又回到了nlines == 0.

printf指令使用*lineptr++表达式。它是指针的后增量(++位于变量的右侧)。这意味着首先计算表达式,并在使用执行增量。所以在第一次执行时printf会收到字符串数组第一个元素的副本,它是指向字符串第一个字符的指针。lineptr只有在那之后才增加。下次printf执行时,lineptr点在第二个元素上,并在打印第二个字符串时移动到第三个。这是有道理的,因为我们显然想要打印第一个字符串。如果 Adam Rosenfield 是对的,第一个字符串会被跳过,最后我们会尝试打印超出最后一个字符串的字符串,这显然是一件坏事。

因此,该printf指令是以下两个指令的简明形式

printf("%s\n", *lineptr);
++lineptr; // or lineptr++, which is equivalent but not as good. lineptr += 1; is ok too.

请注意,根据经验,当前置增量和后置增量的作用相同时,出于性能原因,前置增量更可取。编译器会小心为您切换它。嗯,大多数时候。只要有可能,对预操作员自己最好,所以总是使用它。一旦您在 C++ 中实现了后自增和预自增,原因就会变得更加明确。

于 2009-05-08T06:42:10.523 回答
0

我认为上面的答案都没有回答这个问题,也就是说,为什么lineptr数组的名称而不是变量的名称可以像 K&R 中那样递增,即使是 chmike 最赞成的答案也只能说明关联性运营商,但仍然错过了问题的重点。

我认为这个问题的答案在于这个定义:

对出现在表达式中的数组 T 类型对象的引用衰减(除了三个例外)成指向其第一个元素的指针;结果指针的类型是指向 T 的指针。

也就是说,lineptr这里不再是数组的名字了lineptr,已经衰减成指针了。

参考:

  1. http://c-faq.com/aryptr/aryptrequiv.html
  2. 在 C 中通过引用传递数组
于 2019-10-13T14:19:27.640 回答