Как построить char * из массива char * - PullRequest
1 голос
/ 07 июля 2011

Пожалуйста, взгляните на следующий код:

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

typedef struct {
        const char * cmd;
        const char * help;
} CmdEnum;

static CmdEnum cmd_enum[] = {
        {"help", "This help..."},
        {"first", "The first command"},
        {"second", "The second command"},
};

void main()
{
    int i,n;
    char *out = "";

        n = sizeof(cmd_enum) / sizeof(CmdEnum);
        for (i=0; i<n; i++)
        {
            char *oldOut = out;
            CmdEnum cmd = cmd_enum[i];
            asprintf(&out, "%s%s -> %s\n", oldOut, cmd.cmd, cmd.help);
            if(i>0) free(oldOut);
        }

    printf("%s", out);
    printf("Done.\n");
}

Это хороший способ для создания текста из CmdEnum?
Есть ли более приятный способ определить cmd впервое место, чтобы избежать if(i>0) free...?
или я делаю что-то совершенно не так?

РЕДАКТИРОВАТЬ:
После прочтения ответа Ларсмана я изменил main:

int main()
{
    int i,n, copied, siz;
    char *out, *cursor;
    siz = 1;// 1 for NUL char
    n = sizeof(cmd_enum) / sizeof(CmdEnum);

    for (i=0; i<n; i++)
    {
        siz += strlen(cmd_enum[i].cmd) + strlen(cmd_enum[i].help) + strlen(":\n\t\n\n");
    }

    out = malloc(siz);
    if(!out)
    {
        printf("Could not alloc!\n");
        return 1;
    }

    cursor = out;
    for (i=0; i<n; i++)
    {
        copied = snprintf(cursor, siz, "%s:\n\t%s\n\n", cmd_enum[i].cmd, cmd_enum[i].help);
        if(copied < 0 || copied >= siz)
        {
            printf("snprintf failed: %i chars copied.\n", copied);
            return 1;
        }

        cursor += copied;
        siz -= copied;
    }

    printf("%s", out);
    printf("Done.\n");
    free(out);
    return 0;
}

(Примечание: я также изменил формат вывода ...)

1 Ответ

2 голосов
/ 07 июля 2011

Является ли это хорошим способом для создания текста из CmdEnum?

Да, за исключением того, что asprintf не является переносимым (хотя вы можете легко определить его в терминах snprintf для платформ, у которых его нет), и вы не проверяете ошибки.void main недопустимо C btw.

Есть ли "более приятный" способ определить cmd во-первых, чтобы избежать if (i> 0) free ...?

Вы можете заранее выделить всю строку.

size_t i, siz = 1;  // 1 for NUL char
for (i=0; i<n; i++)
    siz += strlen(cmd_enum[i].cmd) + strlen(cmd_enum[i].help) + strlen(" -> \n");

char *out = malloc(siz);
// check for errors

, а затем построить строку с помощью snprintf.Это сэкономит вам malloc и проверку ошибок в цикле.

...