K&R:字符指针数组
上页。 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 是指向数组的指针] 和 a++ 这样的结构是非法的。”
On pg. 109 of K&R, we see:
void writelines(char *lineptr[], int nlines)
{
while (nlines -- > 0) printf("%s\n", *lineptr++);
}
I'm confused about what *lineptr++ does exactly. From my understanding, printf requires a char pointer, so we provide that with *lineptr. Then we increment lineptr up to the next char pointer in the array? Isn't this illegal?
On page 99, K&R writes that "an array name is not a variable; constructions like a=pa [where a is an array, pa is a pointer to an array] and a++ are illegal."
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
继续阅读! 在p的最底部。 99
即,您永远不能将数组(不是变量)传递给函数。 如果您声明的函数看起来像是需要一个数组,那么它实际上需要一个指针(它是一个变量)。 这是有道理的。 如果函数参数不是变量,那就很奇怪了——每次调用函数时它都可以有不同的值,所以它肯定不是常量!
Keep reading! At the very bottom of p. 99
I.e. you can never pass an array (which is not a variable) to a function. If you declare a function that looks like it takes an array, it really takes a pointer (which is a variable). This makes sense. It would be odd for a function argument not to be a variable -- it can have a different value every time you call the function so it sure ain't a constant!
lineptr
并不是真正的数组; 它是一个指向指针的指针。 请注意,后自增运算符++
的优先级高于解引用运算符*
,因此lineptr++
中发生的情况如下:lineptr< /code> 递增以指向数组中的下一个元素
lineptr++
的结果是lineptr
的旧值,即指向数组中当前元素的指针因此,while 循环迭代 lineptr 指向的数组中的所有元素(每个element 是一个
char*
) 并打印出来。lineptr
is not really an array; it's a pointer to a pointer. Note that the postincrement operator++
has higher precedence than the dereference operator*
, so what happens inlineptr++
is this:lineptr
gets incremented to point to the next element in the arraylineptr++
is the old value oflineptr
, namely a pointer to the current element in the array*lineptr++
dereferenced that, so it is the value of the current element in the arrayThus, the while loop iterates over all of the elements in the array pointed to by
lineptr
(each element is achar*
) and prints them out.将
*lineptr++
想象如下可能更容易:其中,指向
char*
数组的指针被移动到数组的下一个元素,即,从lineptr[0]
移动到lineptr[1]
。 (由于指针的后缀增量,指针的增量发生在取消引用之后。)所以基本上,会发生以下事情:
lineptr[0]
(类型为char*) 通过引用检索。
lineptr
上的后缀增量。)lineptr[1]
,再次从步骤 1 开始重复该过程。It might be easier to imagine the
*lineptr++
as the following:There, the pointer to the array of
char*
s is moved to the next element of the array, that is, fromlineptr[0]
, we move tolineptr[1]
. (The increment of the pointer occurs after the dereferencing due to the postfix increment of the pointer.)So basically, the following things happen:
lineptr[0]
(of typechar*
) is retrieved by deferencing.lineptr
.)lineptr[1]
, repeat the process from step 1 again.亚当·罗森菲尔德选择的答案是错误的。 coobird的答案也是。 因此,我对这两个答案都投了反对票。
Adam Markowitz 对 *lineptr++ 的解释是正确的,但他没有回答主要问题这是否是合法的 C99 代码。 只有汤姆·未来做到了; 不幸的是他没有解释
*lineptr++
。 我给他们每人一分。简而言之,lineptr 是一个变量,可以作为指针进行操作。 因此增加指针是合法的。
lineptr 是指向字符序列的指针序列的指针。 换句话说,它是指向字符串数组的第一个字符串的指针。 根据代码,我们可以假设字符串是以空('\0')结尾的字符序列。
nlines
是数组中字符串的数量。while 测试表达式为 nlines-- > 0 。
nlines--
是后减量(因为--
位于变量的右侧)。 因此,无论测试结果如何,它都会在执行测试之后执行,因此在任何情况下都是如此。因此,如果作为参数给出的
nlines
值为0
,则首先执行测试并返回false
; 循环中的指令不被执行。 请注意,由于nlines
无论如何都会递减,因此while
循环之后的nlines
的值将为-1
。如果
nlines == 1
,测试将返回true
并且nlines
将递减; 循环中的指令将被执行一次。 请注意,执行这些指令时,nlines
的值为0
。 当再次执行测试时,我们又回到了nlines == 0
的情况。printf
指令使用*lineptr++
表达式。 它是指针的后增量(++
位于变量的右侧)。 这意味着首先对表达式求值,然后在使用后执行增量。 因此,在第一次执行时,printf
收到字符串数组第一个元素的副本,它是指向字符串第一个字符的指针。 仅在此之后lineptr
才会递增。 下次执行 printf 时,lineptr 指向第二个元素,并在打印第二个字符串后移动到第三个元素。 这是有道理的,因为我们显然想要打印第一个字符串。 如果 Adam Rosenfield 是对的,那么第一个字符串将被跳过,最后我们将尝试打印最后一个字符串之外的字符串,这显然是一件坏事。因此,printf 指令是以下两条指令的简洁形式。
请注意,根据经验,当前置增量和后置增量在其操作上等效时,前置增量更适合性能原因。 编译器会小心地为你切换它。 嗯,大多数时候。 只要有可能,最好由预操作员自己进行,因此始终使用它。 一旦您自己在 C++ 中实现了后增量和预增量,原因就会变得更加明确。
The selected answer of Adam Rosenfield is wrong. The answer of coobird too. For that reason I down voted both answers.
Adam Markowitz interpretation of
*lineptr++
is right, but he doesn't answer the main question whether this is legal C99 code. Only Tom Future does; unfortunately he doesn't explain*lineptr++
. I granted them a point each.So for short,
lineptr
is a variable and can be manipulated as a pointer. It is thus legal to increment the pointer.lineptr
is a pointer into a sequence of pointers to sequences of chars. In other words it is a pointer to the first string of a string array. According to the code we can assume that the strings are null ('\0') terminated char sequences.nlines
is the number of strings in the array.The while test expression is
nlines-- > 0
.nlines--
is a post decrement (because--
is on the right of the variable). It is thus executed after the test has been performed and regardless of the test result, so in any case.So, if the
nlines
value given as argument was0
, the test is performed first and returnsfalse
; the instructions in the loop are not executed. Note that sincenlines
is decremented anyway, the value ofnlines
after thewhile
loop will be-1
.If
nlines == 1
, the test will returntrue
andnlines
will be decremented; the instructions in the loop will be executed once. Note that while these instructions are executed the value ofnlines
is0
. When the test is performed again, we are back to the case whennlines == 0
.The
printf
instruction uses the*lineptr++
expression. It is a post increment of the pointer (++
is on the right of the variable). This means the expression is evaluated first and the increment is performed after its use. So on the first executionprintf
receives a copy of the first element of the string array, which is a pointer to the first char of the strings. Thelineptr
is incremented only after that. The next time theprintf
is to be executed,lineptr
points on the second element and will be move to the third when the second string has been printed. This makes sense because we obviously want to print the first string. If Adam Rosenfield was right, the first string would have been skipped and at the end we would try to print the string beyond the last one which is obviously a bad thing to do.So, the
printf
instruction is a concise form of the two following instructionsNote, as a rule of thumb, that when pre- and post-increment are equivalent in their action, the pre-increment is preferable for performance reasons. The compilers will take care to switch it for you. Well, most of the time. It is better to the the pre- operators yourself, whenever possible, so it is used always. The reason becomes more explicit once you implement a post- and pre- increment yourself in C++.
我认为上面的答案都没有回答这个问题,也就是说,为什么,
lineptr
,一个数组的名称而不是一个变量,可以像K&R中那样递增,甚至是最受支持的chmike 的回答只说了一些关于运算符的结合性的内容,但仍然没有抓住问题的要点。我认为这个问题的答案在于这个定义:
也就是说,这里的
lineptr
不再是数组lineptr
的名字,而已经退化为应该被当作一个指针。参考:
I think none of the answers above has answered the question, that is, why,
lineptr
, the name of an array and not a variable, can be incremented as in K&R, and even the most upvoted answer by chmike only says something about the associativity of operators but still misses the point of the question.And I think the answer to this question lies in this definition:
Which is to say,
lineptr
here is no longer the name of the arraylineptr
, and has decayed into and should be treated as a pointer.Reference: