【问题标题】:Seg fault error?段错误错误?
【发布时间】:2015-03-25 07:41:50
【问题描述】:

有谁知道为什么我不断收到此段错误错误? 我正在尝试运行一个程序,该程序在“src”中找到一个子字符串“from”,并将 src 中所有不重叠的“from”替换为输出字符串“dest”中的“to”。 另外,任何人都可以为我提供测试此案例的正确方法吗?因为我不太确定如何使用“void”类型来显示它......(尝试这个作为练习)

void find_replace(char* src, char* from, char* to, char* dest)
{
  int count = 0;
  int diff = strlen(to) - strlen(from);
  int destlength = strlen(src);
   dest = malloc(destlength);
  for (int i = 0; i < strlen(src); i++)
    {
      int index = 0;
      while (src[i+index] == from[index] && index < strlen(from)){
        index++;
      }
      if (index == strlen(from)) {
        for (int j = 0; j < strlen(to); j++) {
          dest[i+j+(count * diff)] = to[j];
        }
        i += strlen(from) - 1;
        count++;
      }
      else {
        dest[i + (count * diff)] = src[i];
      }
    }
  return ; 
}

是否足以进行测试?

int main (int argc, char *argv[])
{
     char* dest;
   find_replace("hello my name is leeho lim", "leeho lim", "(insert name)" dest);
  for (int i = 0; i < strlen(dest); i++)
    {
      printf("%c", dest[i]);
    }
  printf("\n");
}

【问题讨论】:

  • 字符串文字在 C 中不可修改。
  • 是的,我意识到了这一点,但我认为这不是我的 seg 错误的根源
  • 怀疑所有警告都没有启用。建议 -Wall
  • 您替换的文本比原来的多,因此 DEST 的大小太小。您需要更精确地将大小分配给 Dest。
  • 修复了来自 -Wall 的所有可疑警告,但它仍然存在...在最后初始化了 char* dest(怀疑可能会做某事)...我还更改了“to”输入小于“来自”输入,但段错误仍然存​​在):

标签: c arrays string segmentation-fault void


【解决方案1】:

出现问题是因为您试图使用

访问未分配的指针
strlen(dest)

在你的主程序中。

这样做的原因是您将指针dest的值发送给函数,而不是指针本身,所以当您在函数内部分配内存时,您实际上并没有修改存储在它外面的指针。

当您将指针作为函数的参数发送时,您实际上是在发送存储在该指针中的内存地址,您发送的是存储在指针中的值,而不是指针本身。

如果您想获取字符串的分配内存地址,您可以让函数返回它,或者您可以将dest 声明为pointer to a pointer 并将其发送。

编辑:正如其他评论指出的那样,您也可以在main() 中执行分配,而不是在您的函数中执行。

【讨论】:

    【解决方案2】:

    您只需要对您的程序进行一些小的调整。

    find_replace的返回值更改为更改后的字符串新分配的内存。

    代替

    void  find_replace(char* src, char* from, char* to, char* dest)
    

    使用

    char* find_replace(char* src, char* from, char* to)
    

    稍微改变实现。

    代替

      dest = malloc(destlength);
    

    使用

      char* dest = malloc(destlength);
    

    代替

      return;
    

    使用

     return dest;
    

    改变你使用函数的方式。

    代替

    char* dest;
    find_replace("hello my name is leeho lim", "leeho lim", "(insert name)", dest);
    

    使用

    char* dest = find_replace("hello my name is leeho lim", "leeho lim", "(insert name)");
    

    确保释放find_replace返回的内存。

    free(dest);
    

    这是一个完整的程序:

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    char* find_replace(char* src, char* from, char* to)
    {
      int count = 0;
      int diff = strlen(to) - strlen(from);
      int destlength = strlen(src);
      char* dest = malloc(destlength);
      for (int i = 0; i < strlen(src); i++)
        {
          int index = 0;
          while (src[i+index] == from[index] && index < strlen(from)){
            index++;
          }
          if (index == strlen(from)) {
            for (int j = 0; j < strlen(to); j++) {
              dest[i+j+(count * diff)] = to[j];
            }
            i += strlen(from) - 1;
            count++;
          }
          else {
            dest[i + (count * diff)] = src[i];
          }
        }
      return dest; 
    }
    
    int main (int argc, char *argv[])
    {
       char* dest = find_replace("hello my name is leeho lim", "leeho lim", "r sahu");
       for (int i = 0; i < strlen(dest); i++)
       {
          printf("%c", dest[i]);
       }
       free(dest);
       printf("\n");
    }
    

    更新,以回应 OP 的评论

    如果find_replace 的返回类型必须是void,则有几个选项可用于处理dest 所需的内存。

    1. 在调用函数中为dest分配内存。

      char* dest = malloc(SUFFICIENT_SIZE);
      find_replace("hello my name is leeho lim", "leeho lim", "(insert name)", dest); 
      
      free(dest);
      

      那么,就不需要这条线了

      dest = malloc(...); 
      

      find_replace.

    2. find_replace 中为dest 分配内存。然后,您需要将指针传递给指针。

      void find_replace(char* src, char* from, char* to, char** dest)
      

      并在函数中使用*dest 而不仅仅是dest

      void find_replace(char* src, char* from, char* to, char** dest)
      {
        int count = 0;
        int diff = strlen(to) - strlen(from);
        int destlength = strlen(src);
        *dest = malloc(destlength);
        for (int i = 0; i < strlen(src); i++)
          {
            int index = 0;
            while (src[i+index] == from[index] && index < strlen(from)){
              index++;
            }
            if (index == strlen(from)) {
              for (int j = 0; j < strlen(to); j++) {
                (*dest)[i+j+(count * diff)] = to[j];
              }
              i += strlen(from) - 1;
              count++;
            }
            else {
              (*dest)[i + (count * diff)] = src[i];
            }
          }
        return; 
      }
      

      并更改您调用的find_replace

      char* dest;
      find_replace("hello my name is leeho lim", "leeho lim", "(insert name)", &dest);
      

    【讨论】:

    • 看,我会将输出更改为 char*,但只是为了练习,我的老师希望我用 void 输出来做。但是非常感谢!
    【解决方案3】:

    您的(原始)代码存在两个主要问题:

    1. 它不提供您的find_replace() 函数将分配的目标缓冲区返回给调用者,并且
    2. 它没有可靠地为目标缓冲区分配足够的空间。

    原则上,问题 (1) 可以通过两种方式解决。空间可以由调用者分配并将指向它的指针传递给函数,或者空间可以由函数分配并将指针返回给调用者。您的原始代码在函数中分配空间,但没有将指向它的指针返回给调用者

    最好由函数执行分配,因为满足问题 (2) 需要对输入进行更彻底的分析,而不是坚持调用者执行。当你这样做时,考虑一下你修改后的代码会发生什么:

    char dest[4];
    int canary = 0;
    
    find_replace("aaa", "a", "longer string", dest);
    assert(canary == 0);
    

    你很可能会遇到段错误,可能会遇到断言失败,也许你会知道谁知道什么,因为find_replace() 不能在不写超过dest 结尾的情况下执行其工作,其结果是未定义。

    虽然你说过这个练习要求你的函数没有返回值(即void),它仍然可以通过参数列表返回一个指向目标字符串的指针。您只需将 pointer 传递给 dest 指针而不是其值,以便函数可以更新该值。签名看起来像这样:

    void find_replace(const char *src, const char *from, const char *to,
                      char **dest_p);
    

    (请注意 srcfromtoconst 限定符,如果函数旨在接受字符串文字,则它们是适当的,如果不是必需的。)

    dest 所需的空间量是src 的长度加上终止符的长度加上,如果tofrom 长,则to 和@987654337 的长度之差@strings 乘以to 字符串的出现次数。但是,您可以计算该长度的上限,然后在确定实际使用了多少空间后缩小分配(如果需要)。例如:

    void find_replace(const char *src, const char *from, const char *to,
                      char **dest_p) {
        ssize_t src_size = strlen(src);
        ssize_t from_size = strlen(from);
        ssize_t to_size = strlen(to);
        char *temp;
    
        if (!from_size) {
             /* special case: the 'from' string is empty ... */
             /* whatever you do, set temp to something valid or NULL */
        } else {
            ssize_t size_diff = to_size - from_size;
    
            if (size_diff < 0) size_diff = 0;
            temp = malloc(1 + src_size + (src_size / from_size) * size_diff);
            if (temp) {
                /* use next to track the next unused position in temp */
                char *next = temp;
    
                /*
                 * perform the substitution, updating 'next' appropriately as
                 * you go along (INSERT CODE AFTER THIS COMMENT) ...
                 */
    
                /* be sure to terminate: */
                *(next++) = '\0';
    
                /* shrink the string to the actual space used (optional): */
                next = realloc(temp, next - temp);
    
                /*
                 * On (re)allocation error, next will be NULL and temp will still
                 * be a valid pointer.  Otherwise, next will be a pointer to the
                 * space, not necessarily equal to temp, and temp might no longer
                 * be a valid pointer.
                 *
                 * An OK error recovery strategy is to just return a pointer
                 * to the full-size space.
                 */
                if (next) {
                    temp = next;
                }
            } /* else allocation failure; return NULL */
        }
    
        /*
         * The caller gets a pointer to the allocated space (if any).  It is his
         * responsibility to free it when it is no longer needed.
         */
        *dest = temp;
    }
    

    实际的替换代码留作练习,毕竟这家庭作业。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-08-01
      • 2014-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多