Introduction
I’ve seen a lot of lists of so-called interview questions for C that are pretty bad, e.g., “What are all of C’s built-in types?” Such questions are bad because they require only rote memorization and not any actual understanding of anything.
When I’ve interviewed candidates, I split my questions into (at least) two types:
- Programming language knowledge (to ensure the candidate actually knows at least the bare minimum of a specific language).
- Algorithm implementation (that I’ve allowed candidates to implement in any language of their choosing, or even pseudocode, since the goal is to determine their problem-solving ability).
For #1, I further split questions into two levels: “any” or “senior” level programmer. I ask whichever set of questions based on what the job requires.
Here are a few questions (with answers) I’d ask a candidate during an interview for a job programming in C — or C++ since all these questions are also valid C++ questions (but see the note at the end).
If you’re a beginner, I recommend trying to answer the questions for yourself before clicking on the Answer links.
Questions
Question 1: Arrays vs. Pointers
Given this code fragment:
const char a[] = "hello";
const char *p = "world";
What are the differences between a
and p
?
Answer
-
a
is an array ofchar
of 6 elements. It uses 6 bytes of memory in total. The namea
is constant, e.g.,++a
would be illegal. -
p
is a pointer variable pointing to an array ofchar
of 6 elements. It uses 6 bytes for the array + 8 bytes (on a 64-bit system) for the pointer or 14 bytes of memory in total. The namep
is variable, e.g.,++p
would increment it by 1 byte.
Question 2: C Strings
Given this code fragment:
char *s = "hello, world";
s[0] = 'H';
What does this code do?
Answer
There’s no definitive answer because it would result in undefined behavior, though it would probably crash. String literals are typically stored in a read-only memory segment, so attempting to overwrite one would be “bad.”
Question 3: struct
Memory Layout
Given this code:
struct S {
int i;
char c;
};
int main() {
struct S s1;
printf( "%zu\n", sizeof( s1 ) );
}
Question 3a: If compiled (with no compiler options) and run, what is a reasonable value for this program to print and why?
Answer
8 — because of padding. 16 is also an acceptable answer. Any odd number, e.g., 5, is not acceptable.
Some candidates try to include compiler options or attributes for packed structures at which point I have to emphasize that the code is to be compiled as-is with no compiler options or attributes.
If the candidate does give an odd number, I then ask them to consider an array of the struct
like:
struct S a[2]; // assume array starts at memory address 0x1000
and draw the bytes in memory starting at 0x1000
and then ask about what address a[1].i
is at. Hopefully at this point, the candidate will realize why an odd number is a bad answer and give a better answer.
Question 3b: Why is padding necessary?
Answer
Because many CPU architectures require that reads and writes for certain data types, e.g., integers and pointers, take place on a word boundary.
Question 4: Local Variables
Given this function (where T
is some arbitrary type that doesn’t matter here):
T* f() {
T t;
// ...
return &t;
}
Question: What’s wrong with this function?
Answer
Because
t
is a local variable, it will cease to exist upon return, hence the pointer will be a dangling pointer. Attempting to dereference the pointer would result in undefined behavior (and would likely result in a core dump, if you’re lucky).
Question 5: static
Given:
static int g;
int f() {
static int i;
return ++i;
}
Question 5a: What does the static
for the declaration of g
do?
Answer
It makes
g
have internal linkage, that is the name of g
can only be used from the file it’s in. It’s like “private” for the file. The program could have another g
in another file and they would be distinct variables.Question 5b: What does the static
for the declaration of i
do?
Answer
It makes
i
be initialized to 0 and continue to exist between calls to f()
.Question 5c: What value does this function return the second time it’s called?
Answer
Two. It’s 0 initially, then the first
++i
makes it 1 and the second ++i
makes it 2.Question 5d (senior): Can this function ever result in undefined behavior?
Answer
Yes, because of signed integer overflow.
Question 5e (senior): How can you eliminate the possibility of undefined behavior?
Answer
Make
i
be unsigned
since unsigned integer overflow is well-defined (it wraps around to 0).Question 5f (senior): Is f()
thread-safe? Why or why not?
Answer
No, because the increment of
i
is not thread-safe because i
is neither _Atomic
nor are mutexes nor locks being used.
Question 6 (Senior): free()
How is free()
typically implemented by the C standard library given that you don’t pass it the amount of memory to be freed? How does it know how much memory to free?
To make this a C++ question, change
free
todelete
. Their implementations are similar or in some casesdelete
callsfree
under the hood.
Answer
One way to implement
free()
is to implement malloc(n)
to:
- Allocate
n
+sizeof(size_t)
bytes. - Store
n
at the start of the allocated memory area. - Return that address +
sizeof(size_t)
.
When free(p)
is called:
- Get the number of bytes from
((size_t*)p)[-1]
. - Deallocate that number of bytes +
sizeof(size_t)
.
Conclusion
Those are some decent C interview questions. Feel free to use them when interviewing candidates.
Note: As mentioned, I’d ask these same questions of a candidate interviewing for a job programming in C++. However, I’d also ask additional questions, but that’s a story for another time.
Top comments (2)
If this is only about C, please don't tag it with #cpp which is only for C++.
It's not only about C which I state clearly in both the introduction and conclusion.
Some comments have been hidden by the post's author - find out more