on pg。 K& R的109,我们看到:
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是指向数组的指针]和++是非法的。”
答案 0 :(得分:7)
继续阅读!在p的最底部。 99
作为函数定义中的形式参数,
char s[];
和
char *s;
是等价的;我们更喜欢后者,因为它更明确地说参数是一个指针。
即。你永远不能将一个数组(不是一个变量)传递给一个函数。如果你声明一个看起来像是一个数组的函数,它实际上需要一个指针( 一个变量)。这是有道理的。函数参数不是变量会很奇怪 - 每次调用函数时它都可以有不同的值,所以肯定不是常量!
答案 1 :(得分:6)
lineptr
实际上并不是一个数组;它是指向指针的指针。请注意,postincrement运算符++
的优先级高于取消引用运算符*
,因此lineptr++
中发生的情况是:
lineptr
增加指向数组中的下一个元素lineptr++
的结果是lineptr
的旧值,即指向数组中当前元素的指针*lineptr++
取消引用,因此它是数组中当前元素的值因此,while循环遍历lineptr
指向的数组中的所有元素(每个元素都是char*
)并打印出来。
答案 2 :(得分:5)
可能更容易想象*lineptr++
如下:
*(lineptr++)
在那里,指向char*
数组的指针被移动到数组的下一个元素,即从lineptr[0]
移动到lineptr[1]
。 (由于指针的后缀增量,在解除引用后会出现指针的增量。)
基本上,以下事情发生了:
lineptr[0]
(类型char*
)。lineptr
上的后缀增量。)lineptr[1]
,再次从步骤1重复该过程。答案 3 :(得分:4)
Adam Rosenfield的精选答案是错误的。还有coobird的答案。出于这个原因,我投了两个答案。
Adam Markowitz对*lineptr++
的解释是正确的,但他没有回答主要问题,这是否是合法的C99代码。只有汤姆未来呢;不幸的是,他没有解释*lineptr++
。我给了他们一个点。
简而言之,lineptr
是一个变量,可以作为指针进行操作。因此增加指针是合法的。
lineptr
是指向字符序列的指针序列的指针。换句话说,它是指向字符串数组的第一个字符串的指针。根据代码,我们可以假设字符串是null('\ 0')终止的char序列。 nlines
是数组中的字符串数。
while测试表达式为nlines-- > 0
。 nlines--
是一个后减量(因为--
位于变量的右侧)。因此,在执行测试后执行,无论测试结果如何,所以无论如何都是如此。
因此,如果作为参数给出的nlines
值为0
,则首先执行测试并返回false
;循环中的指令不会执行。请注意,由于nlines
无论如何都会递减,nlines
循环之后的while
值将为-1
。
如果nlines == 1
,则测试将返回true
,nlines
将递减;循环中的指令将执行一次。请注意,执行这些说明时,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 ++中实现后期和预先增量,原因就变得更加明确了。
答案 4 :(得分:0)
我认为以上答案都无法回答问题,即为什么lineptr
(数组名而不是变量)可以像K&R一样递增,甚至是最受支持的答案chmike只是说了一些运算符的关联性,但仍然没有回答问题的重点。
我认为这个问题的答案就在于以下定义:
对T型数组对象的引用,该对象出现在表达式中(三个例外)衰减为指向其第一个元素的指针;结果指针的类型是T指针。
这就是说,lineptr
不再是数组lineptr
的名称,它已经衰落为指针,应被视为指针。
参考: