2017-09-23 59 views
0

sscanf是这样工作的:sscanf是否有指向输入字符串而不是缓冲区的指针?

int main(const int argc, const char *argv[]) { 
    char buf1[1024] = {0}; 
    char buf2[1024] = {0}; 
    char buf3[1024] = {0}; 
    char *str = "abc, 123; xyz"; 
    sscanf(str, "%[^,], %[^;]; %s", buf1, buf2, buf3); 
    printf("'%s' '%s' '%s'", buf1, buf2, buf3); // Prints: "'abc' '123' 'xyz'" 
    return 0; 
} 

我想知道是否有不需要复制的str内容到缓冲区(buf1, buf2, buf3),也没有分配任何新的记忆功能。相反,它只会将指针(ptr1, ptr2, ptr3)设置为指向str中的匹配部分,并且在匹配之后将null结束。

int main(const int argc, const char *argv[]) { 
    char *ptr1 = NULL; 
    char *ptr2 = NULL; 
    char *ptr3 = NULL; 
    char *str = "abc, 123; xyz"; 
    // 
    // str = "abc, 123; xyz\0" 
    // 
    _sscanf(str, "%[^,], %[^;]; %s", &ptr1, &ptr2, &ptr3); 
    // 
    // str = "abc\0 123\0 xyz\0" 
    //  ^ ^ ^
    //  ptr1 ptr2 ptr3 
    // 
    printf("'%s' '%s' '%s'", ptr1, ptr2, ptr3); // Prints: "'abc' '123' 'xyz'" 

    return 0; 
} 

我知道有作为strtok_r功能,以及regex.h库,也可以使用,但我认为这将是在输入字符串可以被修改的情况下更方便。

+0

的问题是,'sscanf'解析的输入不能始终* *是空终止的! 'regex.h'返回子组匹配的*范围*,这是可行的。 –

+0

你的问题是一个废话,就好像你null终止原始字符串中间的某个地方一样,你将永远不会再是同一个字符串str,因为即使你移动了其余的字符,如果正确的str的大小增加和最有可能的重新分配将需要 –

+0

请注意,我在某些情况下说。在某些情况下,我不关心输入字符串是否被修改。 –

回答

4

它并不漂亮,但%n说明符可能用于捕获标记开始和结束的索引。错误检查将确保指数和最终值不-1

#include <stdio.h> 

int main(int argc, char *argv[]) { 
    int index1 = -1; 
    int end1 = -1; 
    int index2 = -1; 
    int end2 = -1; 
    int index3 = -1; 
    int end3 = -1; 
    char *str = "abc, 123; xyz"; 
    sscanf(str, " %n%*[^,]%n, %n%*[^;]%n; %n%*s%n", &index1, &end1, &index2, &end2, &index3, &end3); 
    printf("'%.*s' '%.*s' '%.*s'", end1, str + index1, end2 - index2, str + index2, end3 - index3, str + index3); // Prints: "'abc' '123' 'xyz'" 
    return 0; 
} 
1

没有与指针最终以char *指向在原始的字符串位置标准化的变种。在POSIX中有一个变体为每个字符串项分配内存并将其复制到每个字符串项。

sscanf()的功能与fscanf()和其他变体的功能相匹配,并且在非常广泛的范围内,适用于所有变体的变体适用于所有变体。但是,您正在寻找的内容不能应用于基于文件的变体,因此它不存在。


有一个sscanf()的变种,为字符串分配内存。这是POSIX 2008变体sscanf()m修改器。

[CX]⌦的%c%s,和%[转换说明应接受一个可选的分配分配字符“M”,其中应导致分配存储器缓冲器来保存串并转换,包括终止空字符。在这种情况下,与转换说明符对应的参数应该是对指针变量的引用,该变量将接收指向已分配缓冲区的指针。系统将分配一个缓冲区,就好像malloc()已被调用一样。应用程序应负责在使用后释放内存。如果没有足够的内存分配缓冲区,则该功能应将errno设置为[ENOMEM],并导致转换错误。如果函数返回EOF,则在函数返回之前,将使用由此调用成功分配给使用分配分配字符'm'的参数的任何内存。 ⌫

的[CX]符号标记此作为扩展在C标准(所以m改性剂是不标准C的一部分,并且它不到处支持),并且⌦和⌫符号标记范围的扩展名。因此,如果您的实现支持它(例如,Linux不支持,macOS Sierra则不支持),则会有sscanf()的变化,它会为您分配正确大小的缓冲区,并且需要参数char **

在Linux手册页说:

一个可选的 'M' 字。这与字符串转换(%s,%c,%[)一起使用,并且减轻了调用者需要分配相应的缓冲区以容纳输入:scanf()而是分配足够大小的缓冲区,并且将该缓冲区的地址分配给相应的指针参数,它应该是指向变量char *的指针(该变量在调用之前不需要初始化)。当不再需要时,调用者应随后释放(3)该缓冲区。

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

int main(void) 
{ 
    char data[] = "The hills are alive with the sound of music"; 
    char *w[9]; 

    if (sscanf(data, "%ms %ms %ms %ms %ms %ms %ms %ms %ms", 
       &w[0], &w[1], &w[2], &w[3], &w[4], &w[5], &w[6], &w[7], &w[8]) != 9) 
    { 
     fprintf(stderr, "Oops!\n"); 
     return 1; 
    } 
    printf("Forwards: %s\n", data); 
    printf("Reversed:"); 
    for (int i = 8; i >= 0; i--) 
     printf(" %s", w[i]); 
    putchar('\n'); 
    for (int i = 0; i < 9; i++) 
     free(w[i]); 
    return 0; 
} 

输出:

Forwards: The hills are alive with the sound of music 
Reversed: music of sound the with alive are hills The 
+0

虽然这仍然会复制字符串。它不返回指向输入字符串的指针,这是OP要求的, – zwol

+0

@zwol:哦,我第一次误解了这个问题。我相应地修改了我的答案。 –

+0

'm'修饰符也适用于Posix'scanf'和'fscanf'。 (我知道你知道这一点,但我认为你的答案可能会被误解。) – rici