Are the “C mock tests” at tutorialspoint correct?

微笑、不失礼 提交于 2021-02-08 14:11:25

问题


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?


回答1:


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.




回答2:


I share many reservations about the code shown in the mock test #1 for C at TutorialsPoint. Using code that is not valid for C99, let alone C11 or C17, is weird. Code from the last millennium should not still be being taught to new programmers — except as object lessons in how the language has changed since it was first standardized.

This SO question originally discussed Q3 of the mock test, but the SO question and primary answer have since been amended to remove the commentary on that one question.

The code for Q3 is:

#include<stdio.h>

main() 
{ 
   char s[]="hello", t[]="hello";
   
   if(s==t){
       printf("eqaul strings");
    }
}

The arrays s and t must be at different locations; they are separate arrays, initialized by the same string, but still separate arrays and hence stored at separate addresses. The conditional compares the addresses at which the arrays are stored (string comparison would use strcmp() or equivalent), and the arrays are stored at separate addresses so the result of the comparison is false.

  • Consequently, the only correct answer is C — No Output.
  • This is the answer given by TutorialsPoint in their key.

There was some discussion on SO of string literals and the fact that they can be stored in the same location. However, that discussion was misguided; it doesn't apply to this code. The strings used to initialize the arrays may be colocated, but the arrays themselves cannot be colocated. However, suppose that the definitions were of pointers, not arrays:

char *s = "hello", *t = "hello";

Now it is quite possible that s and t contain the same address, though it is also possible that they contain different addresses. (The addresses of s and t must be different; they're two separate pointer variables).

But the array initializers in the code in the question must initialize two separate arrays, and those separate arrays must be stored at separate addresses, and hence the comparison s == t in the question must be false, so nothing is printed.



来源:https://stackoverflow.com/questions/62816217/are-the-c-mock-tests-at-tutorialspoint-correct

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!