在C中实现字符串复制功能

时间:2011-04-17 19:47:55

标签: c

在最近的一次面试中,我被要求实现自己的字符串复制功能。我设法编写了我认为有效的代码。然而,当我回到家中再次尝试这个问题时,我意识到它比我想象的要复杂得多。这是我提出的代码:

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

char * mycpy(char * d, char * s);

int main() {

  int i;
  char buffer[1];

  mycpy(buffer, "hello world\n");
  printf("%s", buffer);

  return 0;
}

char * mycpy (char * destination, char * source) {

  if (!destination || !source) return NULL;

  char * tmp = destination;

  while (*destination != NULL || *source != NULL) {
    *destination = *source;
    destination++;
    source++;
  }

  return tmp;
}

我在网上看了一些其他的例子,发现因为C中的所有字符串都是以null结尾的,所以我应该读取空字符,然后在退出之前将空字符附加到目标字符串。

然而,我很好奇的一件事是如何处理内存。我注意到如果我使用了strcpy()库函数,我可以将一个10个字符的字符串复制到一个大小为1的char数组中。这怎么可能? strcpy()函数是否以某种方式为目标分配了更多内存?

9 个答案:

答案 0 :(得分:9)

良好的面试问题有几个层次,候选人可以向其展示不同层次的理解。

在句法“C语言”层上,以下代码来自经典的Kernighan和Ritchie书('The C programming language'):

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

在一次采访中,你确实可以指出这个功能并不安全,最值得注意的是*dest上的缓冲区不够大。此外,可能存在重叠,即如果dest指向src缓冲区的中间,则会有无限循环(最终会产生内存访问错误)。

答案 1 :(得分:2)

不,我认为strcpy()不安全,并且在它之后覆盖了内存。您应该使用strncpy()代替。

答案 2 :(得分:2)

正如其他答案所说,你正在覆盖缓冲区,所以为了你的测试改变它:

char buffer[ 12 ];

对于面试,他们可能希望:

char *mycpy( char *s, char *t )
{
    while ( *s++ = *t++ )
    {
        ;
    }
    return s;
}

答案 3 :(得分:1)

不,你正在写缓冲区并覆盖(在这种情况下)堆栈的其余部分超过缓冲区。这是非常危险的行为。

通常,您应始终创建提供限制的方法。在大多数C库中,这些方法在方法名称中用n表示。

答案 4 :(得分:0)

C不像其他语言(C#,Java等)那样执行任何运行时边界检查。这就是为什么你可以写出数组末尾的东西。但是,在某些情况下,您将无法访问该字符串,因为您可能正在侵占不属于您的内存,从而导致出现分段错误。 K&amp; R是学习这些概念的好书。

答案 5 :(得分:0)

strcpy()函数完全放弃了内存管理,因此所有分配都需要在调用函数之前完成,并在必要时释放。如果源字符串的字符数多于目标缓冲区,则strcpy()将继续将缓冲区的末尾写入未分配的空间,或者写入为其他内容分配的空间。

这可能非常糟糕。

strncpy()strcpy()的工作方式类似,不同之处在于它允许您传递一个描述缓冲区大小的附加变量,因此该函数将在达到此限制时停止复制。这样更安全,但仍然依赖于调用程序来正确分配和描述缓冲区 - 如果提供的错误长度,它仍然可以超过缓冲区的末尾,从而导致相同的问题。

答案 6 :(得分:0)

char * mycpy (char * destination, char * source) {

  if (!destination || !source) return NULL;

  char * tmp = destination;

  while (*destination != NULL || *source != NULL) {
    *destination = *source;
    destination++;
    source++;
  }

  return tmp;
}

在上面的复制实现中,您的tmp和目标具有相同的数据。更好的是你不要后退任何数据,而是让目的地成为你的out参数。你能改写一下吗?

答案 7 :(得分:0)

以下版本适合我。我不确定它是不是很糟糕的设计:

while(source[i] != '\0' && (i<= (MAXLINE-1)))
{
dest[i]=source[i];
++i;
}

答案 8 :(得分:-1)

一般情况下,尽可能使用const修饰符是个好主意,例如 source 参数。