There are a number of popular programming languages these days. Different companies, even different
departments within the same company, prefer to use different languages. Driver developers get used to
writing code in C. Many programmers who work on Linux develop applications in C++, while other
programmers working on Windows prefer C#. Many cross-platform systems are developed in Java.
Objective C becomes more and more popular due to sales of iPads and iPhones. Additionally, scripting
languages, such as Perl and Python, are very suitable to toolkit development.
Massive books have been written about each language. It is not a goal to cover all languages in detail in this book because of the space limitation, so Coding Interviews only discusses interview questions for the four most popular programming languages: C, C++, C#, and Java1.
C
One of the reasons why the C programming language is so popular is the flexibility of its use for memory management. Programmers have opportunities to control how, when, and where to allocate and deallocate memory. Memory is allocated statically, automatically, or dynamically in the C programming language.
Static variables and global variables are static-duration variables, which are allocated along with the executable code of the program and persist during the execution of the application. When a local variable is declared as static inside a function, it is initialized only once. Whatever values the function puts into its static local variables during one call will be present when the function is called again. The following is a typical interview question about static local variables: What is the output when the function test executes? (See Listing 2-1).
Listing 2-1. C Code with Static Variables
Massive books have been written about each language. It is not a goal to cover all languages in detail in this book because of the space limitation, so Coding Interviews only discusses interview questions for the four most popular programming languages: C, C++, C#, and Java1.
C
One of the reasons why the C programming language is so popular is the flexibility of its use for memory management. Programmers have opportunities to control how, when, and where to allocate and deallocate memory. Memory is allocated statically, automatically, or dynamically in the C programming language.
Static variables and global variables are static-duration variables, which are allocated along with the executable code of the program and persist during the execution of the application. When a local variable is declared as static inside a function, it is initialized only once. Whatever values the function puts into its static local variables during one call will be present when the function is called again. The following is a typical interview question about static local variables: What is the output when the function test executes? (See Listing 2-1).
Listing 2-1. C Code with Static Variables
int hasStatic(int n) {
static int x = 0;
x += n;
return x;
void test() {
int sum = 0;
for(int i = 1; i <= 4; ++i)
sum += hasStatic(i);
printf("Result of sum is %d.\n", sum);
}
The variable x in the function hasStatic is declared as static. When the function is called the first
time with a parameter 1, the static variable x is initialized as 0, and then set to 1. When the function is
called the second time with a parameter 2, it is not initialized again and its value 1 persists. It becomes 3
after execution. Similarly, its value becomes 6 and 10 after execution with parameters 3 and 4. Therefore,
the result is the sum 1+2+6+10=19.
Automatic-duration variables, also called local variables, are allocated on the stack. They are allocated and deallocated automatically when the program execution flow enters and leaves their scopes. In the sample code in Listing 2-2, there is a local array str in the function allocateMemory. What is the problem with it?
Listing 2-2. C Code to Allocate Memory
char* allocateMemory() {
char str[20] = "Hello world.";
return str;
}
void test() {
char* pString = allocateMemory();
printf("pString is %s.\n", pString);
}
Because the array str is a local variable, it is deallocated automatically when the execution flow leaves the function allocateMemory. Therefore, the returned memory to pString in the function test is actually invalid, and its content is somewhat random.
One limitation of static-duration and automatic-duration variables is that their size of allocation is required to be compile-time constant. This limitation can be avoided by dynamic memory allocation in which memory is more explicitly, as well as more flexibly, managed. In the C programming language, the library function malloc is used to allocate a block of memory dynamically on the heap, where size is specified at runtime. This block of memory is accessible via a pointer that malloc returns. When the memory is no longer needed, the pointer should be passed to another library function, free, which deallocates the memory in order to avoid memory leaks.
The function allocateMemory in Listing 2-3 utilizes the function malloc to allocate memory dynamically. What is the problem in it?
Listing 2-3. C Code to Allocate Memory
The parameter pString in the function allocateMemory is a pointer, and the string content it points to can be modified. However, the memory address it owns cannot be changed when the function allocateMemory returns. Since the input parameter pString of allocateMemory in the function test is NULL, it remains NULL after the execution of allocateMemory, and it causes the program to crash when the NULL address is accessed in test. In order to fix this problem, the first parameter of allocateMemory should be modified as char** pString.
Macros are commonly used in the C programming language and also commonly asked about in technical interviews. Since it is tricky and error-prone to use macros, unexpected results are gotten when they are misused. For example, what is the output when the function test in Listing 2-4 gets executed?
Listing 2-4. C Code with Macros
The result of 3+4 is 7, and the square of 7 is 49. However, 49 is not the result of SQUARE(3+4). Macros are substituted by the preprocessor, so SQUARE(3+4) becomes 3+4*3+4, which is actually 19. In order to make the result as expected, the macro should be modified to #define SQUARE(x) ((x)*(x)).
Even in the revised version of macro SQUARE, its result might look surprising if it is not analyzed carefully in some cases. For instance, what are the results of x and y after the code in Listing 2-5 is executed?
Listing 2-5. C Code with Macros
void allocateMemory(char* pString, int length) {
pString = (char*)malloc(length);
}
void test() {
char* pString = NULL;
allocateMemory(pString, 20);
strcpy(pString, "Hello world.");
}
The parameter pString in the function allocateMemory is a pointer, and the string content it points to can be modified. However, the memory address it owns cannot be changed when the function allocateMemory returns. Since the input parameter pString of allocateMemory in the function test is NULL, it remains NULL after the execution of allocateMemory, and it causes the program to crash when the NULL address is accessed in test. In order to fix this problem, the first parameter of allocateMemory should be modified as char** pString.
Macros are commonly used in the C programming language and also commonly asked about in technical interviews. Since it is tricky and error-prone to use macros, unexpected results are gotten when they are misused. For example, what is the output when the function test in Listing 2-4 gets executed?
Listing 2-4. C Code with Macros
#define SQUARE(x) (x*x)
void test() {
printf("Square of (3+4) is %d.\n", SQUARE(3+4));
}
The result of 3+4 is 7, and the square of 7 is 49. However, 49 is not the result of SQUARE(3+4). Macros are substituted by the preprocessor, so SQUARE(3+4) becomes 3+4*3+4, which is actually 19. In order to make the result as expected, the macro should be modified to #define SQUARE(x) ((x)*(x)).
Even in the revised version of macro SQUARE, its result might look surprising if it is not analyzed carefully in some cases. For instance, what are the results of x and y after the code in Listing 2-5 is executed?
Listing 2-5. C Code with Macros
#define SQUARE(x) ((x)*(x))
void test() {
int x = 5;
int y = SQUARE(x++);
printf("Result of x is %d, y is %d.\n", x, y);
}
No comments:
Post a Comment