Need help being assessed on basic programming questions

  • Thread starter Jamin2112
  • Start date
  • Tags
    Programming
In summary: Reverse a string: char* revString(string str) { unsigned int len = str.length(); char* newStr = new char[len+1]; for (unsigned int i = 0; i < len; i++) { newStr[i] = str[len - i - 1]; } newStr[len] = '\0'; return newStr;} The first function calculates the length of the string and creates a new character array of the same size, then uses a for loop to reverse the characters and add them to the new array. Finally, a null character is added to the end and the new array is returned.4. Write a function to
  • #1
Jamin2112
986
12
Ok, so I'm going in for an interview on Thursday and the technical recruiter told me to just practice basic coding problems until I'm blue in the face. I know there are some experts here. I was wondering whether you could give me some questions and then assess my answers as you would if you were interviewing me.

For example, finish the following function that returns the mode (most frequent element) of an integer array.

int mode(unsigned int size, int* arr) {
// ...
}


Questions like that.
 
Technology news on Phys.org
  • #2
It looks like you are being tested in C, or maybe C++. Here are a few basic questions I have asked or been asked, from both sides of the interview.

1. Pointer to char vs. array of char

Which is correct, and why?

Code:
const char *GetString1(void)
{
    char *str = "Hello";
    return str;
}

vs.

Code:
const char *GetString2(void)
{
    char str[] = "Hello";
    return str;
}

2. The keyword "static" shows up in a lot of different contexts in C and C++. Give some examples of this, and explain what it means in each case.

3. Reversing things: e.g., write a function to reverse a string, or the digits (decimal or binary) of a given number. Write a function to reverse a linked list. Write a function to reverse a sentence: e.g., "write a function to reverse a sentence" becomes "sentence a reverse to function a write".

4. Write a function to sort an array of numbers in place. (Or an array of strings.)

5. Write a function to count how many "1" bits appear in the binary representation of the input number.

6. (C++, easier) Let's write a simple complex number class, with various useful operators.

7. (C++, harder) Let's write a simple matrix class, with various useful operators. Need to manage memory because we want to support arbitrary sizes of matrices. Alternate: let's write a "big integer" class which can handle integers of arbitrary size.

8. Without using any standard library functions, how might you go about calculating pi to arbitrary precision?

9. Write a function to find the first N prime numbers, where N is specified by the user.
 
  • #3
jbunniii said:
It looks like you are being tested in C, or maybe C++. Here are a few basic questions I have asked or been asked, from both sides of the interview.

1. Pointer to char vs. array of char

Which is correct, and why?

Code:
const char *GetString1(void)
{
    char *str = "Hello";
    return str;
}

vs.

Code:
const char *GetString2(void)
{
    char str[] = "Hello";
    return str;
}

Both those are "legal" and they do the exact same thing, which is, they return a pointer to "H". But you'd want to use the second because it adds a null character as a sentinel to denote the end of the string.
 
  • Like
Likes 1 person
  • #4
jbunniii said:
2. The keyword "static" shows up in a lot of different contexts in C and C++. Give some examples of this, and explain what it means in each case.

I'll have to brush up on this and then answer later. :frown:
 
  • #5
jbunniii said:
3. Reversing things: e.g., write a function to reverse a string, or the digits (decimal or binary) of a given number.

Reverse a string:

Code:
char* revString(string str) { 
    unsigned int len = str.length();
    char* newStr = new char[len+1]; 
    for (unsigned int i = 0; i < len; i++) { 
         newStr[i] = str[len - i - 1];
    }
    newStr[len] = '\0';
    return newStr;
}
 
  • #6
jbunniii said:
IWrite a function to reverse a linked list.

Without loss of generality, suppose it's a linked integer list created from the data structure

Code:
struct listElement { 
     int val;
     listElement* next;
}

and suppose

Code:
listElement* root

is the first element.

The procedure will first need to know how many elements are in the list. So we'll need a function like

Code:
unsigned int numElements(listElement* root) { 
   unsigned int count = 1;
   listElement* currentElementPtr = root;
    while (currentElementPtr->next != NULL) { 
         count++;
         currentElementPtr = currentElementPtr->next;
    }
   return count;
}


Fairly simple after that. Make another function that loops through all the elements and swaps their pointers with those on the opposite end.
 
  • #7
Will work on the others tomorrow morning. It's 1:05 a.m. right now. :zzz:
 
  • #8
jbunniii said:
1. Pointer to char vs. array of char ... Which is correct, and why?

Jamin2112 said:
Both those are "legal" and they do the exact same thing, which is, they return a pointer to "H". But you'd want to use the second because it adds a null character as a sentinel to denote the end of the string.
What happens to "str" once the code exits the functions getstring1() or getstring2()? How does this affect what is returned by those functions?

The test program mentioned in the first post of this thread is a bit more lengthy than what I would expect for an inteview test. How much time do you have to write these test programs?

jbunniii said:
5. Write a function to count how many "1" bits appear in the binary representation of the input number.
Side note, this is an intrinsic function with some compilers, and an instruction for recent versions of the X86 processor. So don't cheat on this one by using the intrinsic function.
 
  • #9
Jamin2112 said:
Both those are "legal" and they do the exact same thing, which is, they return a pointer to "H". But you'd want to use the second because it adds a null character as a sentinel to denote the end of the string.
No, both strings are null-terminated. That isn't the issue. The problem is more serious: in one of the functions, the memory containing "Hello" disappears after the function returns. Focus on the two initializers:

char *str = "Hello";

vs.

char str[] = "Hello";

Where is the string "Hello" stored in each case?
 
  • #10
Jamin2112 said:
Reverse a string:

Code:
char* revString(string str) { 
    unsigned int len = str.length();
    char* newStr = new char[len+1]; 
    for (unsigned int i = 0; i < len; i++) { 
         newStr[i] = str[len - i - 1];
    }
    newStr[len] = '\0';
    return newStr;
}
I don't want the function to allocate memory. Please reverse the string "in place". Also, your function uses a std::string for input and returns a C-style string for output. Please pick one and stick with it.
 
  • #11
Jamin2112 said:
Without loss of generality, suppose it's a linked integer list created from the data structure

Code:
struct listElement { 
     int val;
     listElement* next;
}

and suppose

Code:
listElement* root

is the first element.

The procedure will first need to know how many elements are in the list. So we'll need a function like

Code:
unsigned int numElements(listElement* root) { 
   unsigned int count = 1;
   listElement* currentElementPtr = root;
    while (currentElementPtr->next != NULL) { 
         count++;
         currentElementPtr = currentElementPtr->next;
    }
   return count;
}


Fairly simple after that. Make another function that loops through all the elements and swaps their pointers with those on the opposite end.
The devil is in the details. :biggrin: Also, it's not necessary to count the elements. Suppose my list contains a billion elements. We don't want to have to make two passes through the list, one for counting and one for reversing.
 
  • #12
rcgldr said:
Side note, this is an intrinsic function with some compilers, and an instruction for recent versions of the X86 processor. So don't cheat on this one by using the intrinsic function.
Indeed, please make the function as portable as possible. Don't make any assumptions about the target platform's integer size. For definiteness, assume the input is an unsigned long:
Code:
unsigned int NumberOfOneBits(unsigned long inputVal)
{
    // ...
}
 
  • #13
jbunniii said:
5. Write a function to count how many "1" bits appear in the binary representation of the input number.

Critique my answer:

Code:
unsigned int countOneBits(int num) { 
   unsigned int count;
   for (unsigned int i = 0; i < sizeof(int) * 8; i++) { 
         count += (num % 2 == 1 ? 1 : 0);
         num = num /= 2;
   } 
   return count;
}
 
  • #14
jbunniii said:
No, both strings are null-terminated. That isn't the issue. The problem is more serious: in one of the functions, the memory containing "Hello" disappears after the function returns. Focus on the two initializers:

char *str = "Hello";

vs.

char str[] = "Hello";

Where is the string "Hello" stored in each case?

I'm going to admit that I don't know the difference. Can you explain this one to me?
 
  • #15
Jamin2112 said:
Critique my answer
Try compiling the program and check the results with varius numbers. For example, try the number 0x88888888, which should return 8.

Some of these programs have "clever" alternative methods that can be used. For this program, note that num &= num-1; clears the least significant 1 bit from num.
 
Last edited:
  • #16
jbunniii said:
I don't want the function to allocate memory. Please reverse the string "in place". Also, your function uses a std::string for input and returns a C-style string for output. Please pick one and stick with it.

First of all, thanks for the help so far! Keep critiquing me as harshly as possible.

I think I will need some additional memory to do this because I need a temporary placeholder for a character.

Code:
string revString(string str) { 
    char temp; 
    for (unsigned int i = 0; i < str.length(); i++) { 
        temp = str[i];
        str[i] = str[str.length() - i - 1];
        str[str.length() - i - 1] = temp;
    }
    return str;
}
 
  • #17
rcgldr said:
Some of these programs have "clever" alternative methods that can be used. For this program, note that num &= num-1; clears the least significant 1 bit from num.

Dammit. My electrical engineer buddy is good at doing this fancy logic with bits. Me, not so much. I'll think about this a little later.
 
  • #18
jbunniii said:
Indeed, please make the function as portable as possible. Don't make any assumptions about the target platform's integer size. For definiteness, assume the input is an unsigned long:
Code:
unsigned int NumberOfOneBits(unsigned long inputVal)
{
    // ...
}

In that case you could use the procedure I mentioned:

Code:
unsigned int NumberOfOneBits(unsigned long inputVal) {
     unsigned int count = 0;
     for (unsigned int i = 0; i < sizeof(unsigned long) * 8; i++) { 
         count += inputVal % 2 ? 1 : 0;  
         inputVal /= 2;
     }
     return count;
}
 
  • #19
jbunniii said:
4. Write a function to sort an array of numbers in place. (Or an array of strings.)

Just to be clear: So I should take an array of unique numbers and rearrange them from least to greatest?

Code:
double* SortNumbers(double* arr, unsigned int size) { 
   // move around stuff in arr
   return arr; 
}
 
  • #20
jbunniii said:
No, both strings are null-terminated. That isn't the issue. The problem is more serious: in one of the functions, the memory containing "Hello" disappears after the function returns. Focus on the two initializers:

char *str = "Hello";

vs.

char str[] = "Hello";

Where is the string "Hello" stored in each case?

Jamin2112 said:
I'm going to admit that I don't know the difference. Can you explain this one to me?

You may be unaware that the C standard states that literal strings like "Hello" have static duration (they exist from the tiime the program starts until the program ends), and that the string is constant. For the second case, char str[] = "Hello"; , I'm not sure if the compiler creates a static literal string and copies it to str[], or just initializes str[] to "Hello" without creating a static literal string. The problem is that str[] goes away in the second case. In the first case, the function returns a pointer to the static literal string "Hello", and although str no longer exists, the pointer returned is still valid because "Hello" is a static literal string. The proper syntax would be

const char * str = "Hello";
 
  • #21
Jamin2112 said:
Critique my answer:

Code:
unsigned int countOneBits(int num) { 
   unsigned int count;
   for (unsigned int i = 0; i < sizeof(int) * 8; i++) { 
         count += (num % 2 == 1 ? 1 : 0);
         num = num /= 2;
   } 
   return count;
}
Several problems here:

1. You didn't initialize count to anything, so its value is unpredictable. You have to initialize it to zero.

2. sizeof(int) * 8 assumes that the architecture uses 8-bit bytes. Believe it or not, there are architectures (such as specialized DSP processors) where this is not true.

3. Your num parameter is a signed integer. Your calculation may not work if num is negative, because the behavior of the % operator with a negative operand is implementation-defined. The input should be an unsigned int or unsigned long.
 
  • #22
Jamin2112 said:
I think I will need some additional memory to do this because I need a temporary placeholder for a character.
Yes, it's no problem to use temporary local variables. But don't create stuff using new or malloc unless you verify that it's OK with the interviewer. This is not an arbitrary restriction: on some platforms (e.g. if you're writing a low level application for a cell phone) you aren't allowed to use new/malloc at all. And even where it's acceptable, it is a resource leak waiting to happen if not done carefully.
Code:
string revString(string str) { 
    char temp; 
    for (unsigned int i = 0; i < str.length(); i++) { 
        temp = str[i];
        str[i] = str[str.length() - i - 1];
        str[str.length() - i - 1] = temp;
    }
    return str;
}
This doesn't work because your loop iterates across the entire string. Think about this - you will exchange the first and last character TWICE, so they will end up where they started.

Aside from that, here are some critiques:

1. You are unnecessarily making two copies of str: once when it is passed to you as an argument, and once when you return it. You can avoid both of these copies by changing the function so it accepts a reference to the string:

Code:
void revString(string &str)

2. "temp" can be defined inside the "for" loop since it is not used outside the loop. It's good practice to define local variables to have the smallest scope possible.

3. You can use iterators instead of the integer index. This makes it less likely that you will get the indexing wrong and write outside the array.
 
  • #23
jbunniii said:
Several problems here:

1. You didn't initialize count to anything, so its value is unpredictable. You have to initialize it to zero.

2. sizeof(int) * 8 assumes that the architecture uses 8-bit bytes. Believe it or not, there are architectures (such as specialized DSP processors) where this is not true.

3. Your num parameter is a signed integer. Your calculation may not work if num is negative, because the behavior of the % operator with a negative operand is implementation-defined. The input should be an unsigned int or unsigned long.

1. Sorry. I knew that.

2. True, true.

3. Yea, I redid it later in this thread to correct for the problem you mention.
 
  • #24
Jamin2112 said:
Just to be clear: So I should take an array of unique numbers and rearrange them from least to greatest?

Code:
double* SortNumbers(double* arr, unsigned int size) { 
   // move around stuff in arr
   return arr; 
}
Right, but they don't necessarily need to be unique. Also, you don't need to return the pointer. You can do it like this, again modifying "arr" in place:
Code:
void SortNumbers(double* arr, unsigned int size)
 
  • #25
jbunniii said:
This doesn't work because your loop iterates across the entire string. Think about this - you will exchange the first and last character TWICE, so they will end up where they started.

Wow. I'm an idiot. But I think I know an easy fix. I just change it the condition of the for loop to str.length() / 2.

1. You are unnecessarily making two copies of str: once when it is passed to you as an argument, and once when you return it. You can avoid both of these copies by changing the function so it accepts a reference to the string:

Code:
void revString(string &str)

Yes. I'll redo this.

2. "temp" can be defined inside the "for" loop since it is not used outside the loop. It's good practice to define local variables to have the smallest scope possible.

Thanks for the tip. I'll make sure to do this.

3. You can use iterators instead of the integer index. This makes it less likely that you will get the indexing wrong and write outside the array.

I'll do this too.
 
  • #26
Ok, here's the string reversal:


Code:
#include <iostream>


void ReverseString(string &str) { 
     for (unsigned int i = 0; i < str.length() / 2; i++) { 
        char temp = str[i];
        str[i] = str[str.length() - i - 1]; 
        str[str.length() - i - 1] = temp;
     } 
} 



int main() { 

string s = "Jamin"; 
cout << s << endl;
ReverseString(s);
cout << s;

return 0;
}

Output:

Jamin
nimaJ
 
  • #27
Jamin2112 said:
Output:

Jamin
nimaJ
Looks good to me.
 
  • #28
Jamin2112 said:
Ok, here's the string reversal:
You are calling str.length() *three* times every pass of the loop. Certainly you can do better than that!

I've noticed you aren't using pointer arithmetic very much. The C++ purists will say don't. Your interviewers will most likely say DO. They will want to know whether you understand why the following is the canonical form of a C-style string copy:
Code:
char * strcpy (char * target, char * source) {
   char* ret = target;
   while (*target++ = *source++);
   return ret;
}
 
Last edited:
  • #29
count 1 bits ..

This isn't allowed in some older version of C (ones still using C89 standard).

Code:
   for (unsigned int i = 0; ...

Instead you need to delcare variables (and optionally initialize them) at the start of a function:

Code:
   int i;
   for (i = 0; ...

Alternative method for counting 1 bits:

Code:
int countOneBits(unsigned long num)
{ 
int count = 0;

    while(num){
        count += 1;
        num &= num-1;
    }
    return(count);
}
 
Last edited:
  • #30
rcgldr said:
This normally isn't allowed in C:
Normally? For which millennium are you normally writing code?

For loops with declarations have been part of the C standard since 1999.

Admittedly, a lot of compilers are stuck in the 1989 standard, or before. They never moved up to C99, let alone to the newest version of the standard (2011). Case in point: The GNU compiler suite developers are doing their best to stay current or even ahead of the game with respect to C++. That is not the case with C.
 
  • #31
D H said:
Admittedly, a lot of compilers are stuck in the 1989 standard, or before. They never moved up to C99, let alone to the newest version of the standard (2011). Case in point: The GNU compiler suite developers are doing their best to stay current or even ahead of the game with respect to C++. That is not the case with C.
I have been assuming that the OP is writing in C++ due to the use of "string", even if he is mostly speaking in a low-level dialect. If my assumption is incorrect then I retract my earlier suggestions to use references, iterators, etc. Jamin: which is it, C or C++?

P.S. I use Visual C++ at work. Its C compiler STILL doesn't support C99.
 
  • #32
D H said:
Normally? For which millennium are you normally writing code? For loops with declarations have been part of the C standard since 1999. Admittedly, a lot of compilers are stuck in the 1989 standard, or before.
Just wanted to be sure on this. I updated my prevoius post. Some compilers still use the C89 standard (visual studio 2005 for example). I don't know what the work interview will be expecting. In any case, it's not going to cause problems if all function variable declarations are put at the start of a program.
 
  • #33
rcgldr said:
Just wanted to be sure on this. I updated my prevoius post. Some compilers still use the C89 standard (visual studio 2005 for example). I don't know what the work interview will be expecting. In any case, it's not going to cause problems if all function variable declarations are put at the start of a program.
I probably wouldn't penalize someone for doing that in an interview, but I would probably draw the line at pre-C89 function definitions. Remember these dark days?

Code:
int countOneBits(num)
unsigned long num;
{ 
    ...
}
(In fact, even "unsigned long" may not have been universally supported at the time...)
 
  • #34
D H said:
You are calling str.length() *three* times every pass of the loop. Certainly you can do better than that!

I've noticed you aren't using pointer arithmetic very much. The C++ purists will say don't. Your interviewers will most likely say DO. They will want to know whether you understand why the following is the canonical form of a C-style string copy:
Code:
char * strcpy (char * target, char * source) {
   char* ret = target;
   while (*target++ = *source++);
   return ret;
}

Yea, I know, I should've just done unsigned in len = str.length() in the beginning of the function and then used that variable len throughout. I'll make a final draft of everything by the end of today.

In the code you posted, the function is taking two pointers to characters, then continuing to increment both pointers via pointer arithmetic and with each increment setting the dereferenced value at target equal to the dereferenced value at source. That while loop terminates as soon as source points to no value at all.
 
  • #35
jbunniii said:
Jamin: which is it, C or C++?

Oh, my 4-hr interview is Java, but I'm trying to rehash some C++ knowledge just in case they ask.
 

Similar threads

  • Programming and Computer Science
Replies
4
Views
602
  • Programming and Computer Science
Replies
3
Views
2K
  • Programming and Computer Science
Replies
2
Views
1K
  • Programming and Computer Science
Replies
31
Views
2K
  • Programming and Computer Science
3
Replies
89
Views
4K
  • Programming and Computer Science
Replies
19
Views
970
  • Programming and Computer Science
Replies
1
Views
1K
  • Programming and Computer Science
Replies
17
Views
3K
  • Programming and Computer Science
Replies
17
Views
2K
  • Programming and Computer Science
Replies
4
Views
1K
Back
Top