Bloomberg LP Interview Question
Country: United States
Interview Type: In-Person
for 3.
eugene.yarovoi's solution is the right answer.
if u allocate memory inside the function, u need someone
reclaim them later,that is not what the interview want
"eugene.yarovoi's solution is the right answer."
Someone actually did bring up a legitimate objection to my answer (namely, that the signature ought to be changed to return const char* if one implements my solution). It might still be the best way to go on this question, though (see the comments to my answer).
char * test(int v)
{
switch(v)
{
case 1: return "Case 1";
case 2: return "Case 2";
case 3: return "Case 3";
default: return "Default";
}
}
That technically does make those strings implicit global variables, but I think this is probably what your interviewer wanted.
yeah so thats obviously not the answer as the type of a literal string is char const * not char *
although i gotta tell you gcc -Wall didn't even mention it. Which means if you modified one character of the returned string (which the type suggests one can do) then it would compile (gcc 4.6.2) with no warnings and will segfault at runtime.
The other candidate solution i saw here is mallocing which will obviously leak.
The only sane solution is switching to a fully functional lazy language like Haskell and forget all about this garbage.
I still stand by my earlier statement that my solution is likely to be what the interviewer was looking for. I wouldn't say it's "obviously not the answer".
Your point is valid though -- if this approach is to be used, this function should really be returning a const char*, lest the user inadvertently modify the values. The documentation (if it were to exist) can help here, of course.
"The only sane solution is switching to a fully functional lazy language like Haskell and forget all about this garbage."
I would say that is the least sane solution. So if you're working on a C codebase, you would switch to Haskell just because you're annoyed not all types are immutable in C? Simple problems merit simple solutions.
"you would switch to Haskell just because you're annoyed not all types are immutable in C?"
ad hominem much?
first i would explain the interviewers why the expected answers are all wrong.
then i would explain them how these problems don't ever arise in a functional language.
i'd go on to describe the gajillion advantages of functional languages (massive code reuse, referential transparency, safety, piece-of-cake concurrency and much MUCH more)
finally i would debunk their rebuttal that functional languages are inefficient and would call them morons for not doing their homework.
then i'd be kicked out of the building. oh well
you can use extern or define the array allocated at runtime as pointer and return the address....
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <conio.h>
char * test(int v)
{
char *buf;
buf=(char *)malloc(7);
memset(buf,' ',6);
switch(v)
{
case 1:
strncpy(buf, "Case 1", strlen(buf));
break;
case 2:
strncpy(buf,"Case 2", strlen(buf));
break;
case 3:
strncpy(buf, "Case 3", strlen(buf));
break;
default:
strncpy(buf, "defult", strlen(buf));
}
return buf;
}
int main()
{
char *p = test(2);
printf("%s",p);
getch();
}
Just 2 bugs:-
1. There's nothing like case default ... Its just default
2. char buf[] is an array ... when we refer to buf, it means an address ... We cannot return an address of an address ... So instead of return &buf ... We should have return return buf
# include <iostream.h>
char * test(int v)
{
char buf[6+1];
switch(v)
{
case 1: strncpy(buf, "Case 1", sizeof(buf));
case 2: strncpy(buf,"Case 2", sizeof(buf));
case 3: strncpy(buf, "Case 3", sizeof(buf));
default: strncpy(buf, "Default", sizeof(buf));
}
return buf;
}
int main()
{
char * p = test(2);
cout<<p<<endl;
return 0;
}
I know the Bloomberg guys. They don't care about wrong style of programming. They want to know what EXACTLY happens when you compile/run the program.
In this program there are two compilation errors:
1. case default
2. return &buf
If you fix these errors, what happens in the run-time?
case2, case 3, default -- will be all executed, as no break statements.
Each time different string copied into buf, but each time buf length is not exceeded, so its OK.
After the function returns, buf is deleted from the stack, as it was a local variable. Pointer p will point to some location in the stack (where previously resided buf).
Now operator cout will try to access (read) memory pointed by p.
cout 'thinks' p is char*, so it will try reading *p, *(p+1), etc. until it reaches null character.
So let's think: what resides in the stack where p points?
Before call to test the stack looks like:
ptr to char* p
----BOTTOM OF STACK ----
inside 'test' the stack looks like:
buf [7]
int param
return ptr of 'test'
ptr to char* p
----BOTTOM OF STACK ----
after 'test' returns, p will point on top of the stack (where previously resided buf[7]).
now at this location will reside ptr p itself!
So p will point on itself. The operator cout << will try to read null-terminated string from p.
So it will access *p, *(p+1), *(p+2), ... until it reaches byte with value zero.
As the stack in our case is really small: it contains only pointer p (which is 4 bytes), and this pointer probably does not contain any zero bytes, then segmentation fault will occur, because cout << will try to read memory beyond the bottom of the stack and the process will crash.
(In kernel mode, the process would probably not crash, but continue reading bytes untill zero byte reached).
#include <iostream>
#include<cstring>
using namespace std;
char buf[7];
char * test(int v)
{
switch(v)
{
case 1: strcpy(buf, "Case 1");break;
case 2: strcpy(buf,"Case 2"); break;
case 3: strcpy(buf, "Case 3");break;
default: strcpy(buf, "Default");
}
return buf;
}
int main()
{
char * p = test(2);
cout << p << endl;
return 0;
}
The answer about the stack is the closest, however the conclusion is wrong. *p is going to point to the right string, however it is destroeyd when calling any function, like <<. So we should first save it and then call <<:
char * test(int v)
{
char buf[6 + 1 +1];
switch (v)
{
case 1: strncpy(buf, "Case 1", sizeof(buf));
case 2: strncpy(buf, "Case 2", sizeof(buf));
case 3: strncpy(buf, "Case 3", sizeof(buf));
default: strncpy(buf, "Default", sizeof(buf));
}
return buf;
}
int main()
{
char * p = test(2);
char tmpCopy[10];
for (int i = 0; i < 8; i++)
tmpCopy[i] = p[i];
cout << tmpCopy << endl;
return 0;
}
I noticed the following issues:
1. No break statement used. So the value in buf will get over-written by case statements below 2. How to fix: use break after each case.
2. In default case, strncpy will copy 7 characters (i.e. strlen("Default")) into buf without leaving any space for '\0'. This might create issues later if any string function is used on buf. How to fix: allocate more memory.
3. buf, being a local variable in the function, will be allocated memory in the stack. After the function returns, the contents of the stack associated with this function will be popped and buf would be referring to an address which is not valid anymore. How to fix: allocate memory for buf using either malloc or new and return this address (as shown below):
4. The word 'default' is spelt incorrectly :D
- Jester December 29, 2011