如何在 c 中正确实现 strcpy?



根据这个: strcpy vs strdup, strcpy 可以通过循环实现,他们使用了这个while(*ptr2++ = *ptr1++).我尝试做类似的事情:

#include <stdio.h>
#include <stdlib.h>
int main(){
char *des = malloc(10);
for(char *src="abcdef";(*des++ = *src++););
printf("%sn",des);
}

但这不会打印任何内容,也没有错误。出了什么问题?

非常感谢您的回答,我已经玩了一点,并决定如何最好地设计循环以查看复制如何逐字节进行。这似乎是最好的:

#include <stdio.h>
#include <stdlib.h>
int main(){
char *des = malloc(7);
for(char *src="abcdef", *p=des; (*p++=*src++); printf("%sn",des));
}

在此循环中

for(char *src="abcdef";(*des++ = *src++););

正在更改目标指针des。因此,在循环之后,它不会指向复制字符串的开头。

请注意,显式终止零字符''在字符串文本中是多余的。

循环可以如下所示

for ( char *src = "abcdef", *p = des; (*p++ = *src++););

然后在循环之后

puts( des );

free( des );

您可以编写类似于strcpy以下方式的单独函数

char * my_strcpy( char *des, const char *src )
{
for ( char *p = des; ( *p++ = *src++ ); );
return des;
}

并称它为像

puts( my_strcpy( des, "abcdef" ) )'
free( des );

您正在递增des因此在循环结束时自然地指向字符串的末尾,打印它相当于未定义的行为,您必须将其带回des的开头。

#include <stdio.h>
#include <stdlib.h>
int main(){
int count = 0;
char *des = malloc(10);
if(des == NULL){
return EXIT_FAILURE; //or otherwise handle the error
}
// '' is already added by the compiler so you don't need to do it yourself
for(char *src="abcdef";(*des++ = *src++);){
count++; //count the number of increments
}
des -= count + 1; //bring it back to the beginning
printf("%sn",des);
free(dest); //to free the allocated memory when you're done with it
return EXIT_SUCCESS;
}

或者创建一个指向des开头的指针并打印它。

#include <stdio.h>
#include <stdlib.h>
int main(){

char *des = malloc(10);
if(des == NULL){
return EXIT_FAILURE; //or otherwise handle the error
}
char *ptr = des;
for(char *src="abcdef";(*des++ = *src++);){} //using {} instead of ;, it's clearer
printf("%sn",ptr);
free(ptr) // or free(dest); to free the allocated memory when you're done with it
return EXIT_SUCCESS;
}

printf("%sn",des);未定义的行为(UB(,因为它尝试从写入分配内存的字符串末尾开始打印。

复制字符串

保存原始指针,检查它并在完成后释放。

const char *src = "abcdef"; // string literal here has 2 ending ``, 
char *dest = malloc(strlen(src) + 1);  // 7
char *d = dest;
while (*d++ = *src++);
printf("%sn", dest);
free(dest);

复制字符串文本

const char src[] = "abcdef"; // string literal here has 2 ending ``, 
char *dest = malloc(sizeof src);  // 8
for (size_t i = 0; i<sizeof src; i++) {
dest[i] = src[i];
}
printf("%sn", dest);
free(dest);

你只需要记住原来分配的指针。

不要在主中编程。使用函数


#include <stdio.h>
#include <stdlib.h>
size_t strSpaceNeedeed(const char *str)
{
const char *wrk = str;
while(*wrk++);
return wrk - str;
}
char *mystrdup(const char *str)
{
char *wrk;
char *dest = malloc(strSpaceNeedeed(str));
if(dest)
{
for(wrk = dest; *wrk++ = *str++;);
}   
return dest;
}
int main(){
printf("%sn", mystrdup("asdfgfd"));
}

甚至更好

size_t strSpaceNeedeed(const char *str)
{
const char *wrk = str;
while(*wrk++);
return wrk - str;
}
char *mystrcpy(char *dest, const char *src)
{
char *wrk = dest;
while((*wrk++ = *src++)) ;
return dest;
}
char *mystrdup(const char *str)
{
char *wrk;
char *dest = malloc(strSpaceNeedeed(str));
if(dest)
{
mystrcpy(dest, str);
}   
return dest;
}
int main(){
printf("%sn", mystrdup("asdfgfd"));
}

分配目标缓冲区des并将源字符串正确复制到适当的位置。但是,由于您为复制的每个字符递增des,因此您已将des从字符串的开头移动到末尾。当您打印结果时,您正在打印最后一个字节,即 nil 终止,它是空的。

相反,您需要保留指向字符串开头的指针,以及指向您复制的每个字符的指针。

与原始来源的最小变化是:

#include <stdio.h>
#include <stdlib.h>
int main(){
char *des = malloc(10);
char *p = des;
for(char *src="abcdef";(*p++ = *src++););
printf("%sn",des);
}

因此p是指向下一个目标字符的指针,并沿字符串移动。但是您打印的最后一个字符串是des,从分配开始。

当然,您还应该为des分配strlen(src)+1字节。并且没有必要以 null 终止字符串文字,因为这将由编译器为您完成。

但这不会打印任何内容,也没有错误。出了什么问题?

des在执行(*des++ = *src++)后不再指向字符串的开头。实际上,des指向NUL字符之后的一个元素,该元素将终止字符串。

因此,如果要使用printf("%sn",des)打印字符串,它将调用未定义的行为。

您需要将"start"指针的地址值(指向分配的内存块的第一个char对象(存储到临时的"持有者"指针中。有多种可能的方法。

#include <stdio.h>
#include <stdlib.h>
int main (void) {
char *des = malloc(sizeof(char) * 10);
if (!des)
{
fputs("Error at allocation!", stderr);
return 1;
}
char *tmp = des;
for (const char *src = "abcdef"; (*des++ = *src++) ; );
des = temp;
printf("%sn",des);
free(des);
}

选择:

#include <stdio.h>
#include <stdlib.h>
int main (void) {
char *des = malloc(sizeof(char) * 10);
if (!des)
{
fputs("Error at allocation!", stderr);
return 1;
}
char *tmp = des;
for (const char *src = "abcdef"; (*des++ = *src++) ; );
printf("%sn", tmp);
free(tmp);
}

#include <stdio.h>
#include <stdlib.h>
int main (void) {
char *des = malloc(sizeof(char) * 10);
if (!des)
{
fputs("Error at allocation!", stderr);
return 1;
}
char *tmp = des;
for (const char *src = "abcdef"; (*tmp++ = *src++) ; );
printf("%sn", des);
free(des);
}
<小时 />

旁注:

  • "abcdef"- 不需要显式。它会在翻译过程中自动附加。使用"abcdef"

  • 如果分配成功,请始终通过检查返回的空指针来检查内存管理函数的返回。

  • 通过const限定指向字符串文本的指针,以避免意外的写入尝试。

  • 在调用 malloc 时使用sizeof(char) * 10而不是普通10。这可确保在类型更改时写入大小。

  • int main (void)而不是int main (void).第一个符合标准,第二个不符合标准。

  • 始终free()动态分配的内存,因为您不再需要分配的内存。在上面的示例中,这将是多余的,但是如果您的程序变大并且示例专注于部分,则应立即free()不需要的内存。

最新更新