K&R:字符指针数组

发布于 2024-07-18 08:47:53 字数 380 浏览 4 评论 0原文

上页。 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

欢烬 2024-07-25 08:47:53

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

作为函数定义中的形式参数,

 char s[]; 
  

<前><代码> char *s;

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

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

Keep reading! At the very bottom of p. 99

As formal parameters in a function definition,

 char s[];

and

 char *s;

are equivalent; we prefer the latter because it says more explicitly that the parameter is a pointer.

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!

温柔嚣张 2024-07-25 08:47:53

lineptr 并不是真正的数组; 它是一个指向指针的指针。 请注意,后自增运算符 ++ 的优先级高于解引用运算符 *,因此 lineptr++ 中发生的情况如下:

  1. lineptr< /code> 递增以指向数组中的下一个元素
  2. lineptr++ 的结果是 lineptr 的旧值,即指向数组中当前元素的指针
  3. < code>*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 in lineptr++ is this:

  1. lineptr gets incremented to point to the next element in the array
  2. The result of lineptr++ is the old value of lineptr, namely a pointer to the current element in the array
  3. *lineptr++ dereferenced that, so it is the value of the current element in the array

Thus, the while loop iterates over all of the elements in the array pointed to by lineptr (each element is a char*) and prints them out.

遗失的美好 2024-07-25 08:47:53

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

*(lineptr++)

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

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

  1. lineptr[0](类型为char*) 通过引用检索。
  2. 指针递增到数组的下一个元素。 (通过指针 lineptr 上的后缀增量。)
  3. 指针现在指向 lineptr[1],再次从步骤 1 开始重复该过程。

It might be easier to imagine the *lineptr++ as the following:

*(lineptr++)

There, the pointer to the array of char*s is moved to the next element of the array, that is, from lineptr[0], we move to lineptr[1]. (The increment of the pointer occurs after the dereferencing due to the postfix increment of the pointer.)

So basically, the following things happen:

  1. lineptr[0] (of type char*) is retrieved by deferencing.
  2. The pointer is incremented to the next element of the array. (By the postfix increment on pointer lineptr.)
  3. The pointer now points to lineptr[1], repeat the process from step 1 again.
寻梦旅人 2024-07-25 08:47:53

亚当·罗森菲尔德选择的答案是错误的。 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 指令是以下两条指令的简洁形式。

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

请注意,根据经验,当前置增量和后置增量在其操作上等效时,前置增量更适合性能原因。 编译器会小心地为你切换它。 嗯,大多数时候。 只要有可能,最好由预操作员自己进行,因此始终使用它。 一旦您自己在 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 was 0, the test is performed first and returns false; the instructions in the loop are not executed. Note that since nlines is decremented anyway, the value of nlines after the while loop will be -1.

If nlines == 1, the test will return true and nlines will be decremented; the instructions in the loop will be executed once. Note that while these instructions are executed the value of nlines is 0. When the test is performed again, we are back to the case when nlines == 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 execution printf receives a copy of the first element of the string array, which is a pointer to the first char of the strings. The lineptr is incremented only after that. The next time the printf 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 instructions

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

Note, 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++.

鲜血染红嫁衣 2024-07-25 08:47:53

我认为上面的答案都没有回答这个问题,也就是说,为什么,lineptr,一个数组的名称而不是一个变量,可以像K&R中那样递增,甚至是最受支持的chmike 的回答只说了一些关于运算符的结合性的内容,但仍然没有抓住问题的要点。

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

对出现在表达式中的 array-of-T 类型对象的引用会衰减(有三个例外)为指向其第一个元素的指针; 结果指针的类型是指向 T 的指针。

也就是说,这里的lineptr不再是数组lineptr的名字,而已经退化为应该被当作一个指针。

参考:

  1. http://c-faq.com/aryptr/aryptrequiv.html
  2. < a href="https://stackoverflow.com/questions/19646512/passing-an-array-by-reference-in-c">在 C 中通过引用传递数组

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:

A reference to an object of type array-of-T which appears in an expression decays (with three exceptions) into a pointer to its first element; the type of the resultant pointer is pointer-to-T.

Which is to say, lineptr here is no longer the name of the array lineptr, and has decayed into and should be treated as a pointer.

Reference:

  1. http://c-faq.com/aryptr/aryptrequiv.html
  2. Passing an Array by reference in C
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文