考虑strcpy
的实现:
void my_strcpy(char target[], char source[])
{
target = source;
}
int main(void)
{
char target[20];
char source[] = "Source String";
my_strcpy(target, source);
printf("Target: %s", target);
return 0;
}
这不起作用,这让我质疑我对C中的字符串和数组的理解。
以下是我的推理:target
和source
实际上只是指向数组的第一个元素的指针,即。 target == &target[0]
和source == &source[0]
。当我设置target = source
时,我将指针target
指向指针source
指向的同一内存地址。
现在当我printf
target
时,它还应该打印"Source String"
。但它没有。
有人可以解释原因吗?
答案 0 :(得分:8)
void my_strcpy(char target[], char source[])
{
target = source;
}
在这里,您所做的是将指针传递给函数。但是指针本身是通过值传递的,因此该函数具有这些指针的本地副本。函数内的target
会在函数退出时立即停止。
要实际修改函数中的指针,您必须将指针传递给此指针,例如像这样:
void my_strcpy(char *target[], char source[])
{
*target = source;
}
请注意,这仍然不适用于您的程序,因为在main()
中您声明了一个数组。无法更改声明的数组的地址。这是因为一个数组不与指针相同(正如你经常在编写不好的C教程中读到的那样)但是当你将它传递给函数时,它只是隐式转换为指向它的第一个元素的指针。因此,在char *target
中写main()
,此将工作,调用函数my_strcpy(&target, source);
。
另请注意,这是无法副本,因此您的函数命名在语义上是错误的。真正的复制功能如下所示:
void my_strcpy(char *target, const char *source)
{
while (*target++ = *source++);
}
复制单个字符,直到达到\0
字符(然后表达式将评估为0
,而while循环将停止)。这种超级简单的实现为target
提供了足够的存储空间,并确保source
实际上 0终止给调用者,但确实或多或少标准C库的strcpy()
做了什么。
编辑:我刚刚更改了您的功能签名 - 第一个更改是品味问题,将identifier[]
替换为*identifier
。我喜欢这样做,因为无论如何这都是内部发生的事情,所以它使得函数实际需要的更清楚。第二个是在适当的位置添加const
:您的函数永远不会更改source
所指向的内容,因此您应该明确这样做 - 这样编译器就可以为您捕获更多错误。
答案 1 :(得分:5)
您需要牢记两件事:
现在,
my_strcpy(target, source);
与
相同my_strcpy(&target[0], &source[0]);
传递两个数组的第一个元素的地址和
void my_strcpy(char target[], char source[])
与
相同void my_strcpy(char* target, char* source)
其中target
指向target
中数组main
的第一个元素的地址,source
指向数组的第一个元素source
的地址1}} main
。
所以,
target = source;
只需更改target
指向的位置即可。现在,target
和source
都指向相同的内存位置,即source
中数组main
的地址。 这对main
中的任何一个数组都没有任何影响,因为C使用pass-by-value。函数中的两个指针都有不同的数组地址。