【问题标题】:my_strcpy gives seg faultmy_strcpy 给出段错误
【发布时间】:2013-10-04 05:22:51
【问题描述】:
#include<stdio.h>

char* my_strcpy(char*,const char*);

int main(){
        char a[20];
        char* s = "Hello world!";
        char* d = a;
        my_strcpy(d,s);
        printf("\n d : %s \n",d);
        return 0;
}

char* my_strcpy(char* dest,const char* sour){
        if(NULL == dest || NULL == sour){
                return NULL;
        }
        while(1){
                *dest++ = *sour++;
                if(*sour == '\0'){
                        *dest = *sour;
                        break;
                }
        }
}

为什么我们需要 char* 作为 my_strcpy 的返回类型。如果 d 是“”,它会给我一个分段错误。如果我将它分配给它,它工作正常。为什么给定“”时会出现段错误。

修改:在答案之后

#include<stdio.h>

char* my_strcpy(char*,const char*);

int main(){
        char* ret;
        char a[20];
        char* s = "Hello world!";
        char* d = "";
        ret = my_strcpy(d,s);
        if(NULL == ret){
                perror("\nret");
        }
//      printf("\n d : %s \n",d);
        return 0;
}

char* my_strcpy(char* dest,const char* sour){
        char* temp;

        if(NULL == dest || NULL == sour){
                return NULL; 
        }

        temp = dest;
        while(1){ 
                *temp++ = *sour++;
                if(*sour == '\0'){
                        *temp = *sour;
                        break;
                }
        }
        return temp;
}

这仍然会产生段错误。如果 s="" 传递给函数 strcpy 时如何处理条件。

【问题讨论】:

  • my_strcpy 没有返回任何东西?也这样做:if(*(dest-1) == '\0')
  • 您已更改您的问题,请恢复到以前的版本。 if(*sour == '\0') 曾是 if(*dest == '\0')
  • 无法解释的变化让新读者感到困惑,无法将答案与当前问题联系起来
  • @Angus 没问题,但从下一次开始要小心,并在发布问题之前花点时间。我希望你能得到你的答案。
  • 就目前情况而言 (2010-10-04 06:00:00Z — 修订版 7),使用 s = ""; 会导致问题,因为 *dest++ = *sour++; 行复制了空(零)字节并且是现在查看字符串末尾的数据(产生未定义的行为)。循环的规范形式(供您选择变量名)是while ((*dest++ = *sour++) != '\0') ;,分号是下一行的空循环体(但在 SO cmets 中不显示换行符)。这会完成赋值、增加指针并检查所分配的字符是否是零字节,所有这些都在一个操作中完成。

标签: c


【解决方案1】:

您问:“如果 d 是”“它会给我一个分段错误。” 回答: 如果将“”或“”分配给 d,将没有足够的空间容纳“Hello World”。此外,如果将常量字符串分配给标记为数据的内存页面,则可能不允许修改。

您问“为什么我们需要 char* 作为 my_strcpy 的返回类型”作为我假设的原始 strcpy。 回答: 你不必。您可以将 void 作为返回类型。但是,如果要做这样的事情,它会变得很实用:

printf ("%s", strcpy (dest, sour));

更正的代码:

    while(1){
            *dest++ = *sour++;
            if(*(sour-1) == '\0'){
                    break;
            }

或更好:

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

【讨论】:

  • 仍然不能修改常量/不可变字符串。他没有通过原来的a,作为可以修改记忆的目的地
  • 感谢您在更新答案后立即阅读的评论。
  • 返回 char* 也有助于调用链。
  • @Koushik : 什么是调用链?
  • @Angus 类似于 my_strcpy(dest2,my_strcpy(dest1,src))。以此类推。
【解决方案2】:

给你:

  1. 将 *sour 的值赋给 *dest
  2. 增加酸味和目标,所以现在指向下一个字符
  3. 测试 *dest 现在是否为 NUL 以退出循环

如您所见,第三步从未初始化的内存中读取。您应该测试在递增之前分配的值是否为 NUL。

            *dest++ = *sour++;
            if(*dest == '\0'){
                    break;
            }

如果你传入的 dest 是一个像 " " 这样的常量字符串,你会得到一个段错误,因为字符串常量存储在只读内存中。它们不能被修改。

【讨论】:

  • 我认为最后一部分是这里真正的问题(至少现在是编辑过的问题),即传递一个 const 字符串 "" 并期望用 strcpy 对其进行修改。 +1
【解决方案3】:

正确:

 if(*dest == '\0'){

应该是:

 if(*(dest - 1) == '\0'){

注意:

 *dest++ = *sour++;

等价于

*dest = *sour;
sour++;
dest++;

您在分配后递增dest,因此您在存在垃圾值的位置检查\0,因为您没有初始化a[] - 导致未定义的行为。此外,您不会在 while 循环后返回。

你可以简单地将你的函数写成:

char* my_strcpy(char* dest,const char* sour){
     if(NULL == dest || NULL == sour)
         return NULL;
    char* d = dest;
     while(*dest++ = *sour++)
        ;
     return d;
}

试试看!!

【讨论】:

  • 虽然while循环让人困惑,但它是正确的。 if 语句负责检查是否已到达空字符并在中断之前将其复制。
  • 是的 if(*(dest - 1) == '\0') 这是 OP 需要改变的地方。
  • @Gangadhar 所以每一个答案似乎都是正确的。感谢您的支持。
【解决方案4】:

这是一个简单的版本:

char *my_strcpy(char *d, const char *s){
  int i=0;
  while(d[i++]=*s++)
    /*done inside condition*/;
  return d;
}

【讨论】:

    【解决方案5】:

    我建议将 strcpy 实现为:

    char* my_strcpy (char* s1, const char* s2)
    {
      char* return_val = s1;
    
      *s1 = *s2;
    
      while(*s2 != '\0')
      {
        s1++;
        s2++;
        *s1 = *s2;
      }
    
      return return_val;
    }
    

    始终避免在同一个表达式中使用多个 ++ 语句。没有理由这样做,它迟早会给你一些未定义/未指定的行为错误。

    【讨论】:

      猜你喜欢
      • 2012-07-10
      • 2020-06-15
      • 2019-02-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多