strcpy的C实现不会改变变量值

时间:2015-04-04 05:37:37

标签: c function pointers strcpy

所以,我正在尝试实现自己的strcpy以更好地理解指针在C中是如何工作的,到目前为止我还是处于亏损状态。我尝试了很多不同的方法,尝试使用网络中的代码,以后可能是我的基础,但即便是那些也无法工作。

我相信我可能会在main方法上以错误的方式调用函数。我将变量的指针传递给函数,以便函数可以更改变量的值,并在函数调用中,我给出指针的地址,以便方法可以获取正确的数据。至少我相信这是它的工作方式,无论如何我都能理解。

以下是函数和方法调用:

函数调用:

void my_strcpy( char *dest, const char* src ) {

dest = malloc(sizeof(src));

while ( src != '\0' ) {
  *dest = *src;
  src++;
  dest++;
 }

}

主要:

int main () {

const char* s = "Hello World";
char* test = 'd';

my_strcpy( &test, &s ); // Suposed to change test form d to Hello World.
printf("Changed String: " );
printf( "%c", test );


return 0;
}

PS:我尝试将test用作大于s的字符串,以查看它是否是内存分配问题,但似乎并非如此。任何帮助都是非常令人沮丧的,因为我被困在这里几个小时......

PS:我已经研究了如何更改变量的问题和示例,并且可以使用简单的int来完成。但是在使用char *时我不能这样做。因此这个帖子。如果问题相同,我道歉,但我无法理解我在这里做错了什么。请耐心等待我,因为我是C的初学者。

2 个答案:

答案 0 :(得分:2)

关键是参数在C中传递by value

因此,调用函数永远不会看到正式参数的任何更改。

最后,您的my_strcpy行为不像标准strcpy(不使用malloc分配内存)。您使用malloc是错误的,因为sizeof(src)始终为sizeof(char*)(即Linux / x86-64上为8)。

这是一个更好的版本:

 void my_strcpy( char *dest, const char* src ) {
   while ( *src != '\0' ) {
     *dest = *src;
     src++;
     dest++;
   }
   *dest = '\0'; // zero terminate the string
 }

请注意strcpy(和my_strcpy)本质上是危险的,因为您可能有buffer overflow(因此更频繁地使用strncpy)。一个典型的用例是

 char buf[80];
 my_strcpy(buf, "hello I am here");

所以我们有本地内存(通常在调用堆栈上),我们将其复制到其中。如果文字字符串很长(例如超过80个字符),我们就会有一个缓冲区溢出。

顺便说一下,你的测试while(src != '\0')非常错误。指针与指向的值不同。您的错误测试通常会在32位计算机上循环十亿次,并在达到终止条件src == NULL之前崩溃

同样在实践中,strcpy通常是通过优化编译器来实现的,例如GCC甚至可能在编译时生成循环,而不是对标准函数的函数调用。

如果启用编译器中的所有警告(您应该始终应该这样做),编译器可能会发现您的一些错误(例如GCC),因此请编译,例如使用gcc -Wall -Wextra -g(获取所有警告,更多信息和调试信息),然后使用调试器gdb逐步运行程序。

实际上,如果可能的话,让函数返回指针,比如

 char* my_almost_strdup(const char*src) {
    size_t ln = strlen(src);
    char* newptr = malloc(ln+1);
    if (!newptr) { perror("my_strdup"); exit(EXIT_FAILURE); };
    strcpy (newptr, src);
    return newptr;
 }

这有点像标准strdup,除了我正在捕获内存不足错误的情况(当malloc失败时)。通常只显示一些错误消息并退出该失败案例,但您应 始终处理malloc失败

详细了解C dynamic memory management记录您的内存约定(当有一个函数在堆中分配内存malloc或{{1}时等等......你需要记录谁负责释放它以及如何使用它。

要害怕undefined behaviormemory leaks。如果可用,请使用valgrind

阅读更多关于garbage collection的内容(这是一个非常有用的术语和概念)。您可能希望使用Boehm conservative garbage collector对某些C程序进行编码(但使用Boehm的GC是一个完整的程序决策)。

calloc

main

多次错误(因缓冲区溢出而导致未定义的行为)。您应该传递一个能够包含该字符串的内存区域的地址(包括其终止零字节),并且第二个参数的类型不正确( my_strcpy( &test, &s ); // VERY BAD &s而不是{{1 }})。

答案 1 :(得分:1)

你不需要&引用char *因为它已经是一个指向一个字符的指针,你不希望char **是指向一个字符的指针。

我修补了它:

void my_strcpy(char** dest, const char* src) {
    const char * srcTemp = src;
    int i = 1; //+1 for null char
    while (*srcTemp != '\0') {
        srcTemp++;
        i++;
    }
    char * destTemp = (char*)malloc(sizeof(char)*i);
    *dest = destTemp;

    while (*src != '\0') {
        *destTemp = *src;
        src++;
        *destTemp++;
    }
    *destTemp = *src; //copy null char

}

int _tmain(int argc, _TCHAR* argv[])
{
    const char* s = "Hello World";
    char* test = 0;

    my_strcpy(&test, s); // Suposed to change test form d to Hello World.
    printf("Changed String: ");
    printf("%s", test);


    return 0;
}