使用NUL终结符和分隔符拆分char数组的最佳方法?

时间:2018-05-06 16:29:00

标签: c string

我以这种格式输入一个char数组:"key = value\0key = value...\0"(最后一对以2个NUL终结符结束 - 其中一对+整个字符串一个

我想将它分成{key,value}对,以便打印出来。

这是我的方法,有更好的方法吗?

char str [] =   "line 1 = But I set fire to the rain\0line 2 = Watched it pour as I touched your face\0line 3 = Well, it burned while I cried\0line 4 = 'Cause I heard it screaming out your name, your name!\0";
char * p = str;
char key[10], value[128], * delimiter;

while(*p){
    memset(key,     0, sizeof(key));
    memset(value,   0, sizeof(value));

    delimiter = strchr(p, '=');
    strncpy(key, p, delimiter - p);
    // not sure where the NUL terminator is, so use strcpy
    strcpy(value, 1 + delimiter);

    printf("key: %s\n   value: %s\n", key, value);
    p += strlen(p) + 1;
}

1 个答案:

答案 0 :(得分:2)

有几个选项可供选择,具体取决于您是否需要NUL - 终止字符串以及您的缓冲区是否为只读。

如果您只想打印组合字符串的连续元素,则可以直接将其用作缓冲区:

char str[] = ...;
char *key, *val;
for(key = str; *key; key += strlen(key) + 1) {
    val = strchr(key, '=') + 1;
    printf("%.*s = %s", val - key - 1, key, val);
}

使用%.*s告诉printf从字符串中打印动态数量的字符。

如果你想要更高级的东西,你可能会使用两遍法。第一遍将计算键值对的数量,而第二遍将保留指针,长度,副本或您想要的任何其他信息。这种方法还需要比原始方法更多的清理。

要获得对的数量,您可以执行以下操作:

char str[] = ...;
char *p;
int count;
for(p = str, count = 0; *(p = strchr(p, '\0') + 1); count++) ;

如果您可以使用指向原始缓冲区中的键和值的指针(以及键的长度),则只需要分配count对指针和长度:

char *keys, *vals;
int i, *klens;

keys = malloc(count * sizeof(char *));
vals = malloc(count * sizeof(char *));
klens = malloc(count * sizeof(int));
if(keys == NULL || vals == NULL || klens == NULL) {
    goto cleanup;
}

for(i = 0, p = str; i < count; i++) {
    keys[i] = p;
    vals[i] = strchr(p, '=') + 2;
    klens[i] = vals[i] - keys[i] - 3;
    p = strchr(vals[i], '\0') + 1;
}

// Use the data, e.g., to print:
for(i = 0; i < count; i++) {
    printf("%.*s = %s\n", klens[i], keys[i], vals[i]);
}

cleanup:
if(keys != NULL) free(keys);
if(vals != NULL) free(vals);
if(klens != NULL) free(klens);

如果您想拥有每个键和值的可写版本,您有两个选择:

  1. 为每个缓冲区分配缓冲区,并使用strcpy分别复制每个键和值。在这种情况下,清理会有点复杂,因为您必须在开头将keysvals的所有元素设置为NULL(例如使用memset ),并在完成后释放所有非NULL元素。
  2. 更有效的选项可能是将整个str复制到新分配的可写缓冲区中,只需将=替换为\0即可。您可以在计算keysvals的同时执行此操作。清理工作不会比以前复杂得多。你只需要释放额外的文本缓冲区。