2017-08-03 37 views
0

所以我在读从我的C语言编程过程中的一些代码,和对面这个问题问出来:修剪一个字符串,while循环之后为什么会有分号?


修剪字符串:" make trim ""make trim"。 这是代码:

#include <stdio.h> 
#include <string.h> 
#define MAX 100 

void trim(char *s) { 
    char *d = s; 
    while (isspace(*s++)) 
     ; 
    s--; 
    while (*d++ = *s++) 
     ; 
    d--; 
    while (isspace(*--d)) 
     *d = 0; 
} 
int main() { 
    char s[MAX]; 
    gets(s); 
    printf("[%s] -> ", s); 
    trim(s); 
    printf("[%s]", s); 
    return 0; 
} 

所以,我要问的是,什么是

while (isspace(*s++)) 
     ; 
    s--; 
    while (*d++ = *s++) 
     ; 
    d--; 
    while (isspace(*--d)) 
     *d = 0; 

递增串(*s++),该while()循环后;做的,又是如何工作?

在此先感谢

+0

只有';'在其他空行上是空的语句。除语法和语义上添加语句外,它什么都不做。 –

+1

如果您想知道它是如何工作的,请了解*指针*,*指针算术*以及如何使用*调试器*在监控变量及其值时逐行浏览代码。 –

+0

感谢您的建议。我目前正在为期末考试进行学习,这是2周后,如果您可以提供一些** C-String **问题汇编或一些很好的字符串(算法)书籍和评论一些链接? –

回答

4

空体很简单,因为while的条件有副作用,所以整个循环被封装在条件并没有什么放于身体。

所以:

while (isspace(*s++)) 
    ; 

是一样的:

while (isspace(*s)) { s++; } 

他们把分号上多余的线,更清楚地表明环路是空的(否则你可能会认为下一个真正的语句是循环的一部分)。其他人也可能在那里发表评论,甚至重写它以避免身体空虚。

代码的一些描述性注释:

这个循环拿起每个字符依次递增s指向未来,并继续这样做,直到我们拿起字符不是一个空白字符。请注意,因为它在测试之前递增,所以会增加s一次太多,所以这就是循环结束后递减的原因。 (isspace(* s)) ;

s--; 

这将是等效的,不需要单独的递减:

while (isspace(*s)) { s++; } 

这个循环副本从s每个字符所以从第一个非空白字符d最初指着字符串的开始。如果没有前导空格,它会直接在其本身上复制字符。循环在复制空字符(即字符串的结尾)后结束。由于之前有一个增量太多,所以我们必须递减d以空字符终点确定:

while (*d++ = *s++) 
     ; 
    d--; 

这个循环递减d然后拿起任何字符它指向的。如果它是空白字符,则用空字符替换它。请注意,没有检查字符串的开头,所以如果初始字符串是空的(即,一个空字符),它会高兴地向后弦外存储器损坏字节,只要它们是空白的工作:

while (isspace(*--d)) 
     *d = 0; 
+0

非常感谢。如果你不介意回答他们,我还想问另外两个问题。 首先,如果你可以解释它背后的逻辑,那么循环** while(isspace(* s ++)); **与** s - **一起工作,另外a.k.a如何修剪? 第二,如何做** while(* d ++ = * s ++); d - ; **和** while(isspace(* - d))* d = 0; **工作,如果您可以为我解构它们,我会很感激! –

+1

或者有时一个单独的'continue;'语句放在循环体中,以清楚地表明循环体什么都不做。 –

+0

是,或者至少是一个*空格*,例如'while(foo){}'(正如Andre在他的回答中所指出的那样)。至少原始问题在单独的一行中有分号,它太容易错过写作'while(foo);' –

1

可以重写:

while (condition); 

如下:

while (condition) { /* empty block */ } 

如果condition包含要执行的语句,只要条件满足,就会执行和评估这些语句,在您的示例中就是这种情况。


1. 你的情况第一while循环

while (isspace(*s++)); 

循环,直到它创立的第一个字符是没有空间(这是使在这案件)。因为有一个后缀增量将指向的使

" make trim \0" 
^ ^
d| s| 

2. 之后s递减(s--;)在启动(指着化妆)。

" make trim \0" 
^^
d| s| 

3. 的第二while循环写有开始做的字符缓冲区的开始,因为d指向由于一开始它被设置在函数开头的字符串(char *d = s;)。这样做,直到遇到空终止'\0'

while (*d++ = *s++) 

可以改写为:

while ((*d++ = *s++) != '\0') 

,并会导致(注意空结束也被写入'\0'):

"make trim \0 \0" 
      ^^
      d| s| 

4. 现在d将递减(d--;)指向空终止符'\0'之前的空格。

"make trim \0 \0" 
      ^^
      d| s| 

5。 的最后while循环将搜索的第一个字符是没有空间(与d),但以相反的顺序:

while (isspace(*--d)) 
    *d = 0; 

它将写入多个空终止'\0',直到它找到一个字符是没有空间。

"make trim\0\0\0\0 \0" 

所以得到的字符串将是:

"make trim" 

这是没有必要写多个空终止'\0'这里,而是一个空终止'\0'会后米被足够多的修剪

+1

非常感谢,答案是彻底的和超清晰的! :) –

+0

嗨@JustinHerchel如果这个或任何答案已解决您的问题,请点击复选标记,考虑[接受它](https://meta.stackexchange.com/q/5234/179419)。这向更广泛的社区表明,您已经找到了解决方案,并为答复者和您自己提供了一些声誉。没有义务这样做。 –

0
while (isspace(*s++)) 
     ; 

刚好等于

while (isspace(*s++)); 

不要让;在一个新行迷惑你。总而言之,这只是一种强调此while循环没有正文的方式。并且没有正文的while循环正在执行,直到它的isspace(*s++)条件为假。也是isspace(*s++)这是唯一应该为此循环完成的计算,所以这就是为什么不需要为此循环创建一个主体。

当你这样写代码很容易错过这个;然后你就可以做出一个错误的假设,即表达正下方的循环是一个循环体,只是不{}包围:

while (isspace(*s++)); 
    s--; 

while (isspace(*s++)) 
    s--; 

看到区别?在第二个示例中,s--是一个while循环的主体。为了吸引注意,程序员可以写:

while (isspace(*s++)) 
    ; 
    s--; 

澄清和强调他的真实意图。

相关问题