Search code examples
cc89

Are the "C mock tests" at tutorialspoint correct?


Since I've been coding C for well over 20 years, I think it was high time for me to take a test! To see if I've learnt anything at all, or if I'm just some fraud posting free but incorrect advice to beginners on the Internet.

This site (I'm not affiliated) offers free C tests. https://www.tutorialspoint.com/cprogramming/cprogramming_mock_test.htm.

I took test 1 and failed spectacularly with only 34 out of 50! Is this it? Do I have to give up my C programmer career? How good is this Tutorialspoint site and its tests?

Specifically, I failed to answer Q7, Q9, Q10, Q14, Q16, Q17, Q19, Q21, Q27, Q28, Q31, Q32, Q33, Q35, Q38, Q46 with the answer expected by the test. What are the correct answers to those questions?

Also, when I compile the questions on my conforming implementation C compiler (gcc -std=c11 -pedantic-errors) none of them will even pass compilation. Why is that? Am I and/or my compiler broken? Or is this site not very good at all?


Solution

  • This site is not very good at all.

    The questions are written for an old version of the C language which was withdrawn in the year 1999. It allowed you to write main as main() with no return type. This has not been valid C for over 20 years, so that's why it doesn't compile. You need to compile with -std=c90.

    Although in old C90 with implicit int before main(), the OS will use the return value of the function main(), so in case there is no return statement as in these examples, this means undefined behavior (C11 6.9.1/12).

    Notably, the whole test also suffers from the lack of \n in printf, which means that stdout is not flushed until the program ends. C guarantees that it is flushed upon program termination.

    Specifically, these questions are also incorrect:

    • Q7: None of the answers are likely correct. The operands 'A' and 255 are of type int, so the addition (assuming A=65) is guaranteed not to overflow but to result in 65 + 255 = 320. This resulting int is then converted through simple assignment to the type of c which is char. Which in turn may be a signed or unsigned type, depending on the compiler. This affects if the conversion is well-defined as per C11 6.3.1.3/2 or implementation-defined as per 6.3.1.3/3. One likely result is 320 = 140h, truncated: 40h = 64. This prints the character '@' on the gcc x86 compiler for Linux.

    • Q9: The code results in a compiler error since it's a constraint violation of the rules of simple assignment (references). They probably meant to write unsigned x = 5, *y=&x, *p = y+0; in which case the result is unspecified - there is no guarantee that the expression *y=&x is evaluated before the expression *p = y+0. See C11 6.7.9/23:

      The evaluations of the initialization list expressions are indeterminately sequenced with respect to one another and thus the order in which any side effects occur is unspecified.

      So the whole question is fundamentally wrong no matter how you put it.

    • Q10: A lot of style concerns might be raised regarding whether or not to cast the result of malloc. But apart from that, assuming #include <stdlib.h> is present, the code is ok. In case the include isn't present (as in the question), the code is broken and anything can happen.

    • Q14: It's an infinite loop that prints "Hello" infinitely. It does not print "Infinite loop".

    • Q16: See Q14. Also, a decent compiler (such as gcc -Wall) might have tossed some diagnostic messages here, so answering "compile error" isn't necessarily wrong. Depends on compiler settings.

    • Q17: Assuming 2's complement computer, then -2. Theoretically, it could print -1 or -2 or -(large number), depending on if the computer uses one's complement, two's complement or signed magnitude.

    • Q19: The correct answer is compiler error. Again because of the constraints for simple assignment.

    • Q21: assuming 65 is the symbol table value for 'A', then it can print either 'A' (little endian) or the symbol corresponding to 0 (big endian). The latter may very well look like "garbage".

    • Q27: The correct answer is invalid use of strcmp function, since #include <string.h> is missing. Otherwise it would print 0.

    • Q28: Compile error. Funny how inconsistent the test is. Here it suddenly doesn't allow implicit conversion from integer to pointers, which it merrily (and incorrectly) allowed earlier.

    • Q31: B or C or even D. It depends on the size of int, which is almost certainly either 2 or 4. The compiler is, however, free to add padding at the end of the union, so it might as well print a larger number.

    • Q32: The correct answer is indeed compiler dependent but... why oh why wasn't it compiler dependent in Q31 then?

    • Q33: C allows us to write either short, short int or int short - all equivalent, so the question doesn't make much sense.

    • Q35: There is no output since the code doesn't compile.

    • Q38: The output is 7, not 6.

    • Q46: Only the char member of the union has been assigned, the rest of it contains indeterminate values. The union member x is declared with automatic storage duration and never has its address taken, so it is undefined behavior to access it. https://stackoverflow.com/a/40674888/584518

      If not for that, it would have attempted to print some indeterminate value ("garbage") or even 65 or 0 depending on CPU endianess.