繁体   English   中英

从字符串中删除空格

[英]Removing spaces from strings

我试图编写一个获取字符串并创建一个新字符串的函数,但没有多个空格(单词之间仅保留一个空格)。

到目前为止,我已经写了这个,但是由于某种原因它崩溃了,调试器什么也没显示。

我也不知道我应该在哪里放置免费功能...

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char* upgradestring(char* oldtext);

int main()
{
    char str1[] =  "Chocolate     Can   Boost   Your Workout" ;

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

    printf("\n%s\n", upgradestring(str1));

    return 0;
}

char* upgradestring(char* oldtext)
{
    int i,j, count = 1;
    char *newstr;

    for (i = 0; oldtext[i] != '\0'; i++)
    {
        if (oldtext[i] != ' ')
            count++;
        else if (oldtext[i - 1] != ' ')
            count++;
    }
    newstr = (char*)malloc(count * sizeof(char));
    if (newstr == NULL)
        exit(1);

    for (i = 0, j = 0; (oldtext[i] != '\0')|| j<(count+1); i++)
    {
        if (oldtext[i] != ' ')
        {
            newstr[j] = oldtext[i];
            j++;
        }
        else if (oldtext[i - 1] != ' ')
        {
            newstr[j] = oldtext[i];
            j++;
        }
    }

    return newstr;
}

您要寻址[i-1]并且如果i==0 ,它不在原始数组的范围内。

您可以按照以下方式进行操作:

只需一个一个地复制,如果char为'',则在它为''时继续跳过,否则向前一个。

static size_t newlen(char const *o)
{
    size_t r=0;
    while(*o){
        r++;
        if(*o==' ') 
            while(*o==' ')
                o++;
        else
           o++;
    }
    return r;

}
char *upgradestring(char const *o)
{
    char *r, *p;
    size_t len = newlen(o);
    if( 0==(r = malloc(len+1)))
        return 0;
    r[len]=0;
    for(p=r;*o;){
        *p++=*o;
        if(*o==' ') 
           while(*o==' ') 
              o++;
        else
           o++;
    }
    return r;
}
int main()
{
    char str1[] =  "Chocolate     Can   Boost   Your Workout" ;
    char *new;
    printf("%s\n", str1);
    if(0 == (new = upgradestring(str1)))
        return 1;
    printf("%s\n", new);
    free(new);
}

分配失败最好用返回码表示(如果失败,您不希望库函数中止程序)。

为了能够释放返回的字符串,首先必须将其捕获到变量中。

很好的尝试,但是让我们专注于何时需要释放内存。 您在函数内部动态分配内存,然后在printf内调用函数,这将允许打印字符串,但是如何取消分配呢? 使用指针分配函数的返回值,打印它,然后释放它!

此外,您需要为新字符串具有的字符分配空间,再为null终止符分配一个空间,因为C字符串要求该字符串能与来自头文件的printf()例如printf()一起平稳运行。

此外,我们不malloc()在C中返回的内容,请在此处阅读更多内容。

还有这个:

else if (oldtext[i - 1] != ' ')

应写为:

else if (i != 0 && oldtext[i - 1] != ' ')

避免在i为0时访问oldtext[-1]

最后,您在填充新字符串时使用的条件最好使用逻辑AND(而不是OR),因为一旦任何一个条件为false,我们都必须立即停止(我们不希望读取该条件的null终止符)原始字符串,或超过新字符串的大小)。

将所有内容放在一起,我们:

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

char* upgradestring(char* oldtext)
{
    int i, j, count = 0;
    // compute 'count'
    for(i = 0; oldtext[i]; i++)
    {
        if (oldtext[i] != ' ')
            count++;
        else if (i != 0 && oldtext[i - 1] != ' ')
            count++;
    }
    char* newstr = malloc(count + 1); // PLUS ONE for the null terminator
    if(!newstr) // check if malloc failed
    {
        printf("Malloc failed\n");
        return 0;
    }
    // populate 'newstr'. We need to stop when either condition is false
    for (i = 0, j = 0; (oldtext[i]) && j<(count+1); i++)
    {
        // Same as your code
    }
    // Assign the null terminator!
    newstr[j] = '\0';
    return newstr;
}

int main(void) {
    char str1[] =  "Chocolate     Can   Boost   Your Workout" ;
    // store the result of your function into 'newstr'
    char* newstr = upgradestring(str1);
    // print it
    printf("%s\n", newstr);
    // free it, since you no longer need it!
    free(newstr);
    return 0;
}

输出:

巧克力可以促进您的锻炼


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

char *upgradestring(char *oldtext)
{
size_t len,src,dst,spc;
char *result;

        // First pass: count needed size
for (len=src=spc=0;oldtext[src]; src++){
        if (oldtext[src] != ' ') spc=0;       // non-space needs space
        else if(spc++) continue;              // skip non first space
        len++;
        }

result= malloc (1+len);

        // Second pass: copy(K&R style)
for (dst=src=spc=0; (result[dst] = oldtext[src]) ; src++){
        if (oldtext[src] != ' ') spc=0;      // non-space: rest counter
        else if(spc++) continue;             // skip non-first space
        dst++;
        }

return result;
}

简化版本:不要在第一遍中计算大小,而是从与原始大小相同的大小开始,然后在第二遍后调整大小。 (strdup()可以替换为strlen + malloc + memcpy)


char * strdup(char *);

char *upgradestring2(char *oldtext)
{
size_t src,dst,spc;
char *result;

result= strdup (oldtext);

        // edit the copy, skipping all spaces except the first
for (dst=src=spc=0; result[src] ; src++){
        if (result[src] != ' ') spc=0;  // non-space:reset counter
        else if(spc++) continue;        // skip space,except the first

        result[dst++] = result[src]; // Copy
        }
result[dst] = 0;// terminate string;

// result=realloc(result, dst+1);

return result;
}

对于初学者,程序中都不会使用头文件<string.h>声明。 因此,该指令

#include <string.h>

可能会从程序中删除。

根据C标准,不带参数的main函数应声明为

int main( void )

具有奇怪名称upgradestring :)的函数不会更改参数。 因此,应该像

char* upgradestring( const char* oldtext);
                     ^^^^^

考虑到源字符串可以以空格开头。 在这种情况下,这样的语句

    else if (oldtext[i - 1] != ' ')
        count++;

导致未定义的行为,因为当i等于0时,尝试访问超出字符串的内存。

条件

(oldtext[i] != '\0')|| j<(count+1); 

应该至少写成

(oldtext[i] != '\0') && j<(count+1); 
                     ^^^ 

尽管足以检查索引j因为它不能大于源字符串的长度。

您忘了在结果字符串后附加终止符'\\0'

同样,用此语句退出函数也不是一个好主意

exit(1);

在这种情况下,您可以返回一个空指针。

并且在退出程序之前,应释放已分配的内存。

如前所述,源字符串可以以空格开头,也可以有多余的尾随空格。 我认为从结果字符串中排除它们在逻辑上是一致的。

通常,空格字符与制表符一起使用。 此外,C在头文件<ctype.h>中声明了一个特殊的isblank函数,该函数检查字符是空格还是空格。 (据我所知,MS VS不支持此功能)

考虑到所有这些,可以按照演示程序中所示的以下方式定义功能。

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

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

    const char *p = s;

    //  skip leading blanks
    while ( *p == ' ' || *p == '\t' ) ++p;

    _Bool last_blank = 0;

    for ( ; *p; ++p )
    {
        ++n;
        if ( ( last_blank = ( *p == ' ' || *p == '\t' ) ) )
        {
            while (  p[1] == ' ' || p[1] == '\t' ) ++p;
        }           
    }

    if ( last_blank ) --n;

    char *q = malloc( n + 1 );

    if ( q )
    {
        p = s;

        //  skip leading blanks
        while ( *p == ' ' || *p == '\t' ) ++p;

        size_t i = 0;
        for ( ; i < n; i++, ++p )
        {
            q[i] = *p == '\t' ? ' ' : *p;
            if ( q[i] == ' ' )
            {
                while (  p[1] == ' ' || p[1] == '\t' ) ++p;
            }
        }

        q[i] = '\0';
    }

    return q;
}

int main(void) 
{
    char s[] =  "\t\tChocolate  \t   Can \t  Boost   Your Workout   ";

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

    char *t = trim_blanks( s );

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

    free( t );

    return 0;
}

程序输出为

"       Chocolate      Can    Boost   Your Workout   "
"Chocolate Can Boost Your Workout"

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM