Monday, December 24, 2007

C Interview Questions And Answers- 18

[Q2.14 How can I determine the byte offset of a field within a structure?]

A: ANSI C defines the offsetof() macro, which should be used if
available; see stddef.h. If you don't have it, one possible
implementation is
---
A: ANSI C defines the offsetof() macro in stddef.h, which lets
you compute the offset of field f in struct s as
offsetof(struct s, f). If for some reason you have to code this
sort of thing yourself, one possibility is

==========

[2.15 How can I access structure fields by name at run time?]

A: Build a table of names and offsets, using the offsetof() macro.
The offset of field b in struct a is

offsetb = offsetof(struct a, b)

If structp is a pointer to an instance of this structure, and
field b is an int (with offset as computed above), b's value can
be set indirectly with
---
A: Keep track of the field offsets as computed using the offsetof()
macro (see question 2.14). If structp is a pointer to an
instance of the structure, and field f is an int having offset
offsetf, f's value can be set indirectly with

==========

[Q2.20 Can I initialize unions?]

A: The current C Standard allows an initializer for the first-named
member of a union. C9X will introduce "designated initializers"
which can be used to initialize any member.
---
A: In the original ANSI C, an initializer was allowed only for the
first-named member of a union. C99 introduces "designated
initializers" which can be used to initialize any member.

==========

[Q3.2 Under my compiler... Regardless of the order of evaluation...]

example, the compiler chose to multiply the previous value by
itself and to perform both increments afterwards.
---
itself and to perform both increments later.

[Q3.8 How can I understand these complex expressions?]

The second sentence can be difficult to understand. It says
that if an object is written to within a full expression, any
and all accesses to it within the same expression must be for
the purposes of computing the value to be written. This rule
effectively constrains legal expressions to those in which the
accesses demonstrably precede the modification.
---
and all accesses to it within the same expression must be
directly involved in the computation of the value to be written.
This rule effectively constrains legal expressions to those in
which the accesses demonstrably precede the modification. For
example, i = i + 1 is legal, but not a[i] = i++ (see question
3.1).

==========

[3.9 So... we don't know which..., but i does get incremented..., right?]

A: *No*. Once an expression or program becomes undefined, *all*
---
A: Not necessarily! Once an expression or program becomes
undefined, *all* aspects of it become undefined.

==========

[Q4.2 I'm trying to declare a pointer and allocate some space for it...]

A: The pointer you declared is p, not *p. To make a pointer point
somewhere, you just use the name of the pointer:
---
A: The pointer you declared is p, not *p. When you're manipulating
the pointer itself (for example when you're setting it to make
it point somewhere), you just use the name of the pointer:

==========

[4.3 Does *p++ increment p, or what it points to?]

A: Postfix ++ essentially has higher precedence than the prefix
---
A: The postfix ++ and -- operators essentially have higher
precedence than the prefix unary operators.

==========

[Q4.10 ...How can I pass a constant by reference?]

A: You can't do this directly. You will have to declare
---
A: In C99, you can use a "compound literal":

f((int[]){5});

Prior to C99, you couldn't do this directly; you had to declare
a temporary variable, and then pass its address to the function:

==========

[Q5.6 If NULL were defined as follows...]

At any rate, ANSI function prototypes ensure that most (though
not quite all; see question 5.2) pointer arguments are converted
correctly when passed as function arguments, so the question is
largely moot.

==========

5.20: What does a run-time "null pointer assignment" error mean?
How can I track it down?

A debugger may let you set a data watchpoint on location 0.
Alternatively, you could write a bit of code to stash away a
copy of 20 or so bytes from location 0, and periodically check
that the memory at location 0 hasn't changed. See also question
16.8.

==========

[Q6.15 How can I declare local arrays of a size matching a passed-in array?]

A: Until recently, you couldn't. Array dimensions in C
traditionally had to be compile-time constants. C9X will
introduce variable-length arrays (VLA's) which will solve this
---
A: Until recently, you couldn't; array dimensions in C
traditionally had to be compile-time constants. However, C99
introduces variable-length arrays (VLA's) which solve this
problem; local arrays may have sizes set by variables or other
expressions, perhaps involving function parameters.

==========

[Q6.16 How can I dynamically allocate a multidimensional array?]

You can also use sizeof(*array1) and sizeof(**array1)
instead of sizeof(int *) and sizeof(int).)

==========

[Q6.19 How do I write functions which accept two-dimensional arrays...]

C9X will allow variable-length arrays, and once compilers which
accept C9X's extensions become widespread, this will probably
---
C99 allows variable-length arrays, and once compilers which
accept C99's extensions become widespread, VLA's will probably
become the preferred solution.

==========

[Q7.27 So can I query the malloc package to find out how big...]

(Some compilers provide nonstandard extensions.)

==========

[Q7.32 What is alloca() and why is its use discouraged?]

Now that C99 supports variable-length arrays (VLA's),
they can be used to more cleanly accomplish most of the
tasks which alloca() used to be put to.

==========

[Q8.6 How can I get the numeric (character set) value corresponding to...]

To convert back and forth between the digit characters and the
corresponding integers in the range 0-9, add or subtract the
constant '0' (that is, the character value '0').

==========

[Q10.7 Is it acceptable for one header file to #include another?]

the prestigious Indian Hill Style Guide (see question 17.9)
disparages them; they can make it harder to find relevant
definitions; they can lead to multiple-definition errors if a file
is #included twice;
---
is #included twice; they can lead to increased compilation time;
and they make manual Makefile maintenance very difficult.

==========

10.11: I seem to be missing the system header file sgtty.h.
Can someone send me a copy?
---
10.11: I'm compiling a program, and I seem to be missing one of the
header files it requires. Can someone send me a copy?

A: There are several situations, depending on what sort of header
file it is that's "missing".

If the missing header file is a standard one, there's a problem
with your compiler. You'll need to contact your vendor, or
someone knowledgeable about your particular compiler, for help.

The situation is more complicated in the case of nonstandard
headers. Some are completely system- or compiler-specific.
Some are completely unnecessary, and should be replaced by their
Standard equivalents. (For example, instead of malloc.h, use
stdlib.h.) Other headers, such as those associated with
popular add-on libraries, may be reasonably portable.

Standard headers exist in part so that definitions appropriate
to your compiler, operating system, and processor can be
supplied. You cannot just pick up a copy of someone else's
header file and expect it to work, unless that person is using
exactly the same environment. Ask your compiler vendor why the
file was not provided (or to send a replacement copy).
---
exactly the same environment. You may actually have a
portability problem (see section 19), or a compiler problem.
Otherwise, see question 18.16.

==========

[Q10.26 How can I write a macro which takes a variable number of arguments?]

C9X will introduce formal support for function-like macros with
variable-length argument lists. The notation ... will appear at
---
C99 introduces formal support for function-like macros with
variable-length argument lists. The notation ... can appear at

definition will be replaced by the variable arguments during
---
definition is replaced by the variable arguments during

==========

[Q11.1 What is the "ANSI C Standard?"]

More recently, the Standard has been adopted as an international
standard, ISO/IEC 9899:1990, and this ISO Standard replaces the
earlier X3.159 even within the United States (where it is known
---
A year or so later, the Standard was adopted as an international
standard, ISO/IEC 9899:1990, and this ISO Standard replaced the
earlier X3.159 even within the United States (where it was known

As of this writing, a complete revision of the Standard is in
its final stages. The new Standard is nicknamed "C9X" on the
assumption that it will be finished by the end of 1999. (Many
of this article's answers have been updated to reflect new C9X
features.)
---
Most recently, a major revision of the Standard, "C99", has been
completed and adopted.

The original ANSI Standard included a "Rationale," explaining
many of its decisions, and discussing a number of subtle points,
including several of those covered here. (The Rationale was
"not part of ANSI Standard X3.159-1989, but... included for
information only," and is not included with the ISO Standard.
A new one is being prepared for C9X.)
---
Several versions of the Standard, including C99 and the original
ANSI Standard, have included a "Rationale," explaining many of
its decisions, and discussing a number of subtle points,
including several of those covered here.

==========

[Q11.2 How can I get a copy of the Standard?]

Note that ANSI derives revenues to support its operations
from the sale of printed standards, so electronic copies
are *not* available.
---
An electronic (PDF) copy is available on-line, for US$18,
from www.ansi.org.

The last time I checked, the cost was $130.00 from ANSI or
$400.50 from Global. Copies of the original X3.159 (including
the Rationale) may still be available at $205.00 from ANSI or
$162.50 from Global.

In the U.S., it may be possible to get a copy of the original
ANSI X3.159 (including the Rationale) as "FIPS PUB 160" from

National Technical Information Service (NTIS)
U.S. Department of Commerce
Springfield, VA 22161
703 487 4650

==========

[Q11.10 Why can't I pass a char ** to a function which expects...]

You must use explicit casts (e.g. (const char **) in this case)
when assigning (or passing) pointers which have qualifier
mismatches at other than the first level of indirection.
---
If you must assign or pass pointers which have qualifier
mismatches at other than the first level of indirection, you
must use explicit casts (e.g. (const char **) in this case),
although as always, the need for such a cast may indicate a
deeper problem which the cast doesn't really fix.

==========

11.27: Why does the ANSI Standard not guarantee more than six case-
insensitive characters of external identifier significance?
---
11.27: Why does the ANSI Standard place limits on the length and case-
significance of external identifiers?

The limitation is only that identifiers be *significant*
in the first six characters, not that they be restricted to
six characters in length. This limitation is marked in the
Standard as "obsolescent", and will be removed in C9X.
---
in some initial sequence of characters, not that they be
restricted to that many characters in total length.
(The limitation was to six characters in the original
ANSI Standard, but has been relaxed to 31 in C99.)

==========

[Q11.33 ...implementation-defined, unspecified, and undefined behavior.]

(A fourth defined class of not-quite-precisely-defined behavior,
without the same stigma attached to it, is "locale-specific".)

==========

[Q12.2 Why does the code... copy the last line twice?]

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.
---
the input routine -- fgets(), for example, returns NULL on end-
of-file. In virtually all cases, there's no need to use feof()
at all.

==========

[Q12.21 How can I tell how much... buffer space... for a... sprintf call?]

The "obvious" solution to the overflow problem is a length-
limited version of sprintf(), namely snprintf(). It would be
used like this:
---
To avoid the overflow problem, you can use a length-limited
version of sprintf(), namely snprintf(). It is used like this:

It will be standardized in C9X.
---
It has finally been standardized in C99.

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
---
As an extra, added bonus, the C99 snprintf() provides a way
to predict the size required for an arbitrary sprintf() call.
C99's snprintf() returns the number of characters it would have
placed in the buffer, and it may be called with a buffer size
of 0. Therefore, the call

will compute the number of characters required for the fully-
---
predicts the number of characters required for the fully-

Yet another option is the (nonstandard) asprintf() function,
present in various C libraries including bsd's and GNU's, which
formats to (and returns a pointer to) a malloc'ed buffer, like
this:

char *buf;
asprintf(&buf, "%d = %s", 42, "forty-two");
/* now buf points to malloc'ed space containing formatted string */

==========

[Q12.23 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().
---
that buffer. The Standard fgets() function is a vast
improvement over gets(), although it's not perfect, either.
(If long lines are a real possibility, their proper handling
must be carefully considered.)

==========

12.26: How can I flush pending input so that a user's typeahead isn't
---
12.26b: If fflush() won't work, what can I use to flush input?

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. See also
questions 19.1 and 19.2.
---
other, OS-level input buffers. If you're trying to actively
discard typed-ahead input (perhaps in anticipation of issuing a
critical prompt), you'll have to use a system-specific
technique; see questions 19.1 and 19.2.

==========

[Q12.30 I'm trying to update a file in place...]

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. See also question 19.14.
---
truncate the file at that point, and that you may have to
preserve line lengths. See also question 19.14.

==========

[Q12.34 Once I've used freopen(), how can I get the original stdout... back?]

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.
---
It may be possible, in a nonportable way, to save away
information about a stream before calling freopen(), such that
the original stream can later be restored. One way is to use a
system-specific call such as dup() or dup2(), if available.
Another is to copy or inspect the contents of the FILE
structure, but this is exceedingly nonportable and unreliable.

==========

12.36b: How can I arrange to have output go two places at once,
e.g. to the screen and to a file?

Here is a simple example:

#include stdio.h
#include stdarg.h

void f2printf(FILE *fp1, FILE *fp2, char *fmt, ...)
{
va_list argp;
va_start(argp, fmt); vfprintf(fp1, fmt, argp); va_end(argp);
va_start(argp, fmt); vfprintf(fp2, fmt, argp); va_end(argp);
}

where f2printf() is just like fprintf() except that you give it
two file pointers and it prints to both of them.

==========

[Q13.2 Why does strncpy() not always place a '\0' terminator...]

You can get around the problem by using strncat() instead
of strncpy(): if the destination string starts out empty
(that is, if you do *dest = '\0' first), strncat()
does what you probably wanted strncpy() to do.

==========

[Q13.12 How can I get the current date or time of day in a C program?]

printf("It's %.24s.\n", ctime(&now));
---
printf("It's %s", ctime(&now));

If you need control over the format, use strftime().
If you need sub-second resolution, see question 19.37.

==========

[Q13.14 How can I add N days to a date?]

A: The ANSI/ISO Standard C mktime() and difftime() functions
provide some support for both problems.
---
provide some (limited) support for both problems.

These solutions are only guaranteed to work correctly
---
However, these solutions are guaranteed to work correctly only
for dates in the range which can be represented as time_t's.

(For conservatively-sized time_t, that range is often -- but not
always -- from 1970 to approximately 2037; note however that
there are time_t representations other than as specified by Unix
and Posix.)

Another approach to both problems,
which will work over a much wider range of dates,
is to use "Julian day numbers".

==========

[Q13.15 I need a random number generator.]

If you do find yourself needing to implement your own random
number generator, there is plenty of literature out there; see
the References. There are also any number of packages on the
net: look for r250, RANLIB, and FSULTRA (see question 18.16).
---
the References below or the sci.math.num-analysis FAQ list.
There are also any number of packages on the net: old standbys
are r250, RANLIB, and FSULTRA (see question 18.16), and there is
much recent work by Marsaglia, and Matumoto and Nishimura (the
"Mersenne Twister"), and some code collected by Don Knuth on his
web pages.

==========

[Q13.17 Each time I run my program, I get the same sequence of numbers...]

A: You can call srand() to seed the pseudo-random number generator
with a truly random initial value. Popular seed values are the
time of day, or the elapsed time before the user presses a key
(although keypress times are hard to determine portably;
---
with a truly random (or at least variable) initial value, such
as the time of day. Here is a simple example:

#include stdlib.h
#include time.h

srand((unsigned int)time((time_t *)NULL));

(Unfortunately, this code isn't perfect -- among other things,
the time_t returned by time() might be a floating-point type,
hence not portably convertible to unsigned int without the
possibility of overflow.

==========

[Q14.1 When I set a float... 3.1, why is printf printing it as 3.0999999?]

A: Most computers use base 2 for floating-point numbers as well as
for integers. In base 2, one divided by ten is an infinitely-
repeating fraction (0.0001100110011...), so fractions such as
3.1 (which look like they can be exactly represented in decimal)
---
for integers. Although 0.1 is a nice, polite-looking fraction
in base 10, its base-2 representation is an infinitely-repeating
fraction (0.0001100110011...), so exact decimal fractions such as 3.1
cannot be represented exactly in binary.

[Q14.3 ...I keep getting "undefined: sin" compilation errors.]

A: Make sure you're actually linking with the math library. For
instance, under Unix, you usually need to use the -lm option, at
---
instance, due to a longstanding bug in Unix and Linux systems,
you usually need to use an explicit -lm flag, at the *end* of
the command line, when compiling/linking.

==========

[Q14.5 What's a good way to check for "close enough" floating-point equality?]

use something like

#include math.h
if(fabs(a - b) = epsilon * fabs(a))

for some suitably-chosen degree of closeness epsilon (as long as
a is nonzero!).
---
where epsilon is a value chosen to set the degree of "closeness"
(and where you know that a will not be zero).

==========

[Q14.8 The predefined constant M_PI seems to be missing...]
machine's copy of math.h.

If you need pi, you'll have to define it yourself, or compute it
with 4*atan(1.0).
---
with 4*atan(1.0) or acos(-1.0).

==========

[Q14.9 How do I test for IEEE NaN and other special values?]

C9X will provide isnan(), fpclassify(), and several other
---
C99 provides isnan(), fpclassify(), and several other
classification routines.

==========

[Q14.11 What's a good way to implement complex numbers in C?]

C9X will support complex as a standard type.
---
C99 supports complex as a standard type.

==========

[Q15.6 How can I write a function analogous to scanf()...]

A: C9X will support vscanf(), vfscanf(), and vsscanf().
(Until then, you may be on your own.)
---
A: C99 (but *not* any earlier C Standard) supports vscanf(),
vfscanf(), and vsscanf().

==========

[Q16.1b I'm getting baffling syntax errors which make no sense at all...]

A: Check for unclosed comments or mismatched #if/#ifdef/#ifndef/
#else/#endif directives; remember to check header files, too.
---
A: Check for unclosed comments, mismatched #if/#ifdef/#ifndef/
#else/#endif directives, and perhaps unclosed quotes; remember
to check header files, too.

No comments:

My Ad

.