sscanf 在 C 中包含可变长度字符串和数字的字符串

sscanf a string containing variable length strings and numbers in C

我有一个字符串,例如:“1.5 3 aaa 0 bbbbbbbbbb”,我需要对其进行 sscanf(我确切地知道我期望有多少 space 分隔的元素以及它们的数据类型是什么,但我不知道不知道 aaa 和 bbbbbbbbbb 这两个字符串的长度)。

我想要这样的东西:

sscanf(rx_buffer, "%f %d %s %d %s", &a, &b, string1, &c, string2);
    

将两个字符串存储到 string1 和 string2(两个 char *)中的简单、漂亮且有效的方法是什么?可能涉及 realloc 吗?

提前致谢,非常感谢您的每一个提示。

读入字符串时不能中断sscanf,所以一旦超出缓冲区就没有机会执行realloc

您可以做的一件事是提供一个足够大的缓冲区来容纳您假设的最长字符串;您可以限制您接受的字符数以避免溢出;您可以检查 sscanf 成功扫描了多少项目:

char string1[100];
char string2[100];
int elementsScanned = sscanf(rx_buffer, "%f %d %99s %d %99s", &a, &b, string1, &c, string2);
if (elementsScanned != 5) ... // do some error handling here

您可以做的另一件事是假设 string1 和 string2 都不会大于 rx_buffer 本身。所以你可以相应地分配内存。这是“浪费”了一些内存,但你是在保存方面:

size_t len = strlen(rx_buffer);
char* string1 = malloc(len+1);
char* string2 = malloc(len+1);
int elementsScanned = sscanf(rx_buffer, "%f %d %s %d %s", &a, &b, string1, &c, string2);

如果您可以假设要从 rx_buffer 解析的字符串的最大长度,sscanf() 是一个简单有效的解决方案。

如果rx_buffer可以有任意长度,你可以使用库函数解析它,例如strtod()strtol()strspn()strcspn()strndup():

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

struct context {
    float a;
    int b;
    char *string1;
    int c;
    char *string2;
};

// return the number of fields parsed
int parse_response(struct context *cp, const char *rx_buffer) {
    //sscanf(rx_buffer, "%f %d %s %d %s", &a, &b, string1, &c, string2);
    const char *src = rx_buffer;
    char *p;
    size_t n;
    cp->a = strtod(src, &p);
    if (p == src)
        return 0;
    cp->b = strtol(src = p, &p, 10);
    if (p == src)
        return 1;
    src = p + strspn(p, " \t\r\n\f\v");
    n = strcspn(src, " \t\r\n\f\v");
    if (n == 0)
        return 2;
    if ((cp->string1 = strndup(src, n)) == NULL)
        return -1;
    src += n;
    src += strspn(src, " \t\r\n\f\v");
    cp->c = strtol(src, &p, 10);
    if (p == src)
        return 3;
    src = p + strspn(p, " \t\r\n\f\v");
    n = strcspn(src, " \t\r\n\f\v");
    if (n == 0)
        return 4;
    if ((cp->string2 = strndup(src, n)) == NULL)
        return -1;
    return 5;
}

这显然不简单也不好看

如果您的目标是带有 GNU libc 的 linux 系统,您可以使用其 sscanf() 实现的扩展:%m 前缀=23=] 提供了一个简单、漂亮且有效的解决方案:

#include <stdio.h>

// return the number of fields parsed
int parse_response(const char *rx_buffer) {
    float a;
    int b, c;
    char *string1 = NULL, *string2 = NULL;
    int n = sscanf(rx_buffer, "%f %d %ms %d %ms", &a, &b, &string1, &c, &string2);
    if (n == 5) {
        // all fields parsed correctly, handle values
        ...
    }
    free(string1);
    free(string2);
    return n;
}