【问题标题】:garbage output after whitespace removing删除空格后的垃圾输出
【发布时间】:2017-07-11 11:41:06
【问题描述】:

我有这个代码:

     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来null终止tmp,有问题吗?

【问题讨论】:

  • 字符串后的垃圾听起来像是缺少字符串终止符。

标签: c string algorithm removing-whitespace


【解决方案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"

【讨论】:

  • 谢谢,我试图理解一些事情:当你一开始说 for 循环中的“strlen”是多余的时,可以像“int ln = strlen( str)" 而不是使用 ln 作为循环的上限?(避免像这样连续调用 strlen)。第二件事:强制转换为无符号字符真的有必要吗?第三件事:在 do-while 循环中作为 while 的参数使用“*p++”,然后在循环内的 isspace 中写入“*p”作为参数,但 *p 不仅仅表示第一个字符串的元素?抱歉这些问题,但我正在学习。
  • @Collapsed 您可以在循环之前或在 for 语句的第一个表达式部分计算长度。如果某些字符可以具有负值,则有必要强制转换为无符号字符。在 do while 循环中,可以使用指针 p 访问原始字符串的每个字符。所以它必须增加以顺序指向每个字符,这是在循环的条件下完成的。
【解决方案2】:

这是你的问题

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

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

您不应该以任何方式进行 memset,只需在完成复制时添加 '\0'

不要使用strcat,而是维护一个指向tmp 的指针,然后只使用*p = str[i] 然后递增p

【讨论】:

  • 我不明白,你是在暗示没有0 终结符还是memset() 只将第一个字节设置为0
【解决方案3】:

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

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

  1. 永远不要写while (i &lt; strlen(str))
  2. 不要使用strcat() 添加单个字符,您显然确实覆盖了那里的'\0'。此外,永远不要使用strcat() 来连接多个字符串。

同样值得注意,

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

    事实上,既然你使用了calloc(),并且tmp指向的所有字节都是0,那么strlen(tmp)将返回0,因此你的memset()相当于

    tmp[0] = '\0';
    

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

对于字符串,我总是建议不要使用 calloc(),因为

  1. 您实际上并不需要初始化两次。
  2. 您应该确保您的代码确实考虑了终止'\0',而不是因为您calloc()ed 而简单地假设它在那里。这是一个你可以用calloc() 隐藏的错误,但它会在某个时候出现。

试试这个,看看你能不能理解我改变的原因

#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;
}

【讨论】:

  • 感谢您的回答。我不必写“while(i
  • strlen 函数需要时间和空间。当您编写while(strlen(str)) 时,循环每次都会转到该函数,直到循环结束。当你之前写 int l=strlen(str) 并使用 l 时,你只会调用 strlen 一次。
  • @Collapsed 在 PHP 中,strlen() 在循环控制中很常见,在 c 中这不是一个好主意,因为长度没有存储在任何地方。所以每次你调用它时,它都会一个一个地计算字符。 strcat() 也是如此。知道在执行期间长度不会改变的字符串的长度是 c 中的一个很好的优势,您可以使用它来提高性能。
猜你喜欢
  • 2023-03-20
  • 2019-08-03
  • 1970-01-01
  • 2014-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多