Yes, your check is correct, but, of course, it is not the most effective (if by "efficiency" you mean computational efficiency). The obvious intuitive inefficiency in your implementation is based on the fact that when the lines actually overlap, strlen calls will iterate over their common part twice.
A slightly different approach can be used for formal effectiveness.
int are_overlapping(const char *a, const char *b) { if (a > b) { const char *t = a; a = b; b = t; } while (a != b && *a != '\0') ++a; return a == b; }
An important note about this version is that it performs a relational comparison of two pointers that do not guarantee pointing to the same array, which formally leads to undefined behavior. He will work in practice in a system with a flat memory model, but may attract criticism from a reviewer of pedantic code. To get around this problem formally, you can convert pointers to uintptr_t before doing relational comparisons. Thus, undefined behavior is converted to behavior defined by the implementation, with the correct semantics for our purposes in most (if not all) traditional implementations with a flat memory model.
This approach is free from the “double counting” problem: it analyzes the non-overlapping part of the string that is “earlier” in memory. Of course, in practice, the benefits of this approach may not exist. This will depend on the quality of your strlen implementation as well as on the properties of the actual input.
For example, in this situation
const char *str = "Very very very long string, say 64K characters long......"; are_overlapped(str, str + 1);
my version will detect overlap much faster than yours. My version will do this in 1 iteration of the loop, while your version will spend 2 * 64K iterations (assuming a naive strlen implementation).
If you decide to dive into the area of questionable comparisons of pointers, the above idea can be redefined as
int are_overlapping(const char *a, const char *b) { if (a > b) { const char *t = a; a = b; b = t; } return b <= a + strlen(a); }
This implementation does not perform additional pointer comparisons at each iteration. The price we pay for this is that it always iterates to the end of one of the lines, rather than ending earlier. However, it is still more efficient than your implementation, as it only calls strlen once.