【问题标题】:sscanf a string containing variable length strings and numbers in Csscanf C 中包含可变长度字符串和数字的字符串
【发布时间】:2020-10-15 20:42:01
【问题描述】:

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

我想要这样的东西:

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

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

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

【问题讨论】:

  • 使用strtodstrtolstrchr是一种“简单、漂亮、有效”的方法。

标签: c string malloc scanf realloc


【解决方案1】:

在读取字符串时不能中断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);

【讨论】:

  • 谢谢,但这正是我想避免的,即:考虑到最坏的情况,必须定义许多字符串(为了简单起见,两个只是一个例子)。我想知道是否有一个不错的 sscanf 替代方案可以输出所需的结果。
【解决方案2】:

如果您可以假设从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 前缀在 %s 之间提供了一个简单、漂亮和有效的解决方案:

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

【讨论】:

    猜你喜欢
    • 2020-04-28
    • 2013-03-21
    • 1970-01-01
    • 1970-01-01
    • 2012-01-12
    • 2010-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多