Reputation: 70
I'm not exactly struggling with this exercise(holy crap, after 1-20 through 1-24...), but I am wondering if there is something wrong with my solution. The exercise asks you to write a loop equivalent to the following:
for (i=0; i<lim-1 && (c=getchar()) != '\n' && c!= EOF; ++i)
s[i] = c;
without the use of || or &&. I am choosing not to use any language features not introduced to me already, and I am taking seriously the idea that each exercise is placed where it is because the intent is for the user to use the supplied concepts. Thus, I came up with this:
for (i=0; (i<lim-1) == ((c=getchar()) != EOF) == (c != '\n'); ++i)
s[i] = c;
There's a much prettier solution involving a simple if/else if type conditional, but I wanted to make use of this section's talk about expressions having numerical values based on their truth or falseness and so on. The thing is, my solution isn't in any of the sites I normally check for valid exercise solutions, so even though it appears to work the same. I was wondering if there's anything wrong with the way I did it, other than it being ugly? Does the functionality differ in some way?
Upvotes: 0
Views: 1466
Reputation: 16540
// with the use of break statement and no else statements
for( i=0; i<(lim-1); ++i )
{
c = getchar();
if( '\n' == c ) break;
if( EOF == c ) break;
s[i] = c;
}
Upvotes: 0
Reputation: 241671
Aside from anything else, it is undefined behaviour because it depends on evaluation order. &&
and ||
definitely evaluate their left operands first, but ==
doesn't. So there is no guarantee that the second use of c
will refer to the new value rather than the value from the previous loop (or an unitialised value the first time.)
The short-circuit evaluation of &&
is an important part of the semantics of the original loop. The fact that &&
doesn't evaluate its second operand if its first operand is false means that the original loop is guaranteed to call getchar
no more than lim-1
times. Rewritten without &&
, getchar
will be called an additional time when i
reaches lim-1
, and the character read (if there was one) is then dropped into the bit bucket, which means that it will be missing from the next attempt to read input.
Finally, a == b
is not the same as a && b
. It works for (c != EOF) == (c != '\n')
because it is not possible for both of those conditions to be false -- which is an interesting observation -- but it is not a replacement for (i < lim-1) && ...
.
Upvotes: 1
Reputation:
Your code likely has undefined behavior. Compiling it under GCC and Clang gives me similar warnings:
test.cpp:14:31: warning: unsequenced modification and access to 'c'
[-Wunsequenced]
for (i=0; (i<lim-1) == ((c=getchar()) != EOF) == (c != '\n'); ++i)
Reading sequence points in c and c-faq question 3.8 I'm not convinced ==
is a sequence point, but &&
is. Secondly, I don't think your code does what you think it does. If we take the following example:
#include <stdio.h>
int main()
{
int lim = 512;
int a = 1;
char b = EOF;
char c = '\n';
if ((a < lim) == (b != EOF) == (c != '\n'))
{
printf("True.");
} else {
printf("False.");
}
}
It outputs "True." So it is in fact wrong. I recommend trying to avoid writing clever code and instead stick to the "if/else" solution that you alluded to.
while(i < lim-1) {
c = getchar();
if (c == '\n')
lim = 0; /* We haven't encountered breaks yet. */
else if (c == EOF)
lim = 0;
else
s[i++] = c;
}
Upvotes: 0