C Programming

  Home  Computer Programming  C Programming


“C Programming Interview Questions and Answers will guide you that C is a general-purpose computer programming language developed in 1972 by Dennis Ritchie at the Bell Telephone Laboratories and C language is for use with the Unix operating system. If you are developer and need to update your software development knowledge regarding basic and advance C programming or need to prepare for a job interview? Check out this collection of basic and advance C programing Interview Questions and Answers.”



221 C Programming Questions And Answers

21⟩ Is there a way to have non-constant case labels (i.e. ranges or arbitrary expressions)?

No. The switch statement was originally designed to be quite simple for the compiler to translate, therefore case labels are limited to single, constant, integral expressions. You can attach several case labels to the same statement, which will let you cover a small range if you don't mind listing all cases explicitly.

If you want to select on arbitrary ranges or non-constant expressions, you'll have to use an if/else chain.

 92 views

22⟩ Are the outer parentheses in return statements really optional?

Yes.

Long ago, in the early days of C, they were required, and just enough people learned C then, and wrote code which is still in circulation, that the notion that they might still be required is widespread.

(As it happens, parentheses are optional with the sizeof operator, too, under certain circumstances.)

 84 views

23⟩ How can I implement sets or arrays of bits?

Use arrays of char or int, with a few macros to access the desired bit in the proper cell of the array. Here are some simple macros to use with arrays of char:

#include <limits.h> /* for CHAR_BIT */

#define BITMASK(b) (1 << ((b) % CHAR_BIT))

#define BITSLOT(b) ((b) / CHAR_BIT)

#define BITSET(a, b) ((a)[BITSLOT(b)] |= BITMASK(b))

#define BITCLEAR(a, b) ((a)[BITSLOT(b)] &= ~BITMASK(b))

#define BITTEST(a, b) ((a)[BITSLOT(b)] & BITMASK(b))

#define BITNSLOTS(nb) ((nb + CHAR_BIT - 1) / CHAR_BIT)

(If you don't have <limits.h>, try using 8 for CHAR_BIT.)

Here are some usage examples. To declare an ``array'' of 47 bits:

char bitarray[BITNSLOTS(47)];

To set the 23rd bit:

BITSET(bitarray, 23);

To test the 35th bit:

if(BITTEST(bitarray, 35)) ...

To compute the union of two bit arrays and place it in a third array (with all three arrays declared as above):

for(i = 0; i < BITNSLOTS(47); i++)

array3[i] = array1[i] | array2[i];

To compute the intersection, use & instead of |.

As a more realistic example, here is a quick implementation of the Sieve of Eratosthenes, for computing prime numbers:

#include <stdio.h>

#include <string.h>

#define MAX 10000

int main()

{

char bitarray[BITNSLOTS(MAX)];

int i, j;

memset(bitarray, 0, BITNSLOTS(MAX));

for(i = 2; i < MAX; i++) {

if(!BITTEST(bitarray, i)) {

printf("%dn", i);

for(j = i + i; j < MAX; j += i)

BITSET(bitarray, j);

}

}

return 0;

}

 79 views

24⟩ Why dont C comments nest?

Why don't C comments nest? How am I supposed to comment out code containing comments? Are comments legal inside quoted strings?

C comments don't nest mostly because PL/I's comments, which C's are borrowed from, don't either. Therefore, it is usually better to ``comment out'' large sections of code, which might contain comments, with #ifdef or #if 0 ).

The character sequences /* and */ are not special within double-quoted strings, and do not therefore introduce comments, because a program (particularly one which is generating C code as output) might want to print them. (It is hard to imagine why anyone would want or need to place a comment inside a quoted string. It is easy to imagine a program needing to print "/*".)

 76 views

25⟩ Why isnt there a numbered, multi-level break statement to break out

Why isn't there a numbered, multi-level break statement to break out of several loops at once? What am I supposed to use instead, a goto?

First, remember why it is that break and continue exist at all--they are, in effect, ``structured gotos'' used in preference to goto (and accepted as alternatives by most of those who shun goto) because they are clean and structured and pretty much restricted to a common, idiomatic usages. A hypothetical multi-level break, on the other hand, would rapidly lose the inherent cleanliness of the single break--programmers and readers of code would have to carefully count nesting levels to figure out what a given break did, and the insertion of a new intermediately-nested loop could, er, break things badly. (By this analysis, a numbered break statement can be even more confusing and error-prone than a goto/label pair.)

The right way to break out of several loops at once (which C also does not have) involves a syntax which allows the naming of loops, so that a break statement can specify the name of the loop to be broken out of.

If you do have to break out of more than one loop at once (or break out of a loop from inside a switch, where break would merely end a case label) yes, go ahead and use a goto. (But when you find the need for a multi-level break, it's often a sign that the loop should be broken out to its own function, at which point you can achieve roughly the same effect as that multi-level break by using a premature return.)

 79 views

26⟩ Is C a great language, or what?

Is C a great language, or what? Where else could you write something like a+++++b ?

Well, you can't meaningfully write it in C, either. The rule for lexical analysis is that at each point during a straightforward left-to-right scan, the longest possible token is determined, without regard to whether the resulting sequence of tokens makes sense. The fragment in the question is therefore interpreted as

a ++ ++ + b

and cannot be parsed as a valid expression.

 87 views

27⟩ There seem to be a few missing operators ...

There seem to be a few missing operators, like ^^, &&=, and ->=.

A logical exclusive-or operator (hypothetically ``^^'') would be nice, but it couldn't possibly have short-circuiting behavior analogous to && and || Similarly, it's not clear how short-circuiting would apply to hypothetical assignment operators &&= and ||=. (It's also not clear how often &&= and ||= would actually be needed.)

Though p = p->next is an extremely common idiom for traversing a linked list, -> is not a binary arithmetic operator. A hypothetical ->= operator therefore wouldn't really fit the pattern of the other assignment operators.

You can write an exclusive-or macro in several ways:

#define XOR(a, b) ((a) && !(b) || !(a) && (b)) /* 1 */

#define XOR(a, b) (!!(a) ^ !!(b)) /* 2 */

#define XOR(a, b) (!!(a) != !!(b)) /* 3 */

#define XOR(a, b) (!(a) ^ !(b)) /* 4 */

#define XOR(a, b) (!(a) != !(b)) /* 5 */

#define XOR(a, b) ((a) ? !(b) : !!(b)) /* 6 */

 97 views

28⟩ Does C have circular shift operators?

No. (Part of the reason why is that the sizes of C's types aren't precisely defined----but a circular shift makes most sense when applied to a word of a particular known size.)

You can implement a circular shift using two regular shifts and a bitwise OR:

(x << 13) | (x > >3) /* circular shift left 13 in 16 bits */

 86 views

29⟩ If the assignment operator were ...

If the assignment operator were :=, wouldn't it then be harder to accidentally write things like if(a = b) ?

Yes, but it would also be just a little bit more cumbersome to type all of the assignment statements which a typical program contains.

In any case, it's really too late to be worrying about this sort of thing now. The choices of = for assignment and == for comparison were made, rightly or wrongly, over two decades ago, and are not likely to be changed. (With respect to the question, many compilers and versions of lint will warn about if(a = b) and similar expressions;

As a point of historical interest, the choices were made based on the observation that assignment is more frequent than comparison, and so deserves fewer keystrokes. In fact, using = for assignment in C and its predecessor B represented a change from B's own predecessor BCPL, which did use := as its assignment operator.

 83 views

30⟩ How can I manipulate individual bits?

Bit manipulation is straightforward in C, and commonly done. To extract (test) a bit, use the bitwise AND (&) operator, along with a bit mask representing the bit(s) you're interested in:

value & 0x04

To set a bit, use the bitwise OR (| or |=) operator:

value |= 0x04

To clear a bit, use the bitwise complement (~) and the AND (& or &=) operators:

value &= ~0x04

(The preceding three examples all manipulate the third-least significant, or 2**2, bit, expressed as the constant bitmask 0x04.)

To manipulate an arbitrary bit, use the shift-left operator (<<) to generate the mask you need:

value & (1 << bitnumber)

value |= (1 << bitnumber)

value &= ~(1 << bitnumber)

Alternatively, you may wish to precompute an array of masks:

unsigned int masks[] =

{0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};

value & masks[bitnumber]

value |= masks[bitnumber]

value &= ~masks[bitnumber]

To avoid surprises involving the sign bit, it is often a good idea to use unsigned integral types in code which manipulates bits and bytes.

 103 views

31⟩ Does C have an equivalent to Pascals with statement?

No. The way in C to get quick and easy access to the fields of a structure is to declare a little local structure pointer variable (which, it must be admitted, is not quite as notationally convenient as a with statement and doesn't save quite as many keystrokes, though it is probably safer). That is, if you have something unwieldy like

structarray[complex_expression].a =

structarray[complex_expression].b +

structarray[complex_expression].c;

you can replace it with

struct whatever *p = &structarray[complex_expression];

p->a = p->b + p->c;

 88 views

32⟩ Why doesnt C have nested functions?

It's not trivial to implement nested functions such that they have the proper access to local variables in the containing function(s), so they were deliberately left out of C as a simplification. (gcc does allow them, as an extension.) For many potential uses of nested functions (e.g. qsort comparison functions), an adequate if slightly cumbersome solution is to use an adjacent function with static declaration, communicating if necessary via a few static variables. (A cleaner solution, though unsupported by qsort, is to pass around a pointer to a structure containing the necessary context.)

 94 views

33⟩ What is assert and when would I use it?

It is a macro, defined in <assert.h>, for testing ``assertions''. An assertion essentially documents an assumption being made by the programmer, an assumption which, if violated, would indicate a serious programming error. For example, a function which was supposed to be called with a non-null pointer could write

assert(p != NULL);

A failed assertion terminates the program. Assertions should not be used to catch expected errors, such as malloc or fopen failures.

 89 views

34⟩ How can I call FORTRAN?

How can I call FORTRAN (C++, BASIC, Pascal, Ada, LISP) functions from C? (And vice versa?)

The answer is entirely dependent on the machine and the specific calling sequences of the various compilers in use, and may not be possible at all. Read your compiler documentation very carefully; sometimes there is a ``mixed-language programming guide,'' although the techniques for passing arguments and ensuring correct run-time startup are often arcane. Besides arranging calling sequences correctly, you may also have to conspire between the various languages to get aggregate data structures declared compatibly.

In C++, a "C" modifier in an external function declaration indicates that the function is to be called using C calling conventions. In Ada, you can use the Export and Convention pragmas, and types from the package Interfaces.C, to arrange for C-compatible calls, parameters, and data structures.

 93 views

35⟩ How do I swap bytes?

V7 Unix had a swab function, but it seems to have been forgotten.

A problem with explicit byte-swapping code is that you have to decide whether to call it or not, based on the byte order of the data and the byte order of the machine in use.

A better solution is to define functions which convert between the known byte order of the data and the (unknown) byte order of the machine in use, and to arrange for these functions to be no-ops on those machines which already match the desired byte order. A set of such functions, introduced with the BSD networking code but now in wide use, is ntohs, htons, ntohl, and htonl. These are intended to convert between ``network'' and ``host'' byte orders, for ``short'' or ``long'' integers, where ``network'' order is always big-endian, and where ``short'' integers are always 16 bits and ``long'' integers are 32 bits. (This is not the C definition, of course, but it's compatible with the C definition) So if you know that the data you want to convert from or to is big-endian, you can use these functions. (The point is that you always call the functions, making your code much cleaner. Each function either swaps bytes if it has to, or does nothing. The decision to swap or not to swap gets made once, when the functions are implemented for a particular machine, rather than being made many times in many different calling programs.)

 96 views

36⟩ If I have a char * variable pointing to the name of a function ...

If I have a char * variable pointing to the name of a function, how can I call that function? Code like

extern int func(int, int);

char *funcname = "func";

int r = (*funcname)(1, 2);

or

r = (*(int (*)(int, int))funcname)(1, 2);

doesn't seem to work.

By the time a program is running, information about the names of its functions and variables (the ``symbol table'') is no longer needed, and may therefore not be available. The most straightforward thing to do, therefore, is to maintain that information yourself, with a correspondence table of names and function pointers:

int one_func(), two_func();

int red_func(), blue_func();

struct { char *name; int (*funcptr)(); } symtab[] = {

"one_func", one_func,

"two_func", two_func,

"red_func", red_func,

"blue_func", blue_func,

};

Then, search the table for the name, and call via the associated function pointer, with code like this:

#include <stddef.h>

int (*findfunc(char *name))()

{

int i;

for(i = 0; i < sizeof(symtab) / sizeof(symtab[0]); i++) {

if(strcmp(name, symtab[i].name) == 0)

return symtab[i].funcptr;

}

return NULL;

}

...

char *funcname = "one_func";

int (*funcp)() = findfunc(funcname);

if(funcp != NULL)

(*funcp)();

 80 views

37⟩ How can I write data files which can be read on other machines with different word size, byte order, or floating point formats?

The most portable solution is to use text files (usually ASCII), written with fprintf and read with fscanf or the like. (Similar advice also applies to network protocols.) Be skeptical of arguments which imply that text files are too big, or that reading and writing them is too slow. Not only is their efficiency frequently acceptable in practice, but the advantages of being able to interchange them easily between machines, and manipulate them with standard tools, can be overwhelming.

If you must use a binary format, you can improve portability, and perhaps take advantage of prewritten I/O libraries, by making use of standardized formats such as Sun's XDR (RFC 1014), OSI's ASN.1 (referenced in CCITT X.409 and ISO 8825 ``Basic Encoding Rules''), CDF, netCDF, or HDF.

 81 views

38⟩ What is the right way to use errno?

In general, you should detect errors by checking return values, and use errno only to distinguish among the various causes of an error, such as ``File not found'' or ``Permission denied''. (Typically, you use perror or strerror to print these discriminating error messages.) It's only necessary to detect errors with errno when a function does not have a unique, unambiguous, out-of-band error return (i.e. because all of its possible return values are valid; one example is atoi). In these cases (and in these cases only; check the documentation to be sure whether a function allows this), you can detect errors by setting errno to 0, calling the function, then testing errno. (Setting errno to 0 first is important, as no library function ever does that for you.)

To make error messages useful, they should include all relevant information. Besides the strerror text derived from errno, it may also be appropriate to print the name of the program, the operation which failed (preferably in terms which will be meaningful to the user), the name of the file for which the operation failed, and, if some input file (script or source file) is being read, the name and current line number of that file.

 94 views

39⟩ What is a good data structure to use for storing lines of text?

What's a good data structure to use for storing lines of text? I started to use fixed-size arrays of arrays of char, but they're just too restrictive.

One good way of doing this is with a pointer (simulating an array) to a set of pointers (each simulating an array) of char. This data structure is sometimes called a ``ragged array,'' and looks something like this:

[FIGURE GOES HERE]

You could set up the tiny array in the figure above with these simple declarations:

char *a[4] = {"this", "is", "a", "test"};

char **p = a;

(where p is the pointer-to-pointer-to-char and a is an intermediate array used to allocate the four pointers-to-char).

To really do dynamic allocation, you'd of course have to call malloc:

#include <stdlib.h>

char **p = malloc(4 * sizeof(char *));

if(p != NULL) {

p[0] = malloc(5);

p[1] = malloc(3);

p[2] = malloc(2);

p[3] = malloc(5);

if(p[0] && p[1] && p[2] && p[3]) {

strcpy(p[0], "this");

strcpy(p[1], "is");

strcpy(p[2], "a");

strcpy(p[3], "test");

}

}

(Some libraries have a strdup function which would streamline the inner malloc and strcpy calls. It's not Standard, but it's obviously trivial to implement something like it.)

Here is a code fragment which reads an entire file into memory, using the same kind of ragged array.

#include <stdio.h>

#include <stdlib.h>

extern char *agetline(FILE *);

FILE *ifp;

 81 views

40⟩ How can I return multiple values from a function?

There are several ways of doing this. (These examples show hypothetical polar-to-rectangular coordinate conversion functions, which must return both an x and a y coordinate.)

1. Pass pointers to several locations which the function can fill in:

#include <math.h>

polar_to_rectangular(double rho, double theta,

double *xp, double *yp)

{

*xp = rho * cos(theta);

*yp = rho * sin(theta);

}

...

double x, y;

polar_to_rectangular(1., 3.14, &x, &y);

2. Have the function return a structure containing the desired values:

struct xycoord { double x, y; };

struct xycoord

polar_to_rectangular(double rho, double theta)

{

struct xycoord ret;

ret.x = rho * cos(theta);

ret.y = rho * sin(theta);

return ret;

}

...

struct xycoord c = polar_to_rectangular(1., 3.14);

3. Use a hybrid: have the function accept a pointer to a structure, which it fills in:

polar_to_rectangular(double rho, double theta,

struct xycoord *cp)

{

cp->x = rho * cos(theta);

cp->y = rho * sin(theta);

}

...

struct xycoord c;

polar_to_rectangular(1., 3.14, &c);

(Another example of this technique is the Unix system call stat.)

4. In a pinch, you could theoretically use global variables (though this is rarely a good idea).

 85 views