【问题标题】:Why malloc can't work with strcpy?为什么 malloc 不能与 strcpy 一起使用?
【发布时间】:2017-11-21 21:51:12
【问题描述】:
char * removeChar(char * str, char c){
    int len = strlen(str);
    int i = 0;
    int j = 0;
    char * copy = malloc(sizeof(char) * (len + 1));
    while(i < len){
        if(str[i] != c){
            copy[j] = str[i];
            j++;
            i++;
        }else{
            i++;
        }
   }

    if(strcmp(copy, str) != 0){
        strcpy(str,copy);

    }else{
        printf("Error");
    }
    return copy;
}




int main(int argc, char * argv[]){
    char str[] = "Input string";
    char * input;
    input = removeChar(str,'g');
    printf("%s\n", input);
    free(input);
    return 0;
}

我不知道为什么每次我尝试运行它时,它总是说未初始化的变量并粘在 strcpy 行和 printf 行。

基本上这个函数是获取一个字符串和一个字符,然后从字符串中删除那个字符(因为我正在学习malloc,所以我写了这样的函数)。

【问题讨论】:

  • 在我看来,if(strcmp(copy, str) != 0) 块结束后至少缺少两行代码。请添加它们。 (您可以编辑您的问题 - 看到方框中蓝色“c”下方的灰色小字“编辑”?那是一个按钮。是的,真的。)
  • 我想你忘记将字符串的最后一个字节设置为NUL (\0)。
  • 我没有收到该警告,但收到了不同的警告 ~ 警告 C4715:'removeChar':并非所有控制路径都返回值。但是看到我必须添加一个缺失的},也许我把它放错了地方。
  • 我也没有收到任何未初始化的变量警告。这段代码有几个地方我不会那样做,缺少几行是个问题,但我看到的唯一实际 bug 是 Alexander 和 Krom 指出的那个。
  • @Nina Liu 函数没有意义。在问题中描述您要达到的目标。

标签: c string function malloc strcpy


【解决方案1】:

你从来没有初始化输入并且一些编译器没有注意到, 该值从未在该行之前使用

input = removeChar(str, 'g');

在您的代码中。所以他们发出诊断只是为了确定。

strcpy(str, copy)

卡在您的代码中,因为副本从未得到结束的 0 字节并且 所以取决于你记忆中的不确定性内容 分配内存后备副本的时刻,strcpy 多长时间 将运行,如果你最终得到一个 SIGSEGV(或类似的)。

strcpy 将循环直到它在你的内存中找到一个 0 字节。

【讨论】:

    【解决方案2】:

    在while循环之后做:

    copy[j] = '\0';
    

    NULL-终止你的字符串;这样它就可以与来自 &lt;string.h&gt; 的方法一起使用,这些方法假定字符串是 nul 终止的。


    PS:你应该看到的一个警告是关于在任何情况下都不在你的函数中返回copy,因为现在如果 if 语句的条件错误,你的函数将不会返回有效的东西,所以添加这个:

    return copy;
    

    在您的函数结束时(现在已通过您的编辑更正)。

    除此之外,您仍然应该得到的唯一警告是main() 的未使用参数,仅此而已:

    prog.c: In function 'main':
    prog.c:32:14: warning: unused parameter 'argc' [-Wunused-parameter]
     int main(int argc, char * argv[]){
                  ^~~~
    prog.c:32:27: warning: unused parameter 'argv' [-Wunused-parameter]
     int main(int argc, char * argv[]){
                               ^~~~
    

    【讨论】:

    • 吹毛求疵:NULL 是一个指针。字符串以 NUL 结尾,只有一个 L。
    • @zwol:这就是为什么现在几乎只说“零终止”。不那么混乱。
    【解决方案3】:

    当您将字节从str 复制到copy 时,您不会在末尾添加终止空字节。结果,strcmp 将复制的字符读取到未初始化的内存中,可能超过了分配的内存块的末尾。这会调用undefined behavior

    在您的while 循环之后,向copy 添加一个终止空字节。

    此外,如果末尾的 if 块为 false,则永远不会返回值。你需要为此返回一些东西,可能是复制的字符串。

    char * removeChar(char * str, char c){
        int len = strlen(str);
        int i = 0;
        int j = 0;
        char * copy = malloc(sizeof(char) * (len + 1));
        while(i < len){
            if(str[i] != c){
                copy[j] = str[i];
                j++;
                i++;
            }else{
                i++;
            }
        }
        //  add terminating null byte
        copy[j] = '\0';
    
        if(strcmp(copy, str) != 0){
           strcpy(str,copy);
        }
        // always return copy
        return copy;
    }
    

    【讨论】:

      【解决方案4】:

      对于从字符串中删除字符的初学者,无需动态创建字符数组,然后将该数组复制到原始字符串中。

      您应该编写一个确实从字符串中删除指定字符的函数,或者编写一个基于不包括指定字符的源字符串创建新字符串的函数。

      这只是一个糟糕的设计,只会让用户感到困惑。那就是函数太复杂,使用了mallocstrlenstrcmpstrcpy等冗余函数。事实上,它有一个不明显的副作用。此外,字符串长度使用了不正确的类型int,而不是类型size_t

      至于您的函数实现,您忘记将终止零 '\0' 附加到内置于动态分配数组中的字符串。

      如果您确实想从字符串中删除一个字符,那么该函数可以看起来如演示程序中所示。

      #include <stdio.h>
      
      char * remove_char(char *s, char c)
      {
          char *p = s;
      
          while (*p && *p != c) ++p;
      
          for ( char *q = p; *p++; )
          {
              if (*p != c) *q++ = *p;
          }
      
          return s;
      }
      
      int main( void )
      {
          char str[] = "Input string";
      
          puts(str);
          puts(remove_char(str, 'g'));
      
          return 0;
      }
      

      程序输出是

      Input string
      Input strin
      

      如果您正在学习函数malloc 并想使用它,无论如何您都应该尝试实现正确的设计。

      要使用malloc,您可以编写一个函数,根据不包括指定字符的源字符串创建一个新字符串。例如

      #include <stdio.h>
      #include <stdlib.h>
      
      char * remove_copy_char(const char *s, char c)
      {
          size_t n = 0;
      
          for (const char *p = s; *p; ++p)
          {
              if (*p != c) ++n;
          }
      
          char *result = malloc(n + 1);
      
          if (result)
          {
              char *q = result;
      
              for (; *s; ++s)
              {
                  if (*s != c) *q++ = *s;
              }
      
              *q = '\0';
          }
      
          return result;
      }
      
      int main( void )
      {
          char *str = "Input string";
      
          puts(str);
      
          char *p = remove_copy_char(str, 'g');
      
          if ( p ) puts(p );
      
          free(p);
      
          return 0;
      }
      

      程序输出将与上面相同。

      Input string
      Input strin
      

      注意函数声明

      char * remove_copy_char(const char *s, char c);
                              ^^^^^^
      

      在这种情况下,源字符串可以是字符串文字。

      char *str = "Input string";
      

      【讨论】:

        猜你喜欢
        • 2018-01-03
        • 2018-11-29
        • 2014-06-18
        • 2016-03-16
        • 2018-03-09
        • 2021-06-14
        • 2012-10-09
        • 2020-03-18
        • 2019-04-11
        相关资源
        最近更新 更多