问题描述
我查看了 2 个 C 字符串函数,strtok_r() 和 strsep(),并注意到了两者 函数修改传入的原始字符串的位置。
在我的应用中,原始字符串是动态分配的,所以我想释放原始字符串 解析完成后的字符串。
strtok_r() 示例
int main(){
char * str = strdup("Tutorial and example");
char* token;
char* rest = str;
printf("%s\n",rest);
while ((token = strtok_r(rest," ",&rest)))
printf("%s\n",token);
printf("\n%s\n",str);
return(0);
}
Tutorial and example
Tutorial
and
example
Tutorial
在最后一行,我希望 str 指向未修改的 cstring“教程和示例”。
int main(){
char * str = strdup("Tutorial and example");
char* token;
char* rest = str;
printf("%s\n",rest);
while ((token = strsep(&rest," ")))
printf("%s\n",token);
if (rest != NULL)
printf("%s\n",rest);
printf("%s\n",str);
return(0);
}
谢谢。
解决方法
我认为您误解了strtok_r
。它不会改变原始字符串的位置,而且,它也不能——函数不能改变传递给它的指针的值并使这个改变对调用代码可见。
它可以并且将会做的是修改字符串本身的内容,用nul
-终止符替换标记。所以要回答你原来的问题:
在我的应用中,原始字符串是动态分配的,所以我 希望在解析完成后释放原始字符串。
您不必做任何特别的事情。完成后,您可以并且应该释放原始字符串。
您看到一个单词 Tutorial
被打印出来,只是因为下一个字符被替换为 nul
-终止符并且 printf
停在那里。如果您要逐个字符地检查字符串,您将看到它在其他方面保持不变。
虽然上面提到的字符串函数改变了原来的字符串,但是指针str
指向动态分配的内存,你可以用它来释放分配的内存。
如果您不想更改原始字符串,您可以使用标准 C 字符串函数 strspn
和 strcspn
。
例如
#include <stdio.h>
#include <string.h>
int main(void)
{
const char *s = "Tutorial and example";
const char *separator = " \t";
puts( s );
for ( const char *p = s; *p; )
{
p += strspn( p,separator );
const char *prev = p;
p += strcspn( p,separator );
int width = p - prev;
if ( width ) printf( "%.*s\n",width,prev );
}
return 0;
}
程序输出为
Tutorial and example
Tutorial
and
example
使用这种方法,您可以为每个提取的子字符串动态分配内存。
例如
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void)
{
const char *s = "Tutorial and example";
const char *separator = " \t";
puts( s );
size_t n = 0;
char **a = NULL;
int success = 1;
for ( const char *p = s; success && *p; )
{
p += strspn( p,separator );
if ( p - prev != 0 )
{
char *t = malloc( p - prev + 1 );
if ( ( success = t != NULL ) )
{
t[p - prev] = '\0';
memcpy( t,prev,p - prev );
char **tmp = realloc( a,( n + 1 ) * sizeof( char * ) );
if ( ( success = tmp != NULL ) )
{
a = tmp;
a[n++] = t;
}
else
{
free( t );
}
}
}
}
for ( size_t i = 0; i < n; i++)
{
puts( a[i] );
}
for ( size_t i = 0; i < n; i++)
{
free( a[i] );
}
free( a );
return 0;
}
程序输出与上图相同。
Tutorial and example
Tutorial
and
example