[英]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.