从字符串中删除空格

时间:2017-06-17 13:10:59

标签: c string function pointers memory-management

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

到目前为止,我写了这个,但由于某种原因它崩溃了,调试器没有显示任何内容。

我也不知道在哪里需要放置免费功能......

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

4 个答案:

答案 0 :(得分:2)

您正在寻址template = plt.imread('template_long.png') template = rgb2gray(template) template = template > threshold_mean(template) for i in range(1): # read in image img = cv2.imread('conversion/umsatz_{}.png'.format(i)) # convert to grayscale gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) gray = cv2.bitwise_not(gray) # threshold the image, setting all foreground pixels to # 255 and all background pixels to 0 thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1] # edge detection #edges = cv2.Canny(thresh,2,100, apertureSize = 3) # fill the holes from detected edges #kernel = np.ones((2,2),np.uint8) #dilate = cv2.dilate(thresh, kernel, iterations=1) result = match_template(thresh, template) mask = result < 0.5 r = result.copy() r[mask] = 0 r[~mask] = 1 plt.imshow(r) ,如果[i-1],则不在原始数组的范围内。

以下是你如何做到的:

只需逐个复制,如果字符是“,则继续跳过”,否则按“1”进行复制。

i==0

分配失败最好通过返回代码发出信号(如果失败,您不希望库函数中止您的程序。)

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

答案 1 :(得分:1)

很好的尝试,但是当你需要释放记忆时,请注意。你动态分配函数内部的内存,然后调用printf中的函数,这将允许字符串打印,但你将如何解除分配?使用指针指定函数的返回值,打印它,然后释放它!

此外,您需要为新字符串所包含的字符数量分配空间,并为 null终结符分配一个空格,因为C字符串要求它与来自标题的函数一起顺利运行,例如{ {1}}。

此外,我们不会在C中投放printf()返回的内容,请阅读更多here

还有:

malloc()

应写成:

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

以避免在else if (i != 0 && oldtext[i - 1] != ' ') 为0时访问超出范围的oldtext[-1]

最后,填充新字符串时使用的条件,使用逻辑AND而不是OR会更好,因为我们必须在条件为false时立即停止(我们不想读取空值原始字符串的终止符,或超过新字符串的大小。)

把所有东西放在一起,我们:

i

输出:

  

巧克力可以促进你的锻炼

答案 2 :(得分: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;
}

答案 3 :(得分:0)

对于初学者,程序中不会使用标题<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在标题isblank中声明了一个特殊函数<ctype.h>,用于检查字符是空格还是空格。 (据我所知,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"