为什么仅分配指针的字符串复制函数不起作用?
Why is a string copy function just assigning the pointer not working?
考虑 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"
。但事实并非如此。
有人可以解释为什么吗?
您需要记住两件事:
- C 使用 pass-by-value.
- 您不能更改自动数组的地址。
现在,
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
在 main
.
所以,
target = source;
只是改变了target
指向的位置。现在,target
和 source
都指向相同的内存位置,即 main
中数组 source
的地址。 这对 main
中的任何一个数组都没有任何影响,因为 C 使用按值传递。 函数中的两个指针与函数中的指针具有不同的地址数组。
void my_strcpy(char target[], char source[])
{
target = source;
}
正如您所写,您在这里所做的是将指针传递给函数。但是指针本身是通过值传递的,因此该函数具有这些指针的本地副本。一旦函数退出,函数内部的 target
就会停止存在。
要实际修改函数中的指针,您必须将 指针传递给此指针,例如像这样:
void my_strcpy(char *target[], char source[])
{
*target = source;
}
请注意,这仍然不适用于您的程序,因为在 main()
中您声明了一个数组。已声明数组的地址不能更改。这是因为数组与指针 不同 (正如您经常可以在写得不好的 C 教程中读到的那样),只是在传递数组时隐式转换为指向其第一个元素的指针到一个函数。所以,在你的 main()
中写 char *target
,这个 会 工作,调用像 my_strcpy(&target, source);
.
这样的函数
另请注意,这 绝不是 的副本,因此函数的命名在语义上是错误的。一个真正的复制函数看起来像这样:
void my_strcpy(char *target, const char *source)
{
while (*target++ = *source++);
}
复制单个字符直到遇到 [=18=]
字符(然后表达式将计算为 0
并且 while 循环将停止)。这个超级简单的实现留下了为 target
提供足够存储空间并确保 source
实际上是 0-terminated 给调用者的负担,但它确实是或多或少是标准 C 库的 strcpy()
所做的。
edit:我只是稍微更改了您的函数签名——第一个更改是个人喜好问题,将 identifier[]
替换为 *identifier
。我喜欢这样做,因为无论如何这都是内部发生的事情,所以它使函数实际采用的内容更加清晰。第二个是在适当的地方添加 const
:您的函数永远不会更改 source
指向的内容,因此您应该明确这一点——这样编译器可以为您捕获更多错误。
考虑 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"
。但事实并非如此。
有人可以解释为什么吗?
您需要记住两件事:
- C 使用 pass-by-value.
- 您不能更改自动数组的地址。
现在,
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
在 main
.
所以,
target = source;
只是改变了target
指向的位置。现在,target
和 source
都指向相同的内存位置,即 main
中数组 source
的地址。 这对 main
中的任何一个数组都没有任何影响,因为 C 使用按值传递。 函数中的两个指针与函数中的指针具有不同的地址数组。
void my_strcpy(char target[], char source[])
{
target = source;
}
正如您所写,您在这里所做的是将指针传递给函数。但是指针本身是通过值传递的,因此该函数具有这些指针的本地副本。一旦函数退出,函数内部的 target
就会停止存在。
要实际修改函数中的指针,您必须将 指针传递给此指针,例如像这样:
void my_strcpy(char *target[], char source[])
{
*target = source;
}
请注意,这仍然不适用于您的程序,因为在 main()
中您声明了一个数组。已声明数组的地址不能更改。这是因为数组与指针 不同 (正如您经常可以在写得不好的 C 教程中读到的那样),只是在传递数组时隐式转换为指向其第一个元素的指针到一个函数。所以,在你的 main()
中写 char *target
,这个 会 工作,调用像 my_strcpy(&target, source);
.
另请注意,这 绝不是 的副本,因此函数的命名在语义上是错误的。一个真正的复制函数看起来像这样:
void my_strcpy(char *target, const char *source)
{
while (*target++ = *source++);
}
复制单个字符直到遇到 [=18=]
字符(然后表达式将计算为 0
并且 while 循环将停止)。这个超级简单的实现留下了为 target
提供足够存储空间并确保 source
实际上是 0-terminated 给调用者的负担,但它确实是或多或少是标准 C 库的 strcpy()
所做的。
edit:我只是稍微更改了您的函数签名——第一个更改是个人喜好问题,将 identifier[]
替换为 *identifier
。我喜欢这样做,因为无论如何这都是内部发生的事情,所以它使函数实际采用的内容更加清晰。第二个是在适当的地方添加 const
:您的函数永远不会更改 source
指向的内容,因此您应该明确这一点——这样编译器可以为您捕获更多错误。