面试问题 - 在C中不使用strcat连接两个字符串

时间:2010-09-26 13:31:20

标签: c string

最近我参加了一次采访,他们让我写了一个C程序来连接两个字符串而不使用strcat()strlen()strcmp(),该函数不应超过两(2)线。

我知道如何在不使用strcat()的情况下连接两个字符串。但我的方法有近15行。我不知道怎么写两行。

10 个答案:

答案 0 :(得分:20)

我希望他们想要这样的东西:

void mystrcat(char * dest, const char * src)
{
    //advance dest until we find the terminating null
    while (*dest) ++dest;

    //copy src to dest including terminating null, until we hit the end of src
    //Edit: originally this: 
    //for (; *dest = *src, *src; ++dest, ++src);
    //...which is the same as this
    for (; *dest = *src; ++dest, ++src);
}

它不会像真正的strcat那样返回连接字符串的结尾,但似乎并不需要。

我不一定知道这种事情是否是一个很好的面试问题 - 它表明你可以简洁地编码,并且你知道strcat做了什么,但那就是它。

编辑:正如aib所写,声明

while (*dest++ = *src++);

...可能是编写第二个循环的一种更传统的方式(而不是使用for)。

答案 1 :(得分:17)

鉴于任务是连接两个字符串,而不是创建strcat的副本,我会选择创建一个全新字符串的简单选项,该字符串是两者的组合。

char buffer[REASONABLE_MAX] = {0};
snprintf(buffer, REASONABLE_MAX - 1, "%s%s", string1, string2);

答案 2 :(得分:6)

这个问题的正确答案是,这个问题会证明一项技能是不好的。他们希望您展示编写黑客代码的能力。他们希望你发明自己的每个C编译器提供的东西实现,这是浪费时间。他们希望您编写简化的代码,根据定义,这些代码是不可读的。如果它更具可读性,那么15行实现可能会更好。大多数项目都没有失败,因为开发人员浪费了150个时钟周期。有些人失败了,因为有人写了不可维护的代码。如果你必须写那个,那就需要15行评论。所以我对此的回答是,向我展示保护不需要使用标准库并需要最佳解决方案的性能指标。花在设计和收集性能指标上的时间要好得多。

永远不要忘记 - 你也在采访他们。

 //assuming szA contains "first string" and szB contains "second string"
 //and both are null terminated
 //  iterate over A until you get to null, then iterate over B and add to the end of A
 //  and then add null termination to A
 //  WARNING:  memory corruption likely if either string is not NULL terminated
 //  WARNING:  memory corruption likely if the storage buffer for A was not allocated large
 //            enough for A to store all of B's data
 //  Justification:  Performance metric XXX has shown this optimization is needed
 for(int i=0; szA[i]!='\0'; i++); 
 for(int j=0; (j==0)||(szB[j-1]!='\0'); j++) szA[i+j] = szB[j];

* edit,9/27/2010

在阅读了其他一些解决方案后,我认为以下可能是最佳代码答案:

 //Posted by Doug in answer below this one
 void my_strcat(char * dest, const char * src)
 {    
      while (*dest) ++dest;    
      while (*dest++ = *src++);     
 }

但我会用一个安全版本来跟进:

 void my_safe_strcat(char * dest, const unsigned int max_size, const char * src)
 {
      int characters_used=0;
      while (*dest) { ++dest; characters_used++; }
      while ( (characters_used < (max_size-1) ) && (*dest++ = *src++) ) characters_used++;
      *dest = 0; //ensure we end with a null
 }

然后跟着(完整答案,哪个编译器将优化与上面相同,以及应用程序是真正的问题):

void my_readable_safe_strcat(char * dest, const unsigned int max_size, const char * src)
{
    unsigned int characters_used = 0;
    while (*dest != '\0') 
    { 
        ++dest; 
        characters_used++;   
    }
    while ( (characters_used < (max_size-1) ) && (*dest = *src) ) 
    {
        dest++;
        src++;
        characters_used++;
    }
    *dest = 0; //ensure we end with a null
}



int _tmain(int argc, _TCHAR* argv[])
{
    char szTooShort[15] = "First String";
    char szLongEnough[50] = "First String";
    char szClean[] = "Second String";
    char szDirty[5] = {'f','g','h','i','j'};

    my_readable_safe_strcat(szTooShort,15,szClean);
    printf("This string should be cut off:\n%s\n\n",szTooShort);

    my_readable_safe_strcat(szLongEnough,50,szClean);
    printf("This string should be complete:\n%s\n\n",szLongEnough);

    my_readable_safe_strcat(szLongEnough,50,szDirty);
    printf("This string probably has junk data in it, but shouldn't crash the app:\n%s\n\n",szLongEnough);

}

答案 3 :(得分:5)

两行? Bwah ...

void another_strcat(char* str1, const char* str2)
{
    strcpy(strchr(str1, '\0'), str2);
}
编辑:我非常沮丧,人们如此反对strcpy和strchr。 Waah!所以,我以为我会遵守规则的精神:

char thing(char* p, const char* s)
{
    return *p ? thing(&p[1], s) : *s ? (*p++ = *s++, thing(p, s)) : *p = '\0';
}

我仍然无法理解任何人如何选择2条整线;-P。

答案 4 :(得分:3)

我在VS2008中测试了这个位,它工作正常。

void NewStrCat(char* dest, const char* src)
{
    while (*dest) ++dest;
    while (*dest++ = *src++);
}

答案 5 :(得分:2)

只需移除所有\n

,即可使任何功能适合一行

但是,我认为你正在寻找这个答案:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(void)
{
    char string1[32] = "Hello";
    char string2[] = ", World!";

    char *dst = string1 + strlen(string1);
    char *src = string2;

    while (*dst++ = *src++); //single statement

    printf("\"%s\"\n", string1);

    return EXIT_SUCCESS;
}

解释相当简单:

src++返回指向当前正在复制的字符的指针,然后递增以指向下一个字符。 *取消引用此指针,LHS上的类似表达式将其复制到dst。整个=表达式的结果是复制的字符,因此简单while将其循环,直到遇到并复制\0为止。

然而:

strcat()更容易阅读,可能更快。只有在strcat()不可用时,任何其他解决方案才可行。 (或者当你正在接受采访时,显然。) 并将上面的strcat()替换为strncat(),除非您确实确定目标字符串足够大。

编辑:我错过了关于strlen()被禁止的部分。这是双语句函数:

void my_strcat(char * restrict dst, const char * restrict src)
{
    while (*dst) ++dst;      //move dst to the end of the string
    while (*dst++ = *src++); //copy src to dst
}

请注意,标准strcat()函数会返回dst的原始值。

答案 6 :(得分:1)

一行:

sprintf(string1, "%s%s", string1, string2);

(请注意,这可能会调用未定义的行为。)

<强>附录

ISO C99标准规定:
如果在重叠的对象之间进行复制,则行为未定义。

话虽如此,上面的代码仍然可能正常工作。它适用于MS VC 2010。

答案 7 :(得分:0)

void StringCatenation(char *str1,char *str2)
        {
          int len1,i=0;
          for(len1=0;*(str1+len1);len1++);
          do{
            str1[len1+i]=str2[i];
            i++;
            }
            while(*(str2+i);
        }

答案 8 :(得分:0)

我觉得这些问题意味着消除问题而不是选择。根据这些令人费解的问题而不是通过向他们提出更真实的问题来选择候选人,更容易消除他们的候选人。 我只是一个咆哮,因为我也在寻找工作并面对这样的问题,并回答了其中的一些,感谢SO!

答案 9 :(得分:0)

void my_strcat(char* dest, const char* src)
{
    while (*dest) ++dest;
    while (*dest++ = *src++);
    *dest = '\0';
}

目标字符串必须以NULL终止结束。