如何在 c 中正确实现 strcpy?
How to properly implement strcpy in c?
据此:
strcpy vs strdup,
strcpy 可以用一个循环来实现,他们使用了这个while(*ptr2++ = *ptr1++)
。我试过做类似的事情:
#include <stdio.h>
#include <stdlib.h>
int main(){
char *des = malloc(10);
for(char *src="abcdef[=10=]";(*des++ = *src++););
printf("%s\n",des);
}
但是什么都不打印,也没有错误。出了什么问题?
非常感谢您的回答,我已经玩了一点,并决定如何最好地设计循环以查看复制是如何逐字节进行的。这似乎是最好的:
#include <stdio.h>
#include <stdlib.h>
int main(){
char *des = malloc(7);
for(char *src="abcdef", *p=des; (*p++=*src++); printf("%s\n",des));
}
你正在递增 des
所以在循环结束时它自然会指向字符串的末尾,打印它等于 undefined behavior,你必须把它带回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
}
// '[=10=]' 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("%s\n",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("%s\n",ptr);
free(ptr) // or free(dest); to free the allocated memory when you're done with it
return EXIT_SUCCESS;
}
您分配目标缓冲区 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("%s\n",des);
}
所以p
是指向下一个目标字符的指针,并沿着字符串移动。但是您打印的最终字符串是 des
,从分配开始。
当然,您还应该为des
分配strlen(src)+1
个字节。并且没有必要以 null 终止字符串文字,因为这将由编译器为您完成。
在这个循环中
for(char *src="abcdef[=10=]";(*des++ = *src++););
目标指针 des
正在更改。所以在循环之后它不指向复制字符串的开头。
注意显式终止零字符'[=17=]'
在字符串文字中是多余的。
循环可以如下所示
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 );
printf("%s\n",des);
是 未定义的行为 (UB),因为它尝试从写入分配内存的字符串末尾开始打印。
复制字符串
保存原始指针,检查并在完成后释放。
const char *src = "abcdef[=10=]"; // string literal here has 2 ending `[=10=]`,
char *dest = malloc(strlen(src) + 1); // 7
char *d = dest;
while (*d++ = *src++);
printf("%s\n", dest);
free(dest);
复制字符串文字
const char src[] = "abcdef[=11=]"; // string literal here has 2 ending `[=11=]`,
char *dest = malloc(sizeof src); // 8
for (size_t i = 0; i<sizeof src; i++) {
dest[i] = src[i];
}
printf("%s\n", 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("%s\n", 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("%s\n", mystrdup("asdfgfd"));
}
But that prints nothing, and no error. What went wrong?
des
在执行 (*des++ = *src++)
后不再指向字符串的开头。事实上,des
指向 NUL
字符之后的一个元素,此后终止字符串。
因此,如果您想使用 printf("%s\n",des)
打印字符串,它会调用未定义的行为。
您需要将“起始”指针(指向已分配内存块的第一个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("%s\n",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("%s\n", 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("%s\n", des);
free(des);
}
旁注:
"abcdef[=19=]"
- 不需要明确的 [=20=]
。它在翻译过程中自动附加。使用 "abcdef"
.
如果分配成功,请始终检查 return 内存管理函数,方法是检查空指针的 returned。
通过 const
限定指向字符串文字的指针以避免无意的写入尝试。
在调用 malloc 时使用 sizeof(char) * 10
而不是普通的 10
。如果类型发生变化,这可以确保写入大小。
int main (void)
而不是 int main (void)
。第一个符合标准,第二个不符合标准。
始终free()
动态分配内存,因为您不再需要分配的内存。在上面的示例中,这将是多余的,但是如果您的程序变得更大并且示例是部分集中的,您应该立即 free()
不需要的内存。
据此:
strcpy vs strdup,
strcpy 可以用一个循环来实现,他们使用了这个while(*ptr2++ = *ptr1++)
。我试过做类似的事情:
#include <stdio.h>
#include <stdlib.h>
int main(){
char *des = malloc(10);
for(char *src="abcdef[=10=]";(*des++ = *src++););
printf("%s\n",des);
}
但是什么都不打印,也没有错误。出了什么问题?
非常感谢您的回答,我已经玩了一点,并决定如何最好地设计循环以查看复制是如何逐字节进行的。这似乎是最好的:
#include <stdio.h>
#include <stdlib.h>
int main(){
char *des = malloc(7);
for(char *src="abcdef", *p=des; (*p++=*src++); printf("%s\n",des));
}
你正在递增 des
所以在循环结束时它自然会指向字符串的末尾,打印它等于 undefined behavior,你必须把它带回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
}
// '[=10=]' 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("%s\n",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("%s\n",ptr);
free(ptr) // or free(dest); to free the allocated memory when you're done with it
return EXIT_SUCCESS;
}
您分配目标缓冲区 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("%s\n",des);
}
所以p
是指向下一个目标字符的指针,并沿着字符串移动。但是您打印的最终字符串是 des
,从分配开始。
当然,您还应该为des
分配strlen(src)+1
个字节。并且没有必要以 null 终止字符串文字,因为这将由编译器为您完成。
在这个循环中
for(char *src="abcdef[=10=]";(*des++ = *src++););
目标指针 des
正在更改。所以在循环之后它不指向复制字符串的开头。
注意显式终止零字符'[=17=]'
在字符串文字中是多余的。
循环可以如下所示
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 );
printf("%s\n",des);
是 未定义的行为 (UB),因为它尝试从写入分配内存的字符串末尾开始打印。
复制字符串
保存原始指针,检查并在完成后释放。
const char *src = "abcdef[=10=]"; // string literal here has 2 ending `[=10=]`,
char *dest = malloc(strlen(src) + 1); // 7
char *d = dest;
while (*d++ = *src++);
printf("%s\n", dest);
free(dest);
复制字符串文字
const char src[] = "abcdef[=11=]"; // string literal here has 2 ending `[=11=]`,
char *dest = malloc(sizeof src); // 8
for (size_t i = 0; i<sizeof src; i++) {
dest[i] = src[i];
}
printf("%s\n", 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("%s\n", 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("%s\n", mystrdup("asdfgfd"));
}
But that prints nothing, and no error. What went wrong?
des
在执行 (*des++ = *src++)
后不再指向字符串的开头。事实上,des
指向 NUL
字符之后的一个元素,此后终止字符串。
因此,如果您想使用 printf("%s\n",des)
打印字符串,它会调用未定义的行为。
您需要将“起始”指针(指向已分配内存块的第一个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("%s\n",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("%s\n", 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("%s\n", des);
free(des);
}
旁注:
"abcdef[=19=]"
- 不需要明确的[=20=]
。它在翻译过程中自动附加。使用"abcdef"
.如果分配成功,请始终检查 return 内存管理函数,方法是检查空指针的 returned。
通过
const
限定指向字符串文字的指针以避免无意的写入尝试。在调用 malloc 时使用
sizeof(char) * 10
而不是普通的10
。如果类型发生变化,这可以确保写入大小。int main (void)
而不是int main (void)
。第一个符合标准,第二个不符合标准。始终
free()
动态分配内存,因为您不再需要分配的内存。在上面的示例中,这将是多余的,但是如果您的程序变得更大并且示例是部分集中的,您应该立即free()
不需要的内存。