12

Yesterday I was at interview and was asked to implement strlen() in C without using any standard functions, all by hands. As an absolute amateur, I implemented primitive version with while loop. Looking at this my interviewer said that it can be implemented at just one line of code. I wasn't be able to produce this code using that term at that moment. After interview I asked my colleagues, and the most experienced from them gave me this piece which really worked fine:

size_t str_len (const char *str)
{
    return (*str) ? str_len(++str) + 1 : 0;
}

So there is a question, is it possible without using recursion, and if yes, how? Terms:

  • without any assembler
  • without any C functions existed in libraries
  • without just spelling few strings of code in one

Please, take note that this is not the question of optimization or real using, just the possibility of make task done.

Olex
  • 1,656
  • 3
  • 20
  • 38
  • 5
    This is probably better for code golf – Anya Shenanigans Mar 19 '14 at 23:32
  • 5
    "One line" is a pretty loose requirement. – hatchet - done with SOverflow Mar 19 '14 at 23:36
  • 7
    Being able to implement strlen () in a single line is rather pointless. I'd never ask anyone to do that in an interview or otherwise. – gnasher729 Mar 19 '14 at 23:40
  • 2
    @gnasher729: Agreed. Then again, most interview "puzzle" questions are pretty pointless except as an opportunity to watch how the candidate's mind works... assuming they don't already have an answer on tap, in which case it tells you nothing except that they have some experience. – keshlam Mar 19 '14 at 23:42
  • @keshlam, agree with you. Looks like it was the case to see my behavior in this situation – Olex Mar 19 '14 at 23:46
  • 2
    In C++ you could use tail recursion: `size_t strlen(const char *str, size_t acc = 0) { return *str ? strlen(str+1, acc + 1) : acc; }` That *should* be compiled to a loop I guess – Niklas B. Mar 20 '14 at 01:01

9 Answers9

16

Similar to @DanielKamilKozar's answer, but with a for-loop, you can do this with no for-loop body, and len gets initialized properly in the function:

void my_strlen(const char *str, size_t *len)
{
    for (*len = 0; str[*len]; (*len)++);
}
Digital Trauma
  • 15,475
  • 3
  • 51
  • 83
  • 2
    Ah, very clever! And so obvious. – Daniel Kamil Kozar Mar 19 '14 at 23:56
  • 2
    What about `for (*len = 0; *str; ++str, (*len)++);`? That way you don't have to dereference `len` to index into `str` on every iteration. – Remy Lebeau Mar 19 '14 at 23:58
  • @RemyLebeau Yep, that would work too. I guess if you were optimizing this, you'd need to profile which is fastest out of the deference or the additional increment. Either way the compiler would likely put both `str` and `len` in registers, so probably doesn't make much difference either way – Digital Trauma Mar 20 '14 at 00:06
  • 1
    strlen prototype is `size_t strlen (const char *str)` – technosaurus Jan 20 '17 at 18:59
  • 2
    This is not the same signature as strlen. – n. m. could be an AI Mar 19 '17 at 06:40
  • @RemyLebeau Usually the increment will effectively dereference `len` anyway. So it's the same, but none of it matters, because as long as `len` and `*str` are in L1, this will blaze through the string at basically max speed. – pmttavara Feb 17 '18 at 05:06
9

The best I could think of is this, but it's not the standard strlen since the function itself has a different prototype. Also, it assumes that *len is zero at start.

void my_strlen(const char *str, size_t *len)
{
        while(*(str++)) (*len)++;
}

I'm curious how a standard strlen might be implemented in "one line of code", because it's going to require a return, which is "one line of code", judging by what you've posted.

That said, I do agree with the comments saying that it's an incredibly dumb interview question.

Daniel Kamil Kozar
  • 18,476
  • 5
  • 50
  • 64
7
size_t str_len (const char *str)
{
    for (size_t len = 0;;++len) if (str[len]==0) return len;
}
Alexey Malistov
  • 26,407
  • 13
  • 68
  • 88
  • I would use this: `for (size_t len = 0; ; ++str, ++len) { if (!*str) return len; }` – Remy Lebeau Mar 20 '14 at 00:04
  • 1
    note the criteria: `without just spelling few strings of code in one` – Lie Ryan Mar 20 '14 at 00:43
  • Lines end with a newline.. you might be thinking of "statements" – M.M Mar 20 '14 at 01:39
  • 2
    **+1** Given how vaguely the question was formulated, I think, that's the best answer: it retains both functionality and signature of the `strlen()`, and it's arguably done in one line. – lapk Mar 20 '14 at 03:04
  • @MattMcNabb: technically you're correct, and the problem description definitely could be reworded to be more precise; but putting three statements into a single line clearly doesn't satisfy the intent of the question IMO. – Lie Ryan Mar 20 '14 at 04:53
  • @Liw Ryan: where do you see few strings? It is a single statement `for(... ; ... ; ...) ...;` – Alexey Malistov Mar 20 '14 at 08:07
  • @Alex: The implementation is quite obviously a single line of code. It's also a single statement. It consists of multiple expressions, but then so does your recursive implementation, which apparently fits the problem statement. This answer is really the only one that implements `strlen` in one line of code. Your accepted answer doesn't implement `strlen`, but rather something that can be called to calculate the length of a zero terminated string. – IInspectable Mar 03 '17 at 11:38
2

If this doesn't have to be a function, this one-liner is probably the simplest and shortest way to calculate the length of any null-terminated array (not including variable declarations and prints):

int main() {
    const char *s = "hello world";
    int n = 0;

    while (s[++n]);

    printf ("%i\n", n);
    return 0;
}

if it must be a function, then you can't have an exact function signature as strlen(), since a return have to be in separate line. Otherwise you can do this:

void my_strlen(int* n, const char* s) {
    while (s[++(*n)]);
}

int main() {
    const char *s = "hello world";
    int n = 0;

    my_strlen(&n, s);

    printf ("%i\n", n);
    return 0;
}
Lie Ryan
  • 62,238
  • 13
  • 100
  • 144
  • Your `while` loop counts the null terminator, so the length will always be +1 higher than what `strlen()` would return. You would have to use `while (s[n]) ++n;` instead to account for that. – Remy Lebeau Mar 20 '14 at 03:35
  • The fix introduced undefined behavior for strings of size 0. A string of size 0 is a valid string, and `strlen` doesn't fail for that case either. Remy Lebeau provided the correct solution. – IInspectable Mar 03 '17 at 11:27
  • Here are some other ways to solve it: `if (*s) while (s[++n]);`; `while (s[n++]); n--;`; `for (n = -1; s[++n];);`. – pmttavara Feb 18 '18 at 20:23
1

What about an empty for loop. Like

int i=0;
for(; str[i]!=0; ++i);
user1404617
  • 585
  • 1
  • 5
  • 20
1

This seems to work fine.

unsigned short strlen4(char *str)
{
    for (int i = 0; ; i++) if (str[i] == '\0') return i;
}

Any thoughts?

UPDATE!

This is probably the most efficient way of implementing strlen. Most compilers use this one implemented in one way or another.

This may be a little harder to understand especially if haven't learned pointers.

size_t strlen(char *str)
{
    register const char *s;
    for (s = str; *s; ++s);
    return(s - str);
}
ChrisK
  • 118
  • 8
0
size_t strlen (const char* str) {
    for (const char* s1 = str; ; s1++) if (!(*s1)) return s1 - str; 
}

In comparison to str[i], the above code that increments the pointer would perform better, because indexing str[i] would evaluate to: *(str + i) which is an addition operation done with every loop, while increment operation is faster.

Also, in comparison to the strlen(const char *str, size_t *len) there is no need for an extra parameter that the caller would provide.

Finally, it's on one line as per the original request.

  • While this code may answer the question, providing additional context regarding how and/or why it solves the problem would improve the answer's long-term value. – Donald Duck Mar 19 '17 at 11:05
  • In comparison to str[i], the code that increments the pointer would perform better, because indexing str[i] would evaluate to: *(str + i) which is an addition operation done with every loop, while increment operation is faster. Also, in comparison to the strlen(const char *str, size_t *len) there is no need for an extra parameter that the caller would provide. Finally, it's on one line as per the original request. – Tamer Mahfouz Mar 19 '17 at 22:26
  • Added to the answer. – Tamer Mahfouz Mar 20 '17 at 15:50
0

Contrary to what others say, it is impossible if some sensible restrictions are followed. The restrictions are:

  • one non-empty statement or declaration in the body of the function (a compound statement with a non-empty body is at least two statements in total)
  • same signature as the real strlen
  • no recursion

Any function with the signature of strlen must have a return statement. A return statement consists of the return keyword and an expression. The C language doesn't have expressions that perform loops. One need a statement for that, but this position is reserved for the return statement.

If one relaxes these restrictions (say, change the signature, or don't count return statements and/or declarations and/or bodies of compound statements as long as they are "simple", as separate "lines") the task becomes possible and rather straightforward, as can be seen in many examples here and all over the internet.o

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • How is `size_t strlen (const char *s) { for (auto p = s;; ++p) if (!*p) return p - s; }` not one statement? – pmttavara Feb 19 '18 at 04:40
  • @pmttavara I count three statements (for, if and return). And please call me when C has `auto`. – n. m. could be an AI Feb 19 '18 at 05:47
  • That's kind of an unworkably restrictive definition of a statement. – pmttavara Feb 19 '18 at 11:28
  • @pmttavara if you don't count nested statements as statements you can just wrap everything in a block and call it a day. – n. m. could be an AI Feb 19 '18 at 13:00
  • Those are not nested statements, they are compound statements. `p = s; p++;` is obviously two statements. `if (*p) p = s;` is a control statement with a simple statement. It's not like I'm saying "hey look it's one line because I deleted all the newlines". – pmttavara Feb 19 '18 at 18:55
0

Native Code

unsigned int strlen(const char *s)
{
    int l;for(l=0;s[l]!='\0';l++);return l;
}

You can replace '\0' with zero but i prefer as it

Hope it helps.