построение строки из переменного количества аргументов - PullRequest
5 голосов
/ 17 июня 2011
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>


int main(int argc, char * argv[])
{
    char *arr[] = { "ab", "cd", "ef" };
    char **ptr, **p, *str;
    int num = 3;
    int size = 0;

    ptr = calloc(num, 4);
    p = ptr;

    for (; num > 0; num--)
            size += strlen(*(p++) = arr[num - 1]);

    str = calloc(1, ++size);
    sprintf(str, "%s%s%s", ptr[0], ptr[1], ptr[2]);

    printf("%s\n", str);

    return 0;
}

вывод: "efcdab" как ожидалось.

Теперь все в порядке и подходит, если количество аргументов до sprintf заранее определено и известно. Однако я пытаюсь добиться элегантного способа построения строки, если число аргументов является переменным (ptr[any]).

первая проблема: 2-й аргумент, который требуется передать sprintf, равен const char *format.
второй: третий аргумент - это фактическое количество переданных аргументов для построения строки на основе предоставленного format.

как мне добиться чего-то из следующего:

sprintf(str, "...", ...)

в основном, что, если функция получает 4 (или более) указателя на символы, из которых я хочу построить целую строку (в настоящее время в приведенном выше коде есть только 3). это будет означать, что 2-й аргумент должен быть (как минимум) в форме "%s%s%s%s", за которым следует список аргументов ptr[0], ptr[1], ptr[2], ptr[3].

как вообще можно сделать такой «комбинированный» вызов на sprintf (или vsprintf)? все было бы проще, если бы я мог просто предоставить весь массив указателей (** ptr) в качестве 3-го аргумента вместо этого ... но это не представляется возможным? по крайней мере, не таким образом, чтобы sprintf это понимало, так что, кажется ... поскольку для этого нужна какая-то особая форма format.

идей / предложений?

Ответы [ 4 ]

1 голос
/ 17 июня 2011
Предложение

Карлфиллип о strcat, похоже, является решением здесь.Или, скорее, вы захотите использовать что-то вроде strncat (хотя, если вы работаете с библиотекой C, которая поддерживает это, я бы порекомендовал strlcat, что, на мой взгляд, намного лучше, чем strncat).

Таким образом, вместо sprintf(str, "%s%s%s", ptr[0], ptr[1], ptr[2]); вы могли бы сделать что-то вроде этого:

int i;

for (i = 0; i < any; i++)
    strncat(str, arr[i], size - strlen(str) - 1);

(или strlcat(str, arr[i], size);; что приятно в strlcat, так этовозвращаемое значение будет указывать, сколько байтов необходимо для перераспределения, если целевой буфер слишком мал, но это не стандартная функция C и многие системы не поддерживают ее.)

0 голосов
/ 17 июня 2011

Цикл, который я использовал бы для окончательного копирования в str, будет выглядеть примерно так:

for(i=0, p=str; i < num; i++)
    p += sprintf(p, "%s", ptr[i]);

или

for(i=0, p=str; i < num; i++)
    p += strlen(strcpy(p, ptr[i]));

вместо того, чтобы пытаться работать с переменным числом аргументов водин звонок в sprintf.

0 голосов
/ 17 июня 2011

Ваша первая проблема решена: const char * для функции, а не для вас.Соберите свою собственную строку - эта подпись просто означает, что функция не изменит ее.

Ваша вторая проблема решена с помощью: pass в вашем собственном va_list.Как вы его получите?Создайте свою собственную функцию varargs:

char *assemble_strings(int count, ...)
{
    va_list data_list;
    va_list len_list;
    int size;
    char *arg;
    char *formatstr;
    char *str;
    int i;

    va_start(len_list, count);
    for (i = 0, size = 0; i < count; i++)
    {
        arg = va_arg(len_list, char *);
        size += strlen(arg);
    }
    va_end(len_list);

    formatstr = malloc(2*count + 1);
    formatstr[2*count] = 0;
    for (i = 0; i < count; i++)
    {
        formatstr[2*i] = '%';
        formatstr[2*i+1] = 's';
    }
    str = malloc(size + 1);

    va_start(data_list, count);
    vsprintf(str, formatstr, data_list);
    va_end(data_list);

    free(formatstr);

    return(str);
}

Конечно, вам понадобится какой-нибудь способ завершить varargs, и гораздо проще просто передать его в vsprintf, если список строк полностью находится внутри varargs -поскольку стандарт C требует хотя бы одного регулярного аргумента.

0 голосов
/ 17 июня 2011

Нет другого способа сделать это в C без манипулирования буферами.

Вы можете, однако, переключиться на C ++ и использовать невероятные std::string, чтобы сделать вашу жизнь проще.

...