MeC*_*ris 40 c arrays string pointers for-loop
我不明白指针在for循环中的作用.什么是*p在下面的循环呢?
char str[128] = "Some Text";
char *p;
for (p = str; *p /*what does this mean?*/; p++)
{
// Code
}
Run Code Online (Sandbox Code Playgroud)
我确实了解其余的,但为什么不*p喜欢p > 3或类似的东西?
为什么一个人?
为什么这样写?
err*_*kos 53
在布尔上下文(例如for循环的条件)中,C中的每个表达式的计算结果为true(非零)或false(零).
您希望for循环在到达字符串末尾时终止.
在C中,每个字符串都以字符终止'\0',这实际上是0.因此,当for循环到达字符串的结尾时,*p求值为'\0',即0,哪个求值为false,从而终止for循环.
Man*_*dis 31
如果;语句中两者之间的任何内容为零(false),则for循环将终止.*p取消引用p并返回char,p指向.根据Dennis Ritchie的 说法,"C将字符串视为传统上由标记终止的字符数组".该标记是(ASCII)值为零的空字符.所以,这个for循环:
for (p = str; *p; p++)
Run Code Online (Sandbox Code Playgroud)
相当于这些
for (p = str; *p != '\0'; p++)
for (p = str; *p != 0; p++)
for (p = str; p[0] != '\0'; p++)
Run Code Online (Sandbox Code Playgroud)
空终止字符的另一个名称是sentinel或根据Donald Knuth "虚拟值"(Art of Computer Programming,第1卷).下面是str每个字符的字符串,索引(从起点开始的偏移量)和每个索引的值的图表:
为了完整性,在此处的注释请求之后是调试器在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
Run Code Online (Sandbox Code Playgroud)
p指向for循环开始的位置.t十六进制值0x74.之后你有字符串的空字符0x00.然后你会看到一些空字符,因为我在调试模式下构建并且编译器零初始化.通常你会看到垃圾(看似随机的值)我知道你现在正处于陡峭的学习曲线,用C指针,但最终你会说"IC点"
小智 19
这可以像这样重写
for (p = str; *p != '\0'; p++)
{
// Code
}
Run Code Online (Sandbox Code Playgroud)
在C中,字符串必须始终以空字符结尾,该字符与'\ 0'或0.相同.
hac*_*cks 14
在深入研究之前,我想在C中陈述关于表达的简单规则
当C需要的表达的布尔值,一个
false值是推断当表达式比较等于零,和一true值,否则.也就是说,无论什么时候写Run Code Online (Sandbox Code Playgroud)if(expr)
expr任何表达式都在哪里,编译器本质上就像它被写成一样Run Code Online (Sandbox Code Playgroud)if((expr) != 0)
现在回答你的问题:
什么是
*p在下面的循环呢?
在C中,字符串由空字符终止'\0'.
每个字符都有一个十进制等值.这'\0'是一个ASCII转义字符.十进制当量'\0'是0.
因此,*p循环中的表达式只是检查指向的内存地址处的字符的十进制等效p值是零还是非零.当p到达字符串的末尾并找到第一个'\0'字符时,表达式*p返回1一个零值.零表示false在C中.这相当于测试*p != '\0'或*p != 0如上所述.
这是它的工作原理:
1当*p然后评估的值*p是从存储器中取出.该值是表达式的值*p.
dhe*_*ein 13
或者正如D. Ritchie所说:让我们用汇编语言的力量和汇编语言的便利来做.
我将尝试通过参考ISO/IEC:9899(强调我的) - C99标准来解释所有必要的方面.(帖子风格的动机是唐纳德克努特的短语"科学是我们理解得足以向计算机解释的东西.艺术就是我们所做的一切.")
for-loop 究竟应该做什么!参考ISO/IEC:9899 6.8.5"迭代语句"
语义
4迭代语句导致一个称为循环体的语句重复执行,直到控制表达式比较等于0.
到目前为止我没想到任何新东西,所以让我们开始吧:
6.8.5.3 for语句
1声明
for ( clause-1 ; expression-2 ; expression-3 ) statement行为如下:表达式表达-2是控制表达式即每次执行之前计算循环体....
因此,我们现在知道// Code,只要预先评估的值*p不为零,就会执行正文(在您的情况下).
...表达式-3 在每次执行循环体后被计算为void表达式.[...]
所以现在我们知道,(我假设挖掘p++的定义不是必要的?!)对于每次迭代p递增,所以可能会有变化*p.
以下几点没有关系,但是我正在添加它,因为这使得语义部分for完整并且很好地知道它的原因,为什么for(;;)是inf循环.
2 (---)可以省略子句-1和表达式3.省略的表达式-2由非零常量替换.
好的,这是for循环在您的情况下所做的干燥但信息丰富的部分.
6.5.6加法运算符
约束
2另外,两个操作数都应具有算术类型,或者一个操作数应是指向对象类型的指针,另一个操作数应具有整数类型.(递增相当于添加1.)
因此,在您的情况下,您将1(整数)添加到"指向对象的指针"类型.
相当于通过其指向类型的sizeof增加地址,如tomislav kostic的图片中所示:
现在让我们看看*p实际做了什么.
6.5.3.2地址和间接运营商
约束
[...]
2一元*运算符的操作数应具有指针类型.
语义
[...]
4一元*运算符表示间接.如果操作数指向函数,则结果是函数指示符; 如果它指向一个对象,则结果是指定该对象的左值.如果操作数的类型为''指向类型'',则结果的类型为''type''.如果为指针分配了无效值,则unary*运算符的行为未定义.
这又有点干了1但为了更好地理解,这可以通过以下方式进行逆向工程:
6.5.2.1数组下标
[...]
语义
2后缀表达式后跟方括号[]中的表达式是数组对象元素的下标名称.下标运算符[]的定义是E1 [E2]与(*((E1)+(E2)))相同.
那么*((p)+(0))是什么(因为p+0是相同的p......很明显)等于p[0],没有别的任务作为评价p的对象.
而且因为我们知道,expression-2如果正在评估0,for循环正在中断迭代,我们可以说它是相同的p[0] != 0.
让我们看看C-Coder的朋友; JSSCA......不,等等......我们的朋友被叫了...... ASCII现在澄清了,我们可以弄清楚0它代表什么.
它是NULL标记,在C中指定字符串的结尾.
所有,这样做是:
迭代该循环的主体for,直到p实际指向地址,其中对象评估为"字符串结束"-token.
要么:
让我们p通过字符串直到到达结尾.
现在只是为了引用自己; 你永远不应该忘记的事情:(
强调我的......)
变量通过声明符(类型说明符)声明,该声明符位于标识符之前,该标识符命名可以计算其值的左值对象
它既不多也不少!
1 那就是我所承诺的!;)
诗意地说,我试图在循环中代表*p的挣扎:
勇敢的C*p(程序员)
在whilederness循环
NUL将阻止他们
这是一首ha句诗,它由三行组成,第一行和最后一行有5个音节,中间行有7个.另一个例子是@Samidamaru(海库诗人,见下面的评论):第一个p等于str,然后p递增,直到*p为NUL.
代码大使小时,杰西卡阿尔芭
按照Jessica(引用D. Knuth(1))的想象,我们将尝试在for循环中看到*p的含义:
for (p = str; *p; p++)
Run Code Online (Sandbox Code Playgroud)
为了达到这个目标,我们首先检查一元运算符 "*" 如何在C中工作:"一元运算符*是间接或引用运算符; 当应用于指针时,它访问指针指向的对象."(B. Kernighan和D. Ritchie(2))
所以*p只是p指向的值:
for循环由三个指令组成:
- p = str
- *p
- 的p ++
在1.我们将指向数组str的指针分配给p.在C中,以下分配具有相同的效果:
p = &str[0];
p = str;
Run Code Online (Sandbox Code Playgroud)
"根据定义,数组类型的变量或表达式的值是数组元素零的地址"(K&R(2)).此外,我们有"在评估a [i]时,C立即将其转换为*(a + i).....因此&a [i]和a + i是相同的"(K&R(2)).如果我们把i = 0,我们获得上述分配.
我们现在可以说,在for循环的开头,p指向str的第一个元素.
让我们转到第2点,这是你问题的核心.循环的第二个表达式控制退出条件:评估指令"*p",如果为false则循环退出.这意味着"*p"等同于"*p!= 0"或用词:当p指向的值为零时,退出.
现在,为了理解*p为零时我们记得数组str已经初始化如下:
char str[128] = "Some Text";
Run Code Online (Sandbox Code Playgroud)
和:"所有字符串常量都包含一个空终止字符(\ 0)作为它们的最后一个字符"(gnu-manual).所以实际存储在内存中的字符串最后有一个\ 0:"Some Text\0".
在第三条指令p ++中,指针p前进到str数组的下一个元素,因此,在第9次迭代时*p变为0(或者\ 0,NULL,NUL,请参阅@Joe的答案)和循环退出.
一张图片胜过千言万语,这里是循环的图形表示:
在下面的代码片段中, *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");
}
Run Code Online (Sandbox Code Playgroud)
参考
(1)卷.I,基本算法,第1.1节(1968)
(2)C编程语言第94-99页
它利用了这样一个事实:字符串的终止符(最终由 for 循环找到)将是 ASCII NUL,它是零,它也恰好计算为false,从而终止 for 循环。
值得注意的是 0、false、NULL 和 ASCII NUL 之间的区别和相似之处。看这个问题:NULL、'\0' 和 0 之间有什么区别
| 归档时间: |
|
| 查看次数: |
21809 次 |
| 最近记录: |