Saturday, April 5, 2008

C language technical interview questions - 13

C Technical Interview Question Set: Checking Program correct or not, find error program and technical interview questions
Stdio . h

1. What's wrong with this code?
char c;
while((c = getchar()) != EOF) ...
A: For one thing, the variable to hold getchar's return value must be an int. getchar() can return all possible character values, as well as EOF. By squeezing getchar's return value into a char, either a normal character might be misinterpreted as EOF, or the EOF might be altered (particularly if type char is unsigned) and so never seen.

2. Why does the code
while(!feof(infp)) {
fgets(buf, MAXLINE, infp);
fputs(buf, outfp);
}
copy the last line twice?
A: In C, end-of-file is only indicated *after* an input routine has tried to read, and failed. (In other words, C's I/O is not like Pascal's.) Usually, you should just check the return value of the input routine (in this case, fgets() will return NULL on end- of-file); often, you don't need to use feof() at all.

3. My program's prompts and intermediate output don't always show up on the screen, especially when I pipe the output through another program.
A: It's best to use an explicit fflush(stdout) whenever output should definitely be visible (and especially if the text does not end with \n). Several mechanisms attempt to perform the fflush() for you, at the "right time," but they tend to apply only when stdout is an interactive terminal.

4. How can I print a '%' character in a printf format string? I tried \%, but it didn't work.
A: Simply double the percent sign: %% .
\% can't work, because the backslash \ is the *compiler's* escape character, while here our problem is that the % is essentially printf's escape character.

5. Someone told me it was wrong to use %lf with printf(). How can printf() use %f for type double, if scanf() requires %lf?
A: It's true that printf's %f specifier works with both float and double arguments. Due to the "default argument promotions" (which apply in variable-length argument lists such as printf's, whether or not prototypes are in scope), values of type float are promoted to double, and printf() therefore sees only doubles. (printf() does accept %Lf, for long double.)

6. What printf format should I use for a typedef like size_t when I don't know whether it's long or some other type?
A: Use a cast to convert the value to a known, conservatively- sized type, then use the printf format matching that type. For example, to print the size of a type, you might use
printf("%lu", (unsigned long)sizeof(thetype));

7. How can I implement a variable field width with printf? That is, instead of %8d, I want the width to be specified at run time.
A: printf("%*d", width, x) will do just what you want.

8. How can I print numbers with commas separating the thousands? What about currency formatted numbers?
A: The functions in begin to provide some support for these operations, but there is no standard routine for doing either task. (The only thing printf() does in response to a custom locale setting is to change its decimal-point character.)

9. Why doesn't the call scanf("%d", i) work?
A: The arguments you pass to scanf() must always be pointers. To fix the fragment above, change it to scanf("%d", &i) .

10. Why doesn't this code:
double d;
scanf("%f", &d);
work?
A: Unlike printf(), scanf() uses %lf for values of type double, and %f for float.

11. How can I specify a variable width in a scanf() format string?
A: You can't; an asterisk in a scanf() format string means to suppress assignment. You may be able to use ANSI stringizing and string concatenation to accomplish about the same thing, or you can construct the scanf format string at run time.

12. When I read numbers from the keyboard with scanf "%d\n", it seems to hang until I type one extra line of input.
A: Perhaps surprisingly, \n in a scanf format string does *not* mean to expect a newline, but rather to read and discard characters as long as each is a whitespace character.

13. I'm reading a number with scanf %d and then a string with gets(), but the compiler seems to be skipping the call to gets()!
A: scanf %d won't consume a trailing newline. If the input number is immediately followed by a newline, that newline will immediately satisfy the gets().

As a general rule, you shouldn't try to interlace calls to scanf() with calls to gets() (or any other input routines); scanf's peculiar treatment of newlines almost always leads to trouble. Either use scanf() to read everything or nothing.

14.I figured I could use scanf() more safely if I checked its return value to make sure that the user typed the numeric values I expect, but sometimes it seems to go into an infinite loop.
A: When scanf() is attempting to convert numbers, any non-numeric characters it encounters terminate the conversion *and are left on the input stream*. Therefore, unless some other steps are
taken, unexpected non-numeric input "jams" scanf() again and again: scanf() never gets past the bad character(s) to encounter later, valid data. If the user types a character like `x' in response to a numeric scanf format such as %d or %f, code that simply re-prompts and retries the same scanf() call will immediately reencounter the same `x'.

15. Why does everyone say not to use scanf()? What should I use instead?
A: scanf() has a number of problems Also, its %s format has the same problem that gets() has -- it's hard to guarantee that the receiving buffer won't overflow.

More generally, scanf() is designed for relatively structured, formatted input (its name is in fact derived from "scan formatted"). If you pay attention, it will tell you whether it succeeded or failed, but it can tell you only approximately where it failed, and not at all how or why. It's nearly impossible to do decent error recovery with scanf(); usually it's far easier to read entire lines (with fgets() or the like), then interpret them, either using sscanf() or some other techniques. (Functions like strtol(), strtok(), and atoi() are often useful; If you do use any scanf variant, be sure to check the return value to make sure that the expected number of items were found. Also, if you use %s, be sure to guard against buffer overflow.

16. How can I tell how much destination buffer space I'll need for an arbitrary sprintf call? How can I avoid overflowing the destination buffer with sprintf()?
A: When the format string being used with sprintf() is known and relatively simple, you can sometimes predict a buffer size in an ad-hoc way. If the format consists of one or two %s's, you can
count the fixed characters in the format string yourself (or let sizeof count them for you) and add in the result of calling strlen() on the string(s) to be inserted. For integers, the number of characters produced by %d is no more than
((sizeof(int) * CHAR_BIT + 2) / 3 + 1) /* +1 for '-' */
(CHAR_BIT is in <limits.h>), though this computation may be over- conservative. (It computes the number of characters required for a base-8 representation of a number; a base-10 expansion is
guaranteed to take as much room or less.)

When the format string is more complicated, or is not even known until run time, predicting the buffer size becomes as difficult as reimplementing sprintf(), and correspondingly error-prone
(and inadvisable). A last-ditch technique which is sometimes suggested is to use fprintf() to print the same text to a bit bucket or temporary file, and then to look at fprintf's return value or the size of the file and worry about write errors).

If there's any chance that the buffer might not be big enough, you won't want to call sprintf() without some guarantee that the buffer will not overflow and overwrite some other part of memory. If the format string is known, you can limit %s expansion by using %.Ns for some N, or %.*s

The "obvious" solution to the overflow problem is a length- limited version of sprintf(), namely snprintf(). It would be used like this:
snprintf(buf, bufsize, "You typed \"%s\"", answer);
snprintf() has been available in several stdio libraries (including GNU and 4.4bsd) for several years. It will be standardized in C9X.

When the C9X snprintf() arrives, it will also be possible to use it to predict the size required for an arbitrary sprintf() call. C9X snprintf() will return the number of characters it would have placed in the buffer, not just how many it did place. Furthermore, it may be called with a buffer size of 0 and a null pointer as the destination buffer. Therefore, the call
nch = snprintf(NULL, 0, fmtstring, /* other arguments */ );
will compute the number of characters required for the fully- formatted string.

17. Why does everyone say not to use gets()?
A: Unlike fgets(), gets() cannot be told the size of the buffer it's to read into, so it cannot be prevented from overflowing that buffer. As a general rule, always use fgets().

18. Why does errno contain ENOTTY after a call to printf()?
A: Many implementations of the stdio package adjust their behavior slightly if stdout is a terminal. To make the determination, these implementations perform some operation which happens to fail (with ENOTTY) if stdout is not a terminal. Although the output operation goes on to complete successfully, errno still contains ENOTTY. (Note that it is only meaningful for a program to inspect the contents of errno after an error has been reported; errno is not guaranteed to be 0 otherwise.)

19. What's the difference between fgetpos/fsetpos and ftell/fseek? What are fgetpos() and fsetpos() good for?
A: ftell() and fseek() use type long int to represent offsets (positions) in a file, and may therefore be limited to offsets of about 2 billion (2**31-1). The newer fgetpos() and fsetpos() functions, on the other hand, use a special typedef, fpos_t, to represent the offsets. The type behind this typedef, if chosen appropriately, can represent arbitrarily large offsets, so fgetpos() and fsetpos() can be used with arbitrarily huge files. fgetpos() and fsetpos() also record the state associated with multibyte streams.

20. How can I flush pending input so that a user's typeahead isn't read at the next prompt? Will fflush(stdin) work?
A: fflush() is defined only for output streams. Since its definition of "flush" is to complete the writing of buffered characters (not to discard them), discarding unread input would not be an analogous meaning for fflush on input streams.

There is no standard way to discard unread characters from a stdio input stream, nor would such a way necessarily be sufficient, since unread characters can also accumulate in other, OS-level input buffers. You may be able to read and discard characters until \n, or use the curses flushinp()
function, or use some system-specific technique.

21. I'm trying to update a file in place, by using fopen mode "r+", reading a certain string, and writing back a modified string, but it's not working.
A: Be sure to call fseek before you write, both to seek back to the beginning of the string you're trying to overwrite, and because an fseek or fflush is always required between reading and writing in the read/write "+" modes. Also, remember that you can only overwrite characters with the same number of replacement characters, and that overwriting in text mode may truncate the file at that point.

22. How can I redirect stdin or stdout to a file from within a program?
A: Use freopen()

23. Once I've used freopen(), how can I get the original stdout (or stdin) back?
A: There isn't a good way. If you need to switch back, the best solution is not to have used freopen() in the first place. Try using your own explicit output (or input) stream variable, which you can reassign at will, while leaving the original stdout (or stdin) undisturbed.

It is barely possible to save away information about a stream before calling freopen(), such that the original stream can later be restored, but the methods involve system-specific calls such as dup(), or copying or inspecting the contents of a FILE structure, which is exceedingly nonportable and unreliable.

24. How can I arrange to have output go two places at once, e.g. to the screen and to a file?
A: You can't do this directly, but you could write your own printf variant which printed everything twice.

25. How can I read a binary data file properly? I'm occasionally seeing 0x0a and 0x0d values getting garbled, and I seem to hit EOF prematurely if the data contains the value 0x1a.
A: When you're reading a binary data file, you should specify "rb" mode when calling fopen(), to make sure that text file translations do not occur. Similarly, when writing binary data files, use "wb".

Note that the text/binary distinction is made when you open the file: once a file is open, it doesn't matter which I/O calls you use on it.

No comments: