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

Posted

技术标签:

【中文标题】C语言中带有指针的for循环【英文标题】:For loop with pointer in C 【发布时间】:2016-02-23 02:39:54 【问题描述】:

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

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

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

    // Code

我明白其余的,但为什么 *p 不像 p > 3 或类似的东西? 为什么是孤独的? 为什么会这样写?

【问题讨论】:

其实c string terminator作为搜索关键字更有帮助。 已省略比较。它是*p != 00 是字符串结束时 char 指针指向的值,因为它是字符串终止符。有关更多详细信息,请参阅this question,尤其是使用0 还是'\0' @FUZxxl *p*p != 0 取消引用 p... 所以它不是检查 NULL 指针,而是检查它是否指向零值。 这个赏金是为了创意还是你需要一些额外的信息? @艾克 @hacks 如果你能提供新信息,我会很惊讶!我认为奖金低于答案的教育价值,它们是肤浅的挑战,希望能防止答案变得过于简单或快速(也希望读/写有点乐趣——C标签有点沉闷最近)。如果您认为您可以提供新信息(例如:程序集故障、编译器设计观点、历史等等?)至少可以说,我真的会印象深刻。 【参考方案1】:

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

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

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

【讨论】:

非常感谢!解释得非常非常好。我真的很困惑,因为那里只有指针。 请注意,根据定义,字符串是零个或多个以空字节结尾的非空字节序列。 请注意,这个问题有 100 个代表的赏金。 请注意,对于 for 循环,没有任何评估结果为 false。看看我的回答,标准只是简单地说第二个表达式必须是标量类型,并且在其评估值为零时中断迭代。因此,即使使用 stdbool.h,评估为 0 的结果也是错误的,反之亦然;)【参考方案2】:

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

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

等价于这些

for (p = str; *p != '\0'; p++)
for (p = str; *p != 0; p++)
for (p = str; p[0] != '\0'; p++)

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

为了完整起见,在 cmets 发出请求后,调试器在 str 占用的内存块中看到:

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
    第一行的十六进制值是该内存块的地址(64 位)。这就是 p 在 for 循环开始时指向的位置。 在第二行,您可以看到字符串中字母的十六进制值。您可以看到一个 ASCII 表 here。字符串中的最后一个字符是t,十六进制值为0x74。之后你就有了字符串的空字符0x00。然后你会看到更多的空字符,因为我在调试模式下构建并且编译器零初始化。通常你会看到垃圾(看似随机的值) 在第 3 行,我添加了您的字符串的字符以供参考

我知道您目前正处于急速学习曲线中,但最终您将能够说“I C the point”

【讨论】:

这个答案有很大的潜力,但我觉得它缺少一张图片,一个来自 Knuth 的引述,一个来自 Ritchie,一个来自你自己(斜体)。那肯定会得到我的赏金,因为你已经有一顶很酷的帽子了。 *p != NULL 不等同于其他人。 NULL可以定义为(void *)0,表示这是integerpointer的比较。这种比较需要强制转换,除非整数是 null 指针常量,而 *p 不是(即使它恰好持有值 0)。请参阅 C11 6.5.9/2 以供参考(早期版本的 C 有类似的规则)。 图解文字*p = NULL不正确;这应该是 *p = 0*p = '\0' @M.M 你是对的。我错误地记得看到它是这样使用的,但实际上它是NUL(非标准)。 @Ike:如果 ManisNikolaidis 添加带有十六进制转储的第三行会更好,以说明字符如何在内存中编码以及空字符如何拼写为 '\0' 并编码为 @ 987654348@ 终止字符串。【参考方案3】:

在深入研究之前,我想在 C 中声明一个关于 expression 的简单规则

当 C 需要 表达式的布尔值 时,当表达式比较等于 时推断出 false 值,否则推断出 true 值。也就是说,每当一个人写

if(expr)

如果expr 是任何表达式,编译器本质上就好像它被写成

if((expr) != 0)  

现在来回答你的问题:

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

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

每个字符都有一个十进制等值。这个'\0' 是一个ASCII escape character。 '\0' 的十进制等效值为 0

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

它是这样工作的:


1*p 求值时,从内存中获取*p 的值。这个值就是表达式*p的值。

【讨论】:

@Ike;是的当然。事实上,我这几天都在卧床休息,所以有足够的时间。为这个 gif 创建了 36 张图片 :) 我觉得我必须为这个答案再做一次赏金——因为我认为它具有我所见过的最具教育意义的价值。 @Ike;感谢您的赞赏。我很高兴你真的喜欢它。 投我所有的赞成票!我在我生命中的短暂时期(90 年代后期)教过 CS 101/102,所以我认为这是教人们的最有效方法之一(一直希望我能在白板上画动画)。这不太符合我目前的赏金请求,但我想我会为此再做一个,以获得最具教育意义的答案。我一直想做更多这样的视觉答案来解释主题,但总是太懒了。 哇!现在我觉得我必须让杰西卡说话:P【参考方案4】:

可以这样改写

for (p = str; *p != '\0'; p++)

    // Code

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

【讨论】:

虽然我的赏金鼓励使用标题和内容非常详细的问题,以便他们可以教育广泛的人并给他们更多的东西来查找,但这个答案非常好......简短而甜美的,值得注意的是它的简洁。我唯一的抱怨是它可以很快提供。但这是一个绝妙的答案——太棒了!【参考方案5】:

让我们干脆深入地分析一下吧!

或者正如 D. Ritchie 所说:让我们使用the power of assembly language and the convenience of … assembly language.


我将尝试通过参考 ISO/IEC:9899(重点是我的)- C99 标准来解释所有必要的方面。 (帖子风格的灵感来自于 Donald Knuth 的一句话“科学是我们理解得足以向计算机解释的东西。艺术是我们所做的一切。”

首先,让我们看看for-loop 到底应该做什么!

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

语义

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

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

6.8.5.3 for 语句

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

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

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

...表达式 expression-3 被评估为一个空表达式在循环体的每次执行之后。[...]

所以现在我们知道,(我假设没有必要挖掘 p++ 的定义?!)每次迭代 p 都会增加,所以 *p 可能会发生变化。

以下几点不相关,但我添加它是因为这使得 for 的语义部分完整并且众所周知,因为它的原因是,为什么 for(;;) 是一个 inf 循环。

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

好的,这是 for 循环在您的案例中所做的枯燥但信息丰富的部分。

现在让我们回到指针算法:

6.5.6 加法运算符

约束

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

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

相当于将地址增加了其指向类型的大小,如tomislav kostic的这张图片所示:

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

6.5.3.2 地址和间接运算符

约束

[...]

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

语义

[...]

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

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

6.5.2.1 数组下标

[...]

语义

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

所以*((p)+(0)) 是什么(因为p+0p 相同...很明显)等于p[0],在评估p 的对象时没有做任何其他事情。

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

现在是最后一步

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

C 中的 NULL 标记表示字符串的结尾。


如此确凿:

所有,这样做是:

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

或者:

p 遍历字符串直到到达结尾。


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

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

不多也不少!


1就是我答应的! ;)

【讨论】:

这太棒了!我觉得它是新赏金的有力候选人。但我感觉有点像是在读 Spock 的回答。我希望看到更多幽默,关于这个主题的个人观点,哲学或一些诗歌(也许是俳句或这个主题)。想想丑陋的鱼书。我真的觉得这个答案对于这个新的赏金有很大的潜力——也可以使用一些标题和/或项目符号。如果你能以某种方式引用杰西卡阿尔芭,那就太完美了(尽管是可选的)。 @Ike:我会尽我所能。但我有点幽默感,所以我可能会遇到麻烦。但也许我可以根据事实本身做出一些事情。 '^.^ @Ike 现在,我将我的 Profilpicture 改成了专为您设计的石头,因此是一个完美贴合的头部。这不是很棒吗?:D @Ike:到目前为止已经完成。我自己的引用即将到来。只是在寻找我真正经常表达的关于 C 的东西,我希望我能找到一个包含它的高票帖子以供参考:P ... 需要简单、常规的答案,即使是基本问题也可以解决很多人不知道的复杂主题和领域,如果我们想像您一样从技术上走得更远,或者像其他人认为的那样有趣——有时有趣是一个先决条件,至少对一些学生来说,是为了帮助他们学习科目而不感到无聊。那里有各种各样的学习风格——从视觉到数学到非常技术和文字——很多人从不同的风格中受益。我希望这些答案的多样性可以向未来的读者展示这一点。【参考方案6】:

*p俳句

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

勇敢的 C *p(rogrammers)

在whilederness的循环中

NUL 会阻止他们

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


一点点流行音乐

Hour of Code ambassador,杰西卡·阿尔芭


*p 在循环中做了什么?

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

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

为了这个目标,我们首先检查一元运算符“*”在 C 中是如何工作的: “一元运算符 * 是间接或延迟运算符;当应用于指针时,它访问指针指向的对象。” (B. Kernighan 和 D. Ritchie (2))

所以 *p 就是 p 所指向的值

1.1 仔细观察 for 循环

for循环由三个指令组成:

    p = str *p p++

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

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

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

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

1.2 问题的核心

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

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

char str[128] = "Some Text";

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

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

1.3 眼见为实

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

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

在下面的 sn-p *p 中使用相同的方式,但在一个while循环中:

#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 == '\0'
    while(*p) 
        printf("%c", *p);
        p++;
    
    printf("\n");


愿for(;*C;)e与你同在!


参考文献

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

(2) C 编程语言 Pg 94-99

【讨论】:

天啊,这是一个很棒的答案,它实际上有一张 嵌入 Jessica Alba 的照片!太棒了!我不知道现在该怎么办——你和 Zaibis 之间正在进行一场激烈的竞争!我觉得您的回答更适合问题的初学者水平,但 Zaibus 具有绝对的技术精度。不管怎样,无论发生什么,你们俩都是我眼中的赢家! @Ike wow,感谢您的评论,尤其是这款有趣的游戏。我真的很喜欢自己回答。我更新了我的答案,希望你会更喜欢它。 @terencehill 有一个新的奖金挑战更高的赏金可以让你的答案成为超级主导优势(尽管它在大多数情况下已经有了这个)——它是在主语,5-7-5 音节形式(不严格遵守俳句的音节形式)——只是这样格式化。 我认为如果for(;C;) 真棒笑话是for(;*C;) 来调整它来解决这个问题,你的答案(除了俳句)部分可能会更棒,尽管这取决于你——无论哪种方式的道具。可能有帮助的一件事是在 while 循环代码版本中添加注释,尤其是在 while(*p) 部分周围。 @Ike & terence hill,如果你想使用它,我会接受参考和每周向我的贝宝账户付款:MasterHaikuPoet@paypal.com【参考方案7】:

很久以前,在一个很远很远的 PDP 中,资源稀缺,名字很短:i 表示索引,p 表示指针,这会取悦早期的绝地程序员

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

直到今天,他们仍使用for(e = s;*e;e++) 最熟悉和优雅的循环来挑战 C++ 帝国及其由 ctors、dtors 和卑鄙的迭代器组成的群体。对模板、异常和晦涩类型的裸比特和字节,只有勇敢的人还敢为 C 战斗,并取消void *

【讨论】:

我的天啊,我从反叛的一方对此投了赞成票(认为我不应该)——作为 C 和 C++ 开发人员,但欣赏 C 美学很多极简主义的优雅。这是一个有趣的风格角度 - 其大胆的性质的道具。 这个答案的绝对(和伟大)大胆让我感到恐惧——我觉得有必要对可能愤怒的 C++ 开发人员进行保护。对于那些观看的人来说,请记住,这为这个问题提供了一个完全独特的美学角度,经验导致我们在美学上产生分歧,甚至通过我们使用的语言的选择。这是一种惯用的 C 美学。而且,归根结底,唯一重要的是结果——看看 Linus Torvalds,他鄙视 C++,尽管如此,我们无法与他取得的辉煌成就争论。 我会跟着你穿过黑暗的 C++,我们会打败模板到 C *。 我也很有趣 +1。但是请记住,即使这是一个好主意,请记住,这仍然是其主题和主题之外的。我很难在其中看到真正的答案。 :// @Zaibis 同意——尽管我不清楚答案中的主观泄漏是否值得将其视为 OT。我认为 POB 问题是 OT 的原因是试图劝阻答案中过多的主观性(不要用铁锤直接避免它们,因为我们大多数人在那里回答任何问题都会遇到很大困难,尽管您可能可以完美地做到这一点!)。但是,如果一个答案无论如何都选择这样做,我认为它处于灰色地带,这使其更多地参与投票而不是标记领土。哦,好吧,这可能就像一个元主题! :-D 但就目前而言,我认为这个答案很有趣!【参考方案8】:

它利用了字符串的终止符(最终由 for 循环找到)将是一个 ASCII NUL,它是一个零,它也恰好评估为 false ,从而终止 for 循环。

值得注意的是0、false、NULL和ASCII NUL的区别和相似之处。看到这个问题:What is the difference between NULL, '\0' and 0

【讨论】:

没问题。实际上并没有太大区别,但值得注意的是,这是人们遇到的一段历史,尤其是像 OP 显示的讨厌的代码。 在布尔上下文中使用*p 不是糟糕的代码,它是所有 C 程序员都熟悉的标准习语。 @user4815162342 @Joe 也许建议做一个糟糕的风格是一个冒险的领域。我个人从来没有在这种情况下使用过它,因为我不确定我能否以最广泛的可移植性假设'\0' == 0。但那些肯定知道这一点的人,或者如果语言标准能保证这一点,可能会很好地使用这种速记。 我同意它是惯用的 C,但我不同意它是好的代码。习语并没有使它更可靠、更可维护、更快或更少耦合。当然它应该被理解,但我不确定它应该被永久化。 一般认为,将'\0'NULL等终止符视为假值,则代码为more readable。它不仅是惯用的 C 和 C++,而且得到 The C Programming Language 中的语言作者的认可。此外,“逻辑真理”继续出现在 C 之后创建的主流语言中,例如 Python、Perl、Ruby 或 javascript。虽然质疑任何特定的编码风格并非不合理,但鉴于现有实践的数量,在这种情况下,举证责任在于提问者。【参考方案9】:

我已经尝试满足赏金者多次提到的愿望。为了简单起见,我将我的答案限制在三个部分,每部分三行,并且因为(正如 The Bellman 在他的三规则中所说)“我告诉你的三遍是真的”(这个答案的主题)。

技术

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

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

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

抒情

真实的表达

年轻人不懂

阅读里奇和高德纳

异想天开

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

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

“一切都与您的产品及其性能有关。要么有效,要么 它没有。”

【讨论】:

所以*p 在每次迭代中都指向数组的连续元素。:我想你的意思是说p,不是吗? @hacks 我和自己争论过使用哪个,我把*p 放在这句话中,因为*p 指的是数组元素的值,而不是它的地址。很难说 perhpas?我会在一分钟内编辑它。 是的。 *p 代表的是连续的元素。 @hacks 谢谢,我做了一个稍微不同的编辑,所以它仍然是我的工作;) +1 歌词!做得好。可以考虑加入我们俳句大师的圈子吗?我也喜欢我亲爱的朋友杰西卡的引文。【参考方案10】:

俳句:

WHY   for (p=str; *p;        p++)
IS    for (p=str; p[0] != 0; p++)
THINK for (i=0;   str[i];    ++i)

已编辑

这里有一些额外的细节:

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

“haiku”的第三行代码是可以在概念上使用的代码行:您可以将原始行的操作视为与第三行应有的行为非常相似。

【讨论】:

【参考方案11】:

从图片中可以看出,for 循环以*p 开头,其中p 指向str。此时*p 拥有S

当不断循环for时,最终到达str[9],其中'\0'表示NULL

此时for (p = str; *p; p++) 中的条件语句*p 等于NULL,因此代码将中断for 循环。

【讨论】:

-1。抱歉,NULL 不是空字符,'\0' 是。 *p != NULL 将无法在大多数 C 环境中编译,因为 NULL 是空指针,因此通常定义为 ((void*)0)。 C++ 将NULL 定义为0,因此可以写出*p != NULL 这样令人困惑的恐怖。不要这样做。 我的意思是 NULL 在这里是 ascii NUL (0) 字符。很抱歉混淆了NUL 字符和NULL 指针。【参考方案12】:

这是循环的条件部分。 如果不满足该条件,则不再执行循环。*p 取消引用指针 p 并返回字符串 str 中指向的字符。 C 风格的字符串 str 以值 \0 结束。 循环遍历每个字符(使用p)直到条件不满足。

在 C 中,0\0 的值类似于false 的含义,即不满足条件。 其他任何值都类似于true的含义,即满足条件。

简而言之,p 遍历str 中的每个字符,并在遇到字符串终止字符\0 时立即停止。

为什么不使用p 而不是*p 因为p 是一个指针并且包含一个地址。有时很难甚至不可能只使用地址算术。这不是一个好的做法,而且会使代码难以阅读。*p 是取消引用的指针,包含p 指向的值。在这种情况下,很容易使用p 指向的值,因为您知道字符串以\0 结尾。作为条件(ifwhile 等)*p 等价于*p != '\0'

【讨论】:

【参考方案13】:

首先你需要掌握一个指针的概念,就像名字说他们指向的东西一样。 指针包含变量的地址。

    int var=0;
    int *p;
    int p=&var;

在此代码中,p 是一个指针,printf("%d",p); 打印变量 var 的地址,printf("%d",*p); 打印变量 var 的值,在此示例中为 0。

其次,您必须了解数组的工作原理。数组是一种数据结构,可以存储相同类型元素的固定大小SEQUENTIAL集合。

        int array[3]=9,8,7;
        printf("%d",array[0]); //prints what is on 1st position,9
        printf("%d",array[1]); //prints what is on 2nd position,8
        printf("%d",array[2]); //prints what is on 3rd position,7

operator [] 只是用户友好的数组工作。 最后三行代码可以替换为以下几行(它们的作用相同):

        printf("%d",*(array+0)); //prints what is on 1st position,9 
        printf("%d",*(array+1)); //prints what is on 2nd position,8
        printf("%d",*(array+2)); //prints what is on 3rd position,7

array 是指向数组第一个元素的指针(包含数组中第一个元素的地址),因此取消引用它我们得到第一个元素的值,例如*array。 我们知道数组是 seqential 这意味着 array+1 指向数组的第二个元素,因此取消引用它可以获得第二个元素的值,例如*(array+1),等等。

同样适用于字符串,因为它们是 char 数组,除了字符串末尾有 '\0'(空字符)。

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

    for (p = str; *p; p++)
    
        printf("%c",*p);
    

这个程序打印字符串str

p = str //将字符串str的第一个字符的地址分配给p,我们不会丢失字符串中第一个字符的轨迹,所以我们使用p而不是str迭代

*p //这个表达式的意思是*p!=0 所以这是真的,直到你到达字符串的末尾,记住ascii中的'0'的整数值是48

p++ //在 for 块的末尾你将 +1 加到p 以获得下一个字符的地址

【讨论】:

【参考方案14】:

可以这样解释:

for( initialization ; Conditional Expression ; expression3)

    Code here will execute while 2nd Expression(Conditional Expression) is true
    true means non-zero value
    '\0' is equivelant to 0,so when *p equal '\0' : loop will terminate

【讨论】:

绝对错误!您对 for 循环的描述完全不正确。这是它通常使用的方式。但是您只是在以某种方式对其进行简单化,这只是排除了它的主要特征,而且无论如何,就您使用的表达而言,措辞本身是模糊的。 @Zaibis & machine_1:请记住,尽管这绝对是初学者级别的讨论(尽管 Zaibis 的帖子甚至可能教给专业人士一两件事)。我们倾向于简化很多,例如在教孩子如何出生时。对于machine_1,避免因过度简化而陷入麻烦的一个好方法可能是确定这是操作员发布的代码在此上下文中从人类的角度逻辑上的含义,而不是for 循环通常如何工作的技术故障。 @Ike:一般来说,我对简单化没有任何问题,我什至可以接受称为初始化的第一个表达式。但是第三次​​降级为“增量”的蜜蜂根本不正确! @Zabis ,并且仅针对那一段代码)。所以我对machine_1 的建议是编辑并做出限定,这是描述代码的作用,而不是一般的for 循环。这会让你可以接受,不是吗?

以上是关于C语言中带有指针的for循环的主要内容,如果未能解决你的问题,请参考以下文章

c语言一个死循环中为啥执行完一个功能函数就退出了?

C语言怎么用for循环为二维数组赋值?请举个例子。

带有指针值的 Go 通道在 for 循环中的行为不符合预期[重复]

C语言中for循环怎么理解?

C语言中for的双循环怎么用

Django 模板语言:使用带有 else 的 for 循环