删除空格后的垃圾输出

时间:2017-02-21 17:41:37

标签: c string algorithm removing-whitespace

我有这段代码:

     int i =0;
  char * str = "ar   bitrary             whitespace";

  int whitespace=0,index;
  for(index = 0;index < strlen(str);index++)
    {
      if(isspace(str[index]) != 0)
    {
      whitespace++;
    }
    }


  char * tmp = (char *)calloc(strlen(str)-whitespace +1,sizeof(char));

  memset(tmp,'\0',strlen(tmp)+1);

  while(i < strlen(str))
    {
      if(isspace(str[i]) != 0)
    {
      i++;
      continue;
    }else if(isspace(str[i]) == 0)
    {

      strcat(tmp,&str[i]);
      i++;
    }

    }


  printf("\nnew string is: %s \n",tmp);

问题是输出是一个字符串,没有删除空格+一些垃圾字符。 我用memset来终止tmp,是不是有问题?

3 个答案:

答案 0 :(得分:1)

我不会读你的问题,你肯定会覆盖'\0'终止符。

现在我已经阅读了你的问题,看起来你需要更好地理解字符串和数组,

  1. 不要写while (i < strlen(str))
  2. 不要使用strcat()添加单个字符,显然您在那里覆盖了'\0'。此外,不要使用strcat()来连接多个字符串。
  3. 也值得注意,

    • memset()之后calloc()已初始化为0。这意味着你正在强制执行一些不必要的东西,并尝试两次,就好像它第一次失败一样,我可以保证它没有。

      事实上,由于您已使用calloc()并且tmp指向的所有字节均为0,因此strlen(tmp)将返回0,因此您memset() 1}}相当于

      tmp[0] = '\0';
      

      并且您真的不需要初始化tmp,除非您最终从str复制实际字节。

    我总是建议反对calloc()字符串,因为

    1. 你真的不需要初始化两次。
    2. 您应该确保您的代码确实将终止'\0'考虑在内,而不是简单地假设它存在,因为您calloc()编辑了。这是一个你只是隐藏calloc()的错误,但它会在某个时刻出现。
    3. 试试这个,看看你能否理解我的变化原因

      #include <stdio.h>
      #include <ctype.h>
      #include <stdlib.h>
      
      int main(void)
      {
          int whitespace;
          int length;
          char *str = "ar   bitrary             whitespace";
          char *tmp;
      
          whitespace = 0;
          for (length = 0; str[length] != '\0'; ++length) {
              if (isspace(str[length]) != 0) {
                  whitespace++;
              }
          }
          tmp = malloc(length - whitespace + 1);
          if (tmp == NULL)
              return -1;
          for (int i = 0, j = 0; str[i] != '\0'; ++i) {
              if (isspace(str[i]) != 0)
                  continue;
              tmp[j++] = str[i];
          }
          tmp[length - whitespace] = '\0';
          printf("new string is: %s\n",tmp);
      
          free(tmp);
          return 0;
      }
      

答案 1 :(得分:1)

这是你的问题

 memset(tmp,'\0',strlen(tmp)+1);

strlen(tmp)通过在'\0'中查找tmp来工作,这里有鸡和蛋的情况。

你不应该以任何方式做一个memset,只需在你复制时使用'\0'

并且不要使用strcat,而是保持指向tmp的指针,然后执行*p = str[i]然后增加p

答案 2 :(得分:1)

可以在此循环之前计算源字符串的长度

for(index = 0;index < strlen(str);index++)

否则,如果代码不会被优化,则将为循环的每次迭代调用函数strlen。实际上,对于这样的任务来说,使用该函数是多余的。

本声明

memset(tmp,'\0',strlen(tmp)+1);

没有意义,因为calloc的调用已经用零初始化了内存。

本声明

strcat(tmp,&str[i]);

还会在位置i之后复制源字符串中的空白。因此它可以写入超出为指针tmp指向的数组分配的内存。

您可以编写一个单独的函数,该函数可以在本演示程序中显示

#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>

char * remove_blanks( const char *s )
{
    size_t n = 0;

    const char *p = s;

    do
    {
        if ( !isspace( ( unsigned char )*p ) ) ++n;
    } while ( *p++ );

    char *t = malloc( n );

    if ( t )
    {
        char *q = t;
        p = s;

        do
        {
            if ( !isspace( ( unsigned char )*p ) ) *q++ = *p;
        } while ( *p++ );
    }

    return t;
}

int main(void) 
{
    char * str = "ar   bitrary             whitespace";

    printf( "\"%s\"\n", str );

    char *t = remove_blanks( str );

    printf( "\"%s\"\n", t );

    free( t );
}   

程序输出

"ar   bitrary             whitespace"
"arbitrarywhitespace"