0

我正在查看 2 个 C 字符串函数 strtok_r() 和 strsep(),并注意到这两个函数都修改了传入的原始字符串的位置。

是否还有其他不修改传入的原始字符串的 C 字符串函数?

在我的应用程序中,原始字符串是动态分配的,所以我希望在解析完成后释放原始字符串。

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“教程和示例”。

strsep() 也会出现类似的输出。

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

谢谢你。

4

2 回答 2

4

我想你是误会了strtok_r。它不会改变原始字符串的位置,而且它不能——函数不能改变传递给它的指针的值,并使这个改变对调用代码可见。

它可以并且将会做的是通过用-terminators替换标记来修改字符串本身的内容。nul所以回答你原来的问题:

在我的应用程序中,原始字符串是动态分配的,所以我希望在解析完成后释放原始字符串。

你不必做任何特别的事情。完成后,您可以并且应该释放原始字符串。

您看到打印一个单词Tutorial仅仅是因为下一个字符被替换为nul-terminator 并printf停在那里。如果您要逐个字符地检查字符串,您会发现它在其他方面保持不变。

于 2021-05-10T17:44:43.280 回答
0

尽管提到的字符串函数改变了原始字符串,但指针str指向动态分配的内存,您可以使用它来释放分配的内存。

如果您不想更改原始字符串,可以使用标准 C 字符串函数strspnstrcspn.

例如

#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 );
        
        const char *prev = p;
        
        p += strcspn( 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
于 2021-05-10T18:16:34.470 回答