2009-05-21 143 views
2

最近我接受了采访,并要求编写mystrcat(*s1, *s2, *s3)其中s1s2是源字符串,连接结果由s3给出。我被告知,不要担心内存分配s3,并假设s1s2不是空值/无效字符串。所以我写了下面的蹩脚的(粗糙的)程序。我被告知s3有什么问题,或者s3可能出问题。你能告诉我这是/可能吗?我的连接函数mystrcat(char *,char *,char *)有什么问题?

void mystrcat(char *s1, char *s2, char *s3) 
{ 
    if (! (s1 || s2 || s3)) return; // one/more pointers are invalid 

    // copy string s1 into s3 
    while(*s1) { 
     *s3 = *s1; 
     s1++; 
     s3++; 
    } 

    // concatenate string s2 into s3 
    while(*s2) { 
     *s3 = *s2; 
     s2++; 
     s3++; 
    } 

    *s3 = '\0'; 
} 

你能告诉我这里有什么问题吗?更专业的做法是什么?

+0

我缺少结束paranthesis第一if语句,但我认为这只是一个现在发生的错字...? – 2009-05-21 22:03:57

+0

这是错字。更正..thnx – curiousone 2009-05-21 22:06:48

回答

5

这里将是我的意见

  • ,因为你没有修改它们的意图S1和S2都应该被输入到const char*
  • 您没有验证s3是否拥有足够的分配空间来包含s1和s2的组合长度
  • 当用户传入错误数据(NULL值)时,您正在失败。这是不好的,因为没有办法为呼叫者成功和失败的呼叫区分
  • 您的验证S1的方法,S2和S3不为空是不正确的(伊戈尔有它右)

问题我希望你在面试过程中要求或自我回答

  • 我该如何表达未能复制字符串?
  • 你想要一个精确的strcat克隆,还是更现代化的更好的参数验证?
  • 我可以使用其他标准str函数来完成答案吗?
7
if (! (s1 || s2 || s3) return; // one/more pointers are invalid 

应该

if ((!s1) || (!s2) || (!s3)) return; 
+1

或即使(!s1 ||!s2 ||!s3)返回;。什么与parens? – jmucchiello 2009-05-21 22:27:20

+3

jmucchiello:parens提高可读性(主观) – 2009-05-21 22:30:30

+3

高度主观。对我来说,它破坏了可读性。 – jmucchiello 2009-05-21 22:30:30

7

两个可能的点

首先,你被告知输入和otput指出,有效的字符串,因此可以说是不需要的有效性测试。如果需要的话,你应该听不到。更好的将是:

void mystrcat(char *s1, char *s2, char *s3) 
    { 
     ASSERT(s1); 
     ASSERT(s2); 
     ASSERT(s3); 
     .... 

然后基本上你写的strcat/strcpy的时候你可能会重用他们:

void mystrcat(char *s1, char *s2, char *s3) 
{ 
    strcpy(s3, s1); 
    strcat(s3, s2); 
} 

如果我是面试你的人比一个初级职位其他任何东西,我将有eexpected你指出我所指定的mystrcat接口是非常花钱设计的,并给出了你将如何改进它的细节。

2

除了之前的答案,还有一件事可能会出错: s3可能会指向s1或s2字符串的中间位置。如果这是一个合法的条件,那么你需要更复杂的实现。

0

如果我错了,请纠正我。复制s1后,s3的最后一个字符不会是'\ 0'吗?那么在某些情况下,s2中剩余的字符永远不会被读取?

从我的理解

while(*s3++ = *s1++); 

将复制的字符达到NULL,直到和“\ 0”不为空,或者它是这样处理?如果我可以假设s1 =“你好”和s2 =“世界!”然后在复制s1之后,s3看起来像:Hello \ 0,然后复制“world!” bit会导致s3看起来像:你好\ 0世界!\ 0

它是否有任何意义?我的理解是否正确?

1

对于你的函数定义有几点批评,但是在问题陈述的约束范围内你的函数会产生正确的答案。这在技术上不是错误的。

我的猜测是问题没有得到有效沟通,或者采访者的批评没有得到有效沟通。也许澄清这些是测试的一部分,呃?

这里有可能投诉的快速摘要...

  • 此行有一个逻辑上的错误...

    如果返回((S1 || S2 || S3)!);

...因为它会返回,如果所有是空的,但你可能要返回,如果任何为空。这不会导致失败,因为问题声明表示不能为空。

  • 上面提到的同一行在默默地失败。返回错误代码,抛出异常或断言会更好。无声故障是不好的做法,但仍然在技术上是正确的,因为考虑到问题的领域,该功能不会失败。
  • s1和s2可以为const char *类型,以提高可读性和效率(const可以帮助一些编译器优化)。
  • 修改参数变量通常被认为是不好的 的做法。 的另一个问题是可读性。
  • 您可以使用现有函数 strcpy和strcat。另一个问题 的可读性和效率。

一个伟大的程序员应该努力超越技术上的正确性,以提高可读性,效率和强大的错误处理能力,但这些主要是主观的和情境的。总之,不管你在第一个if语句中的错误,我认为你的函数读得不错,并完成工作。 (!(S1 || S2 || S3)):)

1
  1. 作废的支票

    如果回报; //一个或多个指针无效

    它实际上检查至少一个指针是否不为0,例如,至少有一个指针是有效的。 它应该是

    if(!s1 ||!s2 ||!s3)return;

  2. 您无法检查是否S3大 不够或者your're写作之外 (但前提是S3大 enougn权 - 但它仍然会 不是实时WORL工作)

  3. 您无法跳过 从s1 末尾复制到s3的空值。你在s3之后附加s2 所以它会结束 “s1stringvalueNULLs2stringvalue” (这里的NULL表示值为0或null或者 无实码,这是针对 的插图)。任何C方法, 期望空终止字符串将 只看到“s1stringvaluepart”和 将停在空。

这里有一个解决方案:

void mystrcat(char *s1, char *s2, char *s3) 
{ 
    if (!s1 || !s2 || !s3) return; 

    while (*s3++ = *s1++); 
    if (!*(s3-1)) --s3;    // reverse over null in s1 
    while (*s3++ = *s2++); 

    *s3 = 0; 
} 

你可以测试一下:

#include <iostream> 
using namespace std; 

int main() 
{ 
    char s1[] = "short"; 
    char s2[] = "longer"; 
    char s3[20]; 

    memset(s3, 0, sizeof(s3)); 
    mystrcat(0,s2,s3); 
    cout << "2: " << s3 << endl; 

    memset(s3, 0, sizeof(s3)); 
    mystrcat(s1,0,s3); 
    cout << "3: " << s3 << endl; 

    memset(s3, 0, sizeof(s3)); 
    mystrcat(s1,s2,0); 
    cout << "4: " << s3 << endl; 

    memset(s3, 0, sizeof(s3)); 
    mystrcat(s1,s2,s3); 
    cout << "1: " << s3 << endl; 

}