Two Cs on the Same Paper

Somewhere in your future there is an exam paper, and on it there is C code that this course's compiler rejects. That is not a contradiction to hide from; it is the last thing this course has to teach. Most university C material in India descends from Turbo C, a Borland compiler for 16-bit MS-DOS released in 1987 and frozen shortly after — before the ANSI standard settled, before its library conventions won. The papers copied from those textbooks still carry its fingerprints: void main, conio.h, gets, "int is 2 bytes", and output questions whose answers were only ever true on that one compiler.

You have spent fifteen chapters writing strict ANSI C89, which is the standard core those exams believe they are testing. This lesson names each Turbo C idiom, states what the standard actually says, and gives you the strategy: write the standard-correct form by default, recognize the old form on sight, and know exactly why it is wrong — so you can score on the paper without carrying its errors into your own programs.

void main()

The exam form, everywhere in old textbooks:

void main()
{
    printf("Hello\n");
}

The C standard says otherwise: in a hosted implementation — a normal program running under an operating system — main returns int, either as int main(void) or as int main(int argc, char *argv[]). The return value is the program's exit status, the same status chapter 12's file programs used to report failure. A void main is at best a nonstandard form some compilers tolerate; the standard gives it no meaning. Turbo C accepted it because DOS barely looked at exit statuses and Borland never insisted; a generation of textbooks copied the habit from each other.

This course's compiler does not tolerate it. The exam form above fails under gcc -std=c89 -pedantic-errors:

error: return type of 'main' is not 'int' [-Wmain]
    3 | void main()
      |      ^~~~

On paper, always write int main(void) and end with return 0; — no examiner has ever deducted marks for the standard form. The explicit return 0; matters in C89: reaching the closing brace of main without returning hands the host an indeterminate status. (C99 later added an implicit return 0; for main — a beyond-C89 fact worth knowing, not relying on.)

#include <conio.h>, clrscr(), getch()

The exam form:

#include <conio.h>

clrscr();      /* clear the screen */
getch();       /* wait for any key */

conio.h is not part of C. It is a Borland library header — "console I/O" — that shipped with Turbo C, and clrscr and getch are its functions, not the language's. Feed it to this course's compiler and the failure is immediate:

fatal error: conio.h: No such file or directory
    2 | #include <conio.h>
      |          ^~~~~~~~~
compilation terminated.

Standard C has nothing for clrscr, because the language does not know it is talking to a screen — chapter 12 taught that all I/O is streams, and a stream might be a file or a pipe with no screen to clear. For getch()'s usual job, the "press any key" pause before Turbo C's output window vanished, the portable equivalent is chapter 4's getchar() — it waits for Enter rather than any key, and it needs no vanishing window because your programs do not run in one. On an exam that asks for clrscr() in a Turbo C context, write it and move on; in any program you compile, leave conio.h out and know it is the one include line that marks code as unportable on sight.

gets()

The exam form:

char name[20];
gets(name);

Chapter 8 gave gets its obituary: it reads a line with no way to state the buffer's size, so a 25-character line into name[20] writes past the end of the array — a buffer overrun, which is undefined behaviour, and one that this platform's AddressSanitizer turns into a hard failure. The flaw is not misuse; the function's interface makes safe use impossible. Even the toolchain protests — link a program calling gets here and you get:

warning: the `gets' function is dangerous and should not be used.

The standards committee eventually agreed: C11 removed gets from the library entirely, the only function ever expelled from C — a beyond-C89 fact, but the best one-line answer to "why shouldn't I use gets?" ever written. The replacement is the course's standard line reader, with the trim that chapter 8 drilled:

char name[20];
int i = 0;

if (fgets(name, 20, stdin) == NULL) {
    return 1;
}
while (name[i] != '\0') {
    if (name[i] == '\n') {
        name[i] = '\0';
    }
    i++;
}

If an exam question uses gets, answer in its world — but if the question is "compare gets and fgets", that is free marks: no size parameter, unpreventable overrun, removed from the standard, replaced by fgets plus newline trim.

"int Is 2 Bytes"

Every Turbo C textbook states flatly that int occupies 2 bytes and holds -32768 to 32767. Here is the same question put to this platform:

sizeof(char)  = 1
sizeof(int)   = 4
sizeof(long)  = 8
INT_MIN = -2147483648
INT_MAX = 2147483647

Neither book nor platform is lying; they are describing different machines. The size of int is implementation-defined: the standard lets each compiler choose and document it, guaranteeing only minimum ranges — int must span at least -32767 to 32767 (at least 16 bits), long at least ±2147483647. Turbo C targeted a 16-bit processor, so its int was 2 bytes and the textbook ranges were true for it. This platform is 64-bit: int is 4 bytes, long is 8. The only size the standard fixes outright is sizeof(char), which is 1 by definition, everywhere, forever — which is why chapter 3 told you to write sizeof rather than a number, and why that habit is the whole answer here.

So when a paper asks "what is the range of int?", answer with the assumption stated: on a 16-bit compiler such as Turbo C, int is 2 bytes, range -32768 to 32767; the size is implementation-defined, and on modern 32- and 64-bit systems int is typically 4 bytes. The first clause earns the expected marks; the second shows you understand the question better than the paper does.

Predict the Output

The most notorious exam genre. The classic:

int i = 5;
i = i++ + ++i;
printf("%d\n", i);

and its sibling printf("%d %d\n", i++, i++);. Answer keys treat these as evaluation-order puzzles with one right number. Chapter 3 taught the truth: modifying i twice with no sequence point between the modifications is undefined behaviour. Not "tricky", not "compiler-dependent" — the program has no defined meaning at all, and the standard permits any result. The compiler here says so out loud:

warning: operation on 'i' may be undefined [-Wsequence-point]
    7 |     i = i++ + ++i;
      |     ~~^~~~~~~~~~~

Run under this platform's gcc, that program happened to print 12; Turbo C-era answer keys usually say 13; another compiler may produce something else, and all of them are "right", which is exactly what undefined means. The second form printed 5 6 here, while the Turbo C tradition — which evaluated arguments right to left — expects 6 5. A question whose answer changes with the compiler is not testing C; it is testing archaeology.

Strategy, with your eyes open. If the paper forces a single number, know the Turbo C conventions its key was built on: arguments evaluated right to left, side effects applied eagerly. But where the format allows a sentence, write "this is undefined behaviouri is modified twice without an intervening sequence point, so the standard imposes no requirement on the result" and be ready to defend it. That answer is the correct one, modern examiners increasingly accept it, and it is the version of you that chapter 3 was building.

The Same Language Underneath

Do not leave this lesson thinking exam C and modern C are enemies. Strip away the five idioms above and what old papers test is precisely what you have been writing all course: declarations at the top of the block, /* */ comments, printf and scanf, arrays, pointers, structures, files — that is C89, and it compiles unchanged on Turbo C and on this platform's gcc. The discipline this course enforced is not a modern layer on top of exam C; it is the standard core the exams were always trying to teach, minus one dead compiler's habits. Write the standard form, recognize the old form, and you can walk into both worlds without translating.

Key Takeaways

  • main returns int in standard C — int main(void) plus an explicit return 0; (C89 gives an indeterminate exit status if main ends without one); void main is a nonstandard Turbo C habit, rejected by this course's compiler.
  • conio.h, clrscr(), and getch() are Borland library extensions, not C; standard C has no screen-clearing and uses getchar() where exams use getch(), and the include fails here with "No such file or directory".
  • gets cannot state a buffer size, so overrun — undefined behaviour — is unpreventable; C11 removed it from the library, and the replacement is fgets plus the newline trim.
  • sizeof(int) is implementation-defined: 2 bytes on 16-bit Turbo C, 4 here; the standard guarantees only minimum ranges (int at least ±32767) and fixes only sizeof(char) as 1 — so answer range questions with the assumption stated.
  • i = i++ + ++i; and printf("%d %d", i++, i++) modify an object twice between sequence points: undefined behaviour with no correct output, warned as -Wsequence-point here; give the paper's expected Turbo C answer only if forced, and know how to defend "undefined behaviour" as the honest one.
  • Exam C minus its five Turbo C idioms is exactly the C89 this course taught; the standard-correct form is always safe to write on paper.