2012-12-15 4 views
0

Рассмотрим следующий код:Почему следующий код переходит в бесконечный цикл?

const char *s = "a b c d !"; 
const char *p = s; 

top:for(; *p; p++) { 
    switch(*p) { 
    case 0x20: 
    case '\n': 
     goto top; 
    default: 
     putchar(*p); 
    } 
} 

Может кто-то объяснить, почему он входит в бесконечный цикл вместо остановки, когда *p является NULL? Я имел в виду следующее: когда *p равно 0x20 или \n, перейдите к началу цикла снова, так как он проверяет условие и оценивает выражение p++. Таким образом, я не вижу причин для его бесконечного цикла, или я действительно не понимаю, как операторы goto и labels работают на языке программирования C.

+8

Обязательно: http://xkcd.com/292/ – Mysticial

+1

@Mysticial:? :-( – Jack

ответ

5

Когда вы goto top, p++ не выполняется, поскольку цикл for начинается с начала. Затем вы снова получите goto top. И снова. И снова. И навсегда.

Если вы хотите, чтобы ваш прирост работал, используйте continue вместо goto. Или, еще лучше, сделать что-то еще более ясное:

for(p = s; *p != '\0'; p++) { 
    switch(*p) { 
    case 0x20: 
    case '\n': 
     // Do nothing. 
     break; 

    default: 
     putchar(*p); 
    } 
} 

О, и кстати, во избежание goto заявления, как от чумы. Если вы не создаете C-код автоматическим способом, и он не должен быть читаемым человеком, goto практически никогда не будет хорошей идеей.

+0

Почему '' р ++ не выполняется и '* p' не слишком – Jack

+0

@Jack' * p' выполняется, только «p ++» пропускается, потому что конец цикла не достигнут. – dasblinkenlight

+1

@Jack Поскольку на первой итерации цикла for приращение-декремент никогда не выполняется, оно выполняется только после завершения первой итерации. вы 'goto' до места, которое находится перед циклом for, оно не может выполнить приращение. Вместо этого оператор for начинается снова * с самого начала *, выполняя другую * итерацию *. * –

1

сделать

const char *s = "a b c d !"; 
const char *p = s; 

for(; *p; p++) { 
    switch(*p) { 
    case 0x20: case '\n': continue; 
    default: putchar(*p); 
    } 
    } 

Причина заключается в том, что ваш код не завершает даже одной итерации и, следовательно, р ++ никогда не приходит к исполнению. Когда вы продолжаете использовать ярлык, он учитывает одну полную итерацию.

0
const char *s = "a b c d !"; 
const char *p = s; 

top: 
for(; *p; p++) { 
    switch(*p) { 
    case 0x20: 
    case '\n': 
     p ++; 
     goto top; 
    default: 
     putchar(*p); 
    } 
} 

Вы должны использовать p ++; перед тем goto top;, потому что собираетесь top: означает, что вы перезапуск цикла.

+1

Использование' goto' не является хорошей практикой, я использую 'goto', когда у меня есть для обработки условий ошибок. –

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