C语言 C中带有指针的for循环

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33829566/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 12:13:35  来源:igfitidea点击:

For loop with pointer in C

carraysstringpointersfor-loop

提问by MeChris

I don't understand what a pointer does in the forloop. What does the *pdo in the following loop?

我不明白指针在for循环中的作用。在下面的循环中做什么*p

char str[128] = "Some Text";
char *p;

for (p = str; *p /*what does this mean?*/; p++)
{
    // Code
}

I do understand the rest, but why isn't *plike p > 3or something like that?
Why is it alone?
Why is it written that way?

我确实理解其余的,但为什么不*p喜欢p > 3或类似的东西?
为什么是一个人?
为什么这么写?

回答by errikos

In a Boolean context such as the condition of a forloop, each expression in C evaluates to true (non-zero) or false (zero).

在诸如for循环条件的布尔上下文中,C 中的每个表达式的计算结果为真(非零)或假(零)。

You want the forloop to terminate, when it reaches the end of the string.

您希望for循环在到达字符串末尾时终止。

In C, each string is terminated with the character '\0', which is practically 0. So, when the forloop reaches the end of string, *pevaluates to '\0', which is 0, which evaluates to false, which terminates the forloop.

在 C 中,每个字符串都以字符 结束'\0',实际上是0. 因此,当for循环到达字符串末尾时,*p计算结果为'\0',即0,计算结果为 false,从而终止for循环。

回答by Manos Nikolaidis

The for loop will terminate if whatever lies between the two ;in the statement is zero (false). *pdereferences p and returns the char, ppoints to. According to Dennis Ritchie"C treats strings as arrays of characters conventionally terminated by a marker". That marker is the null character with (ASCII) value of zero. So, this for loop :

如果;语句中两者之间的内容为零(假),则 for 循环将终止。*p取消引用 p 并返回char,p指向。根据Dennis Ritchie 的说法,“C 将字符串视为通常由标记终止的字符数组”。该标记是 (ASCII) 值为零的空字符。所以,这个 for 循环:

for (p = str; *p; p++)

is equivalent to these

相当于这些

for (p = str; *p != '
0x00007fffffffe6a0:
  0x53 0x6f 0x6d 0x65 0x20 0x54 0x65 0x78 0x74 0x00 0x00 0x00 0x00 0x00 0x00 0x00
     S    o    m    e         T    e    x    t
'; p++) for (p = str; *p != 0; p++) for (p = str; p[0] != '
for (p = str; *p != '
if(expr)
'; p++) { // Code }
'; p++)

Another name for the null terminating character is sentinelor according to Donald Knuth "dummy value"(Art of Computer Programming, Volume 1). Here is a diagram of the strstring, the indexes (offsets from the start) of each character and the values at each index :

空终止字符的另一个名称是哨兵或根据 Donald Knuth 的“虚拟值”(计算机编程艺术,第 1 卷)。这是str字符串的图表,每个字符的索引(从开始的偏移量)和每个索引处的值:

enter image description here

在此处输入图片说明

For completeness and after a request at the comments here is what the debugger sees in the memory block that stroccupies :

为了完整起见,在此处的评论处提出请求后,调试器会在str占用的内存块中看到:

if((expr) != 0)  
  1. The hex value at the first line is the address (64bit) of this memory block. That's where ppoints to at the start of the for loop.
  2. On the 2nd line you see the hex values of the letters in your string. You can see an ASCII table here. The last char in your string is twith hex value of 0x74. After that you have the string's null character 0x00. Then you see a few more null characters because I built in debug mode and the compiler zero-initialized. Normally you would see garbage (seemingly random values)
  3. On the 3rd line I added the chars of your string for reference
  1. 第一行的十六进制值是这个内存块的地址(64 位)。这就是pfor 循环开始处指向的地方。
  2. 在第二行,您会看到字符串中字母的十六进制值。您可以在此处查看 ASCII 表。字符串中的最后一个字符的t十六进制值为0x74. 之后,您将获得字符串的空字符0x00。然后你会看到更多的空字符,因为我在调试模式下构建并且编译器初始化为零。通常你会看到垃圾(看似随机的值)
  3. 在第三行我添加了你的字符串的字符以供参考

I understand you are on precipitous learning curve at the moment with pointers in C, but eventually you'll be able to say "I C the point"

我知道您目前正处于 C 语言指针的陡峭学习曲线上,但最终您将能够说“IC the point”

回答by KeylorSanchez

This could be rewritten like this

这可以像这样重写

if(expr)

In C, a string must always be terminated by a null character, which is the same as '\0' or 0.

在 C 中,字符串必须始终以空字符结尾,这与 '\0' 或0.

回答by haccks

Before diving in, I would like to state a simple rule in C regarding an expression

在深入研究之前,我想在 C 中陈述一个关于表达式的简单规则

When C requires the Boolean value of an expression, a falsevalue is inferred when the expression compares equal to zero, and a truevalue otherwise. That is, whenever one writes

if((expr) != 0)  

where expris any expression at all, the compiler essentially acts as if it had been written as

for (p = str; *p; p++)

当C需要的表达的布尔值,一个false当表达式等于比较值推断,以及true以其他方式的值。也就是说,每当有人写

p = &str[0];
p = str; 

哪里expr有任何表达式,编译器本质上就像它被写成

char str[128] = "Some Text";

Now coming to your question:

现在来回答你的问题:

What does the *pdo in the following loop?

*p在下面的循环中做什么?

In C, strings are terminated by a null character '\0'.

在 C 中,字符串以空字符结尾'\0'

enter image description here

在此处输入图片说明

Every character has a decimal equivalent. This '\0'is an ASCII escape character. The decimal equivalent of '\0'is 0.

每个字符都有一个十进制等效值。这'\0'是一个ASCII 转义字符的十进制等价物'\0'0

So, the expression *pin loop just check that the decimal equivalent of character at the memory address pointed by pis either a zero or non-zero. When preaches the end of the string and finds the first '\0'character, the expression *preturns1a zero value. A zero means falsein C. This is equivalent to testing *p != '\0'or *p != 0as stated above.

因此,*p循环中的表达式只是检查所指向的内存地址处字符的十进制等效p值是零还是非零。当p到达字符串末尾并找到第一个'\0'字符时,表达式*p返回1零值。C 中的零表示false。这相当于测试*p != '\0'*p != 0如上所述。

This is how it works:

这是它的工作原理:

enter image description here

在此处输入图片说明



1When *pevaluates then the value of *pis fetched from memory. This value is the value of expression *p.

1*p求值时,*p从内存中获取的值。该值是 expression 的值*p

回答by dhein

Lets analyze it the dry but depth way!

让我们用枯燥而深入的方式分析它!

Or as D. Ritchie would say: Let's do it with the power of assembly language and the convenience of … assembly language.

或者正如 D. Ritchie 所说:让我们利用汇编语言的强大功能和……汇编语言的便利来实现它



I'll try to explain all necessary aspects by referencing the ISO/IEC:9899 (emphasis mine)- C99 standard. (The post style is motivated by Donald Knuth's phrase "Science is what we understand well enough to explain to a computer. Art is everything else we do. ")

我将尝试通过参考 ISO/IEC:9899(强调我的)- C99 标准来解释所有必要的方面。(帖子风格的动机是唐纳德·克努斯(Donald Knuth)的那句话“科学是我们理解得足以向计算机解释的东西。艺术是我们所做的一切。”

First of all, lets inspect what exactly is the for-loop supposed to do!

首先,让我们检查一下for-loop到底应该做什么!

Referring to ISO/IEC:9899 6.8.5 "Iteration statements"

参考 ISO/IEC:9899 6.8.5“迭代语句”

Semantics

4 An iteration statement causes a statement called the loop body to be executed repeatedly until the controlling expression compares equal to 0.

语义

4 迭代语句会导致重复执行称为循环体的语句,直到控制表达式比较等于 0 为止

So far nothing new I guess, so lets get it on:

到目前为止,我猜没有什么新东西,所以让我们开始吧:

6.8.5.3 The for statement

1 The statement for ( clause-1 ; expression-2 ; expression-3 ) statement

behaves as follows: The expression expression-2 is the controlling expressionthat is evaluated before each executionof the loop body. ...

6.8.5.3 for 语句

1 声明 for ( clause-1 ; expression-2 ; expression-3 ) statement

的行为如下:表达式表达-2是控制表达每次执行之前计算循环体。...

So we now know the body (in your case // Code) will be executed as long the beforehand evaluated value of your *pis not zero.

所以我们现在知道// Code只要你的预先评估值*p不为零,主体(在你的情况下)就会被执行。

... The expression expression-3 is evaluatedas a void expression after each executionof the loop body.[...]

...在每次执行循环体,表达式expression-3 被评估为 void 表达式。[...]

So now we know, (I assume digging up p++'s definition is not necessary?!) that for each iteration pincrements, so there may be a change in *p.

所以现在我们知道,(我认为挖掘p++的定义没有必要?!)每次迭代p都会增加,所以*p.

The following point is not related, but I'm adding it since this makes the Semantic part of forcomplete and its well to know since its the reason, why for(;;)is a inf-loop.

以下点不相关,但我添加它,因为这使得语义部分for完整并且很清楚,因为它的原因,为什么for(;;)是一个 inf-loop。

2 (---)Both clause-1 and expression-3 can be omitted. An omitted expression-2 is replaced by a nonzero constant.

2 (---)子句 1 和表达式 3 都可以省略。省略的表达式 2 由非零常量替换。

Ok, that's the dry but information-enriched part of what the forloop does in your case.

好的,这就是for循环在您的情况下所做的枯燥但信息丰富的部分。

Now lets get over to pointer arithmetic:

现在让我们来看看指针算法:

6.5.6 Additive operators

Constraints

2 For addition, either both operands shall have arithmetic type, or one operand shall be a pointer to an objecttype and the other shall have integer type. (Incrementing is equivalent to adding 1.)

6.5.6 加法运算符

约束

2 对于加法,要么两个操作数都为算术类型,要么一个操作数为指向对象类型的指针另一个操作数为整数类型。(递增相当于加1。

So in your case you are adding 1 (integer) to the "pointer to an object"-type.

因此,在您的情况下,您将 1(整数)添加到“指向对象的指针”类型。

What is equivalent to increasing the Address by the sizeof its pointed to type like shown in this picture of tomislav kostic:

相当于通过其指向类型的 sizeof 增加地址,如tomislav kostic 的这张图片所示:

CC BY-SA 3.0 by tomislav kostic

CC BY-SA 3.0 by tomislav Kostic

Now lets see what *pactually does.

现在让我们看看*p实际做了什么。

6.5.3.2 Address and indirection operators

Constraints

[...]

2 The operand of the unary * operator shall have pointer type.

Semantics

[...]

4 The unary * operator denotes indirection. If the operand points to a function, the result is a function designator; if it points to an object, the result is an lvalue designating the object. If the operand has type ‘‘pointer to type'', the result has type ‘‘type''. If an invalid value has been assigned to the pointer, the behavior of the unary * operator is undefined.

6.5.3.2 地址和间接运算符

约束

[...]

2 一元 * 运算符的操作数应为指针类型。

语义

[...]

4 一元 * 运算符表示间接。如果操作数指向一个函数,则结果是一个函数指示符;如果它指向一个对象,则结果是一个指定对象的左值。如果操作数的类型为“指向类型的指针”,则结果的类型为“类型”。如果为指针分配了无效值,则一元 * 运算符的行为未定义。

This is a bit dry again1but for better understanding this can be reverse engineered by:

这又有点枯燥1但为了更好地理解这可以通过以下方式进行逆向工程:

6.5.2.1 Array subscripting

[...]

Semantics

2 A postfix expression followed by an expression in square brackets [] is a subscripted designation of an element of an array object. The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2))).

6.5.2.1 数组下标

[...]

语义

2 后缀表达式后跟方括号 [] 中的表达式是数组对象元素的下标指定。下标运算符 [] 的定义是 E1[E2] 与 (*((E1)+(E2))) 相同

So *((p)+(0))what is(since p+0is same as p... obvious) is equal to p[0], is doing nothing else as evaluating p's object.

所以*((p)+(0))is(since p+0is same as p... 明显) is equal to p[0],作为评估p的对象不做任何其他事情。

And since we know, expression-2of a for loop is interrupting the iteration if it is evaluating 0, we can say it is the same as p[0] != 0.

并且因为我们知道,expression-2如果 for 循环正在评估0,则它会中断迭代,我们可以说它与 相同p[0] != 0

Now the final step

现在是最后一步

Lets just look onto the C-Coder's Friend; JSSCA... No, wait...our friend was called... ASCIINow as that's clarified, we can figure out what the 0is representing.

让我们看看 C-Coder 的朋友; JSSCA... 不,等等...我们的朋友被称为... ASCII现在已经澄清了,我们可以弄清楚0代表什么。

It is the NULL-token that in C is designating the end of a string.

NULL 标记在 C 中指定字符串的结尾。



So conclusive:

所以结论是:

All, this is doing is:

所有,这是在做的是:

Iterating the body of that for-loop, until pis actually pointing to the address, where the object evaluates to the "end of string"-token.

迭代该for-loop的主体,直到p实际指向地址,该对象评估为“字符串结尾”-token。

Or:

或者:

Let pgo through the string until the end is reached.

让我们p穿过绳子直到到达终点。



And now just to cite my self; Something you never should forget:
(emphasis mine.....)

现在只是引用我自己;你永远不应该忘记的东西:(
强调我的......)

A variable is declared through a declarator(type-specifier) that precedes the identifier which names an lvalue object that can be evaluated to its value

变量是通过一个声明类型说明符)声明的,该声明位于标识符之前,该标识符命名了一个左值对象,该对象可以被评估为它的值

It is neither more nor less!

不多也不少!



1That is, what I promised! ;)

1那就是我的承诺!;)

回答by terence hill

The *p Haiku

*p俳句

Poetically, I tried to represent the struggling of *pin the loop:

在诗意上,我试图表示*p在循环中的挣扎:

Brave C *p(rogrammers)

In the loop of whilederness

The NUL will stop them

勇敢的 C *p(程序员)

在悠闲的循环中

NUL 会阻止他们

This is an haiku poem, it consists of three lines, with the first and last line having 5 syllable, and the middle line having 7. Another example by @Samidamaru (a Master Haiku Poet, see comment below): First p equals str, Then p is incremented, Until *p is NUL.

这是一首俳句,它由三行组成,第一行和最后一行有 5 个音节,中间一行有 7 个。@Samidamaru 的另一个例子(俳句大师,见下面的评论):第一个 p 等于 str,然后 p 递增,直到 *p 为 NUL。



A little bit of pop

一点点流行

enter image description here

在此处输入图片说明

Hour of Code ambassador, Jessica Alba

编程一小时大使杰西卡·阿尔芭



What does the *p do in the loop?

*p 在循环中做什么?

Following the imaginary advice of Jessica (who is citing D. Knuth (1)), we will try to seethe meaning of *pin the for loop:

遵循 Jessica(引用 D. Knuth (1))的虚构建议,我们将尝试查看for 循环中*p的含义:

#include <stdio.h>
int main() {
    char str[128] = "We all scream for ice cream!";
    char *p = str;
    // here we see again the loop exit condition *p == '
WHY   for (p=str; *p;        p++)
IS    for (p=str; p[0] != 0; p++)
THINK for (i=0;   str[i];    ++i)
' while(*p) { printf("%c", *p); p++; } printf("\n"); }

To this goal we first examine how the unary operator"*" works in C: “The unary operator * is the indirection or deferencing operator; when applied to a pointer, it access the object the pointer points to.” (B. Kernighan and D. Ritchie (2))

为此,我们首先检查一元运算符“*”在 C 中的工作方式:“一元运算符 * 是间接或递推运算符;当应用于指针时,它访问指针指向的对象。” (B. Kernighan 和 D. Ritchie (2))

So *p is simply the value pointed by p:

所以 *p 只是 p 指向的值

enter image description here

在此处输入图片说明

1.1 A closer look to the for loop

1.1 深入了解 for 循环

The for loop is composed of three instructions:

for 循环由三个指令组成:

  1. p = str
  2. *p
  3. p++
  1. p = str
  2. *p
  3. p++

In 1. we assign the pointer to the array strto p. In C the following assignments have the same effect:

在 1. 我们将指向数组str的指针分配给p。在 C 中,以下赋值具有相同的效果:

##代码##

“By definition, the value of a variable or expression of type array is the address of element zero of the array” (K & R (2)). Moreover we have that “In evaluating a[i], C converts it to *(a+i)immediately. …. it follows that &a[i]and a+iare identical” (K & R (2)). If we put i = 0, we obtain the above assignments.

“根据定义,数组类型的变量或表达式的值是数组元素零的地址”(K & R (2))。此外,我们有“在评估a[i] 时,C 立即将其转换为*(a+i)。…… 因此&a[i]a+i是相同的”(K & R (2))。如果我们把i = 0,我们得到上面的分配。

We can now state that, at the beginning of the for loop, ppoints to the first element of str.

我们现在可以声明,在 for 循环开始时,p指向str的第一个元素。

1.2 The core of the question

1.2 问题的核心

Let's move to the point 2., the core of your question. The second expression of the loop controls the exit condition: the instruction "*p" is evaluated and if is false the loop exit. This means that "*p" is equivalent to "*p != 0" or in words: when the value pointed by p is zero, exit.

让我们转到第 2 点,即您问题的核心。循环的第二个表达式控制退出条件:评估指令“*p”,如果为假则循环退出。这意味着 "*p" 等价于 "*p != 0" 或在字面上:当 p 指向的值为零时,退出

Now, to understand when *p is zero we recall that the array strhas been initialised as follows:

现在,要了解 *p 何时为零,我们回想一下数组str已按如下方式初始化:

##代码##

and: “all string constants contain a null termination character (\0) as their last character” (gnu-manual). So the string actually stored in memory has a \0 at the end: "Some Text\0".

和:“所有字符串常量都包含一个空终止字符 (\0) 作为它们的最后一个字符”(gnu-manual)。所以实际存储在内存中的字符串末尾有一个\0:“Some Text\0”。

In the third instruction, p++, the pointer pis advanced to the next element of the strarray, thus, at the 9-th iteration *pbecame 0 (or \0, NULL, NUL, see the answer from @Joe) and the loop exits.

在第三条指令p++ 中,指针p前进到str数组的下一个元素,因此,在第 9 次迭代时*p变为 0(或 \0、NULL、NUL,请参阅@Joe 的答案)和循环退出。

1.3 See to believe

1.3 相信

A picture is worth a thousand words, here is a graphical representation of the loop:

一张图值一千字,这是循环的图形表示:

enter image description here

在此处输入图片说明

1.4 A further example: the same usage of *p in a different example

1.4 另一个例子:*p 在不同例子中的相同用法

In the following snippet *pis used the same way but in a while loop:

在以下代码段中, *p的使用方式相同,但在 while 循环中使用:

##代码##

May the for(;*C;)e be with you!

愿原力与你同在!



References

参考

(1) Vol. I, Fundamental Algorithms, Section 1.1 (1968)

(1) 卷。I,基本算法,第 1.1 节(1968 年)

(2) The C Programming Language Pg 94-99

(2) C 程序设计语言 Pg 94-99

回答by Joe

It takes advantage of the fact that the terminator to the string (eventually found by that for loop) will be an ASCII NUL, which is a zero, which also happens to evaluate to false, thus terminating the for loop.

它利用了这样一个事实,即字符串的终止符(最终由 for 循环找到)将是一个 ASCII NUL,它是一个零,它也恰好计算为false,从而终止 for 循环。

It's worth noting the difference and similarity between 0, false, NULL and ASCII NUL. See this question: What is the difference between NULL, '\0' and 0

值得注意的是 0、false、NULL 和 ASCII NUL 之间的区别和相似之处。看到这个问题:NULL, '\0' 和 0 有什么区别

回答by Weather Vane

I have tried to satisfy the bounty awarder's desires which were mentioned at various times. To keep it simple I have restricted my answer to three sections of three lines each, and because (as The Bellmansaid in his Rule Of Three) "What I tell you three times is true"(the theme of this answer).

我试图满足在不同时间提到的赏金获得者的愿望。为了简单起见,我将我的答案限制在三个部分,每部分三行,并且因为(正如贝尔曼在他的三规则中所说)“我告诉你三遍是真的”(这个答案的主题)。

Technical

技术的

The truth of your forloop terminates it when the expression *pevaluates to 0and this evaluation is performed before every iteration of the loop, note that in C 0is false and anything else is true - that's a veryexpansive definition in other worlds!

for当表达式*p计算为时,循环的真实性将终止它,0并且在循环的每次迭代之前执行此评估,请注意,在 C 中0为假而其他任何为真 -在其他世界中这是一个非常广泛的定义!

The pointer variable pis initialised once, to point to the start of the array with p = str, and pis incremented at the end of every iteration, so *pis accessing successive elements of the array in each iteration.

指针变量p初始化一次,指向数组的开头p = str,并p在每次迭代结束时递增,因此*p在每次迭代中访问数组的连续元素。

The expression *pwill thus evaluate to 0(false) when the array element read by *pis the 0or '\0'terminator that signals the end of a C "string", but you can't see this zero in the initialisation of strbecause it is supplied by the compiler automatically.

*p因此,0当读取的数组元素*p是表示 C“字符串”结束的0or'\0'终止符时,表达式将评估为(false) ,但您在初始化中看不到这个零,str因为它是由编译器自动提供的.

Lyrical

抒情

Expressions of truth

Are not understood by youth

Read Ritchie and Knuth

真理的表达

不被年轻人理解

读 Ritchie 和 Knuth

Whimsical

异想天开

Jessica Alba is a fine actress who is very knowledgeable, having taken on board truths from observing the development of computer technology, as these quotes reveal:

杰西卡·阿尔巴 (Jessica Alba) 是一位知识渊博的优秀女演员,从观察计算机技术的发展中汲取了真理,正如这些引言所揭示的:

"Every five years I feel like I'm a completely different person."

"It's all about your product and how it performs. Either it works, or it doesn't."

“每五年我就觉得自己是一个完全不同的人。”

“这完全取决于您的产品及其性能。要么有效,要么无效。”

回答by chqrlie

A long time ago, in a PDP far, far away, resources were scarce, names got short: ifor index, pfor pointer would please early Jedi programmers.

很久以前,在一个很远很远的 PDP 中,资源稀缺,名称很短:i对于索引,p对于指针,早期的绝地程序员会很高兴。

Implicit tests told the truth in forcondition space. A single *was all they typed, trusting pand pushing it to the end of strings.

隐式测试在for条件空间中说出了真相。*他们只输入一个单曲,信任p并将它推到字符串的末尾。

To this day, they use the for(e = s;*e;e++)most familiar and elegant loop to defy the C++ empire and its cohorts of ctors, dtors and vile iterators. Bare bits and bytes against templates, exceptions and obscure types, only the brave still dare for C to fight, and uncast the void *.

直到今天,他们使用for(e = s;*e;e++)最熟悉和最优雅的循环来对抗 C++ 帝国及其 ctors、dtors 和邪恶的迭代器。针对模板、异常和晦涩类型的裸比特和字节,只有勇敢的人还敢与 C 抗争,并解开void *.

回答by synthetel

A haiku:

俳句:

##代码##

EDITED

已编辑

Here is some additional detail:

这里有一些额外的细节:

The second line of code of the "haiku" is equivalent to the first line. The original post asks "what does this mean" in a code-comment. The second line demonstrates the answer by equivalence. *pmeans p[0]. The second clause in the forloop cares about whether or not p[0] is equivalent to zero.

“俳句”的第二行代码相当于第一行。原始帖子在代码注释中询问“这是什么意思”。第二行通过等价证明了答案。 *p表示p[0]for循环中的第二个子句关心 p[0] 是否等于零。

The third line of code of the "haiku" is a line of code which can be used conceptually: You can think of the operation of the original line as behaving much like the third line ought to.

“俳句”的第三行代码是可以从概念上使用的一行代码:您可以认为原始行的操作与第三行应该的行为非常相似。