K&R:字符指针数组

Elb*_*ira 5 c arrays pointers kernighan-and-ritchie

在pg.K&R的109,我们看到:

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

我对*lineptr ++究竟做了什么感到困惑.根据我的理解,printf需要一个char指针,所以我们提供*lineptr.然后我们将lineptr增加到数组中的下一个char指针?这不是非法的吗?

在页99,K&R写道"数组名称不是变量;结构如a = pa [其中a是数组,pa是指向数组的指针]和++是非法的."

Tom*_*ure 7

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

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

 char s[];
Run Code Online (Sandbox Code Playgroud)

 char *s;
Run Code Online (Sandbox Code Playgroud)

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

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


Ada*_*eld 6

lineptr不是一个阵列; 它是指向指针的指针.请注意,postincrement运算符的++优先级高于dereference运算符*,因此会发生以下情况lineptr++:

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

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


coo*_*ird 5

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

*(lineptr++)
Run Code Online (Sandbox Code Playgroud)

在那里,指向char*s 数组的指针被移动到数组的下一个元素,即从lineptr[0],移动到lineptr[1].(由于指针的后缀增量,在解除引用后会出现指针的增量.)

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

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


chm*_*ike 4

亚当·罗森菲尔德选择的答案是错误的。coobird的答案也是。因此,我对这两个答案都投了反对票。

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

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

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

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

因此,如果nlines作为参数给出的值为0,则首先执行测试并返回false; 循环中的指令不被执行。请注意,since无论如何都会递减,循环后nlines的值将为。nlineswhile-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.
Run Code Online (Sandbox Code Playgroud)

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