Я оставлю это как ответ, поскольку Де Морган очень полезен для таких вопросов, как этот. Обсуждаемое преобразование, облегчающее просмотр проблемы в исходном коде:
(not A) or (not B) == not (A and B)
(str[i] != ' ') || (str[i] != '\0') <equivalent> !(str[i] == ' ' && str[i] == '\0')
Поскольку (A && B)
всегда будет ложным (str[i]
не может быть одновременно пробелом и терминатором), обратное , т.е. !(A && B)
всегда будет истинным, так что условие while никогда не оценивается как ложное, и вы получаете бесконечный цикл. Это легче увидеть с последним утверждением (отсюда и полезность Де Моргана).
Обратите также внимание, что исправленное утверждение (см. Ответ FaisalM) также можно реструктурировать, используя другое преобразование Де Моргана:
(not A) and (not B) == not (A or B)
(str[i] != ' ') && (str[i] != '\0') <equivalent> !(str[i] == ' ' || str[i] == '\0')
Это также делает (по крайней мере для меня) более легкую интерпретацию при чтении второй версии: это пробел, или, если это нулевой терминатор, сделайте его ложным с!, Убивает l oop.
Однако теперь вы должны оценить полное выражение внутри круглых скобок ... что может привести к некоторым потерям эффективности, см. Оценки короткого замыкания ... хотя я думаю, что компилятор обычно выполняет преобразование обратно в более эффективную версию автоматически .