在C中实现字符串复制function

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

#include  #include  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()函数以某种方式为目标分配更多内存吗?

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

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

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

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

不,这是strcpy()不安全,并且在它之后覆盖了内存,我想。 你应该使用strncpy()代替。

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

 char buffer[ 12 ]; 

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

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

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

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

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

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

这可能非常糟糕。

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

 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参数。 你能改写一下吗?

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

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

一般来说,在可能的情况下使用const修饰符总是一个好主意,例如对于source参数。