2013-04-09 47 views
1

背后的原因,我已经做了测试,其中就出现了这样的事情:这个输出

char* trim(char* strr, char* str1) { 
    char* s = strr; 
    while(*str1 == 32) str1++; 
    while((*str1 != 32) && (*str1 != 0)) 
     *s++ = *str1++; 
    *s = 0; 
    return strr; 
    } 

int main(void) { 
    char str[20] = "???"; 
    char str1[20] =" bcd \0"; 

    printf("(%s)\n(%s)\n", str, trim(str, str1)); 
    return(0); 
} 

的问题是:什么上面的代码将打印,为什么?我对输出结果和原因有了一些线索,但我希望听到更多有经验的人士的意见。

乍一看,它看起来像它会打印:

(???) 
(bcd) 

但在现实中产生的输出是:

(bcd) 
(bcd) 
+0

是不是你覆盖str? – 2013-04-09 23:50:27

+0

@JaynathanLeung这个功能没有完成,我只是复制和过去。 – dreamcrash 2013-04-09 23:51:44

+0

由于trim是一个参数并在printf之前运行,所以well str正在被修剪覆盖。 – 2013-04-09 23:52:40

回答

2

[编辑:删除以前的答案,这@Nigel哈珀是不错足够有礼貌地指出是完全无稽之谈。]

printf(所有参数)的参数在执行之前以某种未指定的顺序进行评估printf本身就开始了。因此,在printf开始执行时,str和(重要)trim(str, str1)都已被评估。

由于trim(str, str1)修改存储器str点,其本身正在执行时间printf,存储器指向由str将已被修改以包含bcd(显然,指针从trim(str, str1)返回的意志为好) 。

因此,无论评估两个参数的顺序如何,两个输出都将是bcd

+0

有趣的是,我认为printf参数将首先被评估,而不是打印出来。 – dreamcrash 2013-04-09 23:52:57

+0

我不认为评估顺序是相关的。所有评估都会产生指针值 - 它不会查看字符串,只发生在printf中。重要的是,trim一定会首先被调用,所以printf只能看到str的内容,而不是原来的。 – 2013-04-10 00:02:27

+0

我更喜欢这个版本后的答案,因为它与我在测试时的回答相似:) – dreamcrash 2013-04-10 00:11:27

1

您正在调用str函数中的strr。由于它是通过引用传递的,因此该更改会反映回调用函数。 printf将得到str的评估副本(两个参数都相同)。

0

最后一个参数是先评估,先推到堆栈。但评价论点的顺序并不明确。

我装箱一个简单的代码:

#include <stdio.h> 

char *go(char *s) { *s = '0'; return s; } 

int main() { 
    char str[] = "xyz", str1[] = "abc"; 
    printf("(%s)(%s)\n", str, go(str)); 
    printf("(%s)(%s)\n", go(str1), str1); 
} 

输出:

(0yz)(0yz) 
(0bc)(0bc) 

您可以分析这个gcc命令行汇编输出:

gcc -c -g -Wa,-a,-ad x.c >x.lst 

如果添加-02顺序相同,但go()函数变为内联。

嗯......我又学到了一些东西!谢谢!

+0

我只是改变了参数的顺序,并且发生了同样的情况 – dreamcrash 2013-04-09 23:57:21

+0

你和杰夫是对的!堆栈中参数的顺序是明确的。最后是先推。但评价论点的顺序并不明确!我修改我的答案! – TrueY 2013-04-10 07:59:51

+0

Np,谢谢你的回复。 – dreamcrash 2013-04-10 12:36:04