The logical operators expect their operands to be boolean values, and they perform "boolean algebra" on them. In programming, they are usually used with the comparison operators to express complex comparisons that involve more than one variable.
The && operator evaluates to true if and only if its first operand and its second operand are both true. If the first operand evaluates to false, then the result will be false, and && operator doesn't even bother to evaluate the second operand. This means that if the second operand has any side effects (such as those produced by the ++ operator) they might not occur. In general, it is best to avoid expressions like the following that combine side effects with the && operator:
(a == b) && (c++ < 10) // increment may or may not happen
The || operator evaluates to true if its first operand or its second operand (or both) are true. Like the && operator, the || operator doesn't evaluate its second operand when the result is determined by the first operand (i.e., if the first operand evaluates to true, then the result will be true regardless of the second operand, and so the second operand is not evaluated). This means that you should generally not use any expression with side effects as the second operand to this operator.
The ! operator is a unary operator; it is placed before a single operand. Its purpose is to invert the boolean value of its operand. For example, if the variable a has the value true, then !a has the value false. And if p && q evaluates to false, then !(p && q) evaluates to true.