2013-04-09 3 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? –

+0

@JaynathanLeung Эта функция не была выполнена до меня, я просто копирую и прошёл. – dreamcrash

+0

Строка str заменяется триммером, так как trim является аргументом и выполняется перед printf. –

ответ

2

[Edit: удален предыдущий ответ, который @Nigel Харпер был хороший достаточно, чтобы быть вежливым, указывая на то, что это была полная бессмыслица.]

Аргументы printf (все аргументы) оцениваются в некотором неуказанном порядке до выполнения printf. Поэтому к моменту запуска printf оба значения str и (главное) trim(str, str1) были оценены.

Поскольку trim(str, str1) изменяет память, str точки на, к тому времени printf сама исполняющего память, на которую указывает str будут модифицированы, чтобы содержать bcd (и, очевидно, указатель, возвращаемый из trim(str, str1) будет также) ,

Следовательно, независимо от порядка, в котором оцениваются два аргумента, оба выхода будут bcd.

+0

Интересно, я думал, что аргумент printf будет сначала оценен, чем распечатать. – dreamcrash

+0

Я не думаю, что порядок оценки релевантен.Вся оценка - это значение указателя - оно не смотрит в строку, что происходит только в printf. Важно то, что отделка определенно будет вызываться первым, поэтому printf может видеть только измененное содержимое str, а не оригинал. –

+0

Я предпочел ответ после издания, так как он был похож на мой ответ во время теста :) – dreamcrash

1

Вы переписываете strr в функцию, которая является str в вашем вызове. Поскольку он передается по ссылке, это изменение возвращается обратно в вызывающую функцию. 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 

Если Вы добавляете -O2 порядок тот же, но функция go() становится встроенной.

Хммм ... Я кое-что узнал! Спасибо за это!

+0

Я просто изменяю порядок аргументов и то же самое происходит – dreamcrash

+0

Вы и Джефф прав! Порядок аргументов в стеке определен. Последнее выдвигается первым. Но порядок оценки аргументов не определен! Я изменяю свой ответ! – TrueY

+0

Np, спасибо за ответ. – dreamcrash

Смежные вопросы