Skip to main content
deleted 4 characters in body
Source Link
Deduplicator
  • 19.9k
  • 1
  • 32
  • 65
char* astrcat(const char* restrict delim, size_t num_args, ...) {
    if (!num_args)
        return calloc(1, 1);

    size_t lengths[num_args];
    const size_t ndelim = delim ? strlen(delim) : 0;
    size_t total = (num_args - 1) * lengths[0];ndelim;

    va_list args;
    va_start(args, num_args);
    for (size_t i = 0; i < num_args; ++i) {
        lengths[i] = strlen(va_arg(args, const char*));
        total += lengths[i];
    }
    va_end(args);

    char* const r = malloc(total + 1);
    if (!r)
        return r;

    char* p = r;
    va_start(args, num_args);
    for (size_t i = 0;; ++i) {
        memcpy(p, va_arg(args, const char*), lengths[i]);
        p += lengths[i];
        if (i == num_args)
            break;
        memcpy(p, delim, ndelim);
        p += ndelim;
    }
    *p = 0;
    va_end(args);

    return r;
}
char* astrcat(const char* restrict delim, size_t num_args, ...) {
    if (!num_args)
        return calloc(1, 1);

    size_t lengths[num_args];
    const size_t ndelim = delim ? strlen(delim) : 0;
    size_t total = (num_args - 1) * lengths[0];

    va_list args;
    va_start(args, num_args);
    for (size_t i = 0; i < num_args; ++i) {
        lengths[i] = strlen(va_arg(args, const char*));
        total += lengths[i];
    }
    va_end(args);

    char* const r = malloc(total + 1);
    if (!r)
        return r;

    char* p = r;
    va_start(args, num_args);
    for (size_t i = 0;; ++i) {
        memcpy(p, va_arg(args, const char*), lengths[i]);
        p += lengths[i];
        if (i == num_args)
            break;
        memcpy(p, delim, ndelim);
        p += ndelim;
    }
    *p = 0;
    va_end(args);

    return r;
}
char* astrcat(const char* restrict delim, size_t num_args, ...) {
    if (!num_args)
        return calloc(1, 1);

    size_t lengths[num_args];
    const size_t ndelim = delim ? strlen(delim) : 0;
    size_t total = (num_args - 1) * ndelim;

    va_list args;
    va_start(args, num_args);
    for (size_t i = 0; i < num_args; ++i) {
        lengths[i] = strlen(va_arg(args, const char*));
        total += lengths[i];
    }
    va_end(args);

    char* const r = malloc(total + 1);
    if (!r)
        return r;

    char* p = r;
    va_start(args, num_args);
    for (size_t i = 0;; ++i) {
        memcpy(p, va_arg(args, const char*), lengths[i]);
        p += lengths[i];
        if (i == num_args)
            break;
        memcpy(p, delim, ndelim);
        p += ndelim;
    }
    *p = 0;
    va_end(args);

    return r;
}
Source Link
Deduplicator
  • 19.9k
  • 1
  • 32
  • 65

Using C99 Variable Length Arrays to save calculated string-lengths, and fixing all the other problems chux identified, your code can be made far more efficient:

char* astrcat(const char* restrict delim, size_t num_args, ...) {
    if (!num_args)
        return calloc(1, 1);

    size_t lengths[num_args];
    const size_t ndelim = delim ? strlen(delim) : 0;
    size_t total = (num_args - 1) * lengths[0];

    va_list args;
    va_start(args, num_args);
    for (size_t i = 0; i < num_args; ++i) {
        lengths[i] = strlen(va_arg(args, const char*));
        total += lengths[i];
    }
    va_end(args);

    char* const r = malloc(total + 1);
    if (!r)
        return r;

    char* p = r;
    va_start(args, num_args);
    for (size_t i = 0;; ++i) {
        memcpy(p, va_arg(args, const char*), lengths[i]);
        p += lengths[i];
        if (i == num_args)
            break;
        memcpy(p, delim, ndelim);
        p += ndelim;
    }
    *p = 0;
    va_end(args);

    return r;
}

If you don't want (or can't) use VLA, you can use simple recursion (this version also changed to use a sentinel instead of a manual count, using sentinel above or count below left as an exercise for the reader):

static char* vastrcat_impl(const char* restrict delim, size_t ndelim,
        size_t prefix, va_list args) {
    const char* p = va_arg(args, const char*);
    if (!p) {
        char* r = malloc(prefix + 1);
        if (r)
            *(r += prefix) = 0;
        return r;
    }
    size_t n = strlen(p);
    char* r = vastrcat_impl(delim, ndelim, prefix + n + ndelim, args);
    if (!r)
        return r;
    memcpy(r -= n, p, n);
    memcpy(r -= ndelim, delim, ndelim);
    return r;
}

char* vastrcat(const char* restrict delim, va_list args) {
    const char* p = va_arg(args, const char*);
    if (!p)
        return calloc(1, 1);
    size_t n = strlen(p);
    size_t ndelim = delim ? strlen(delim) : 0;
    char* r = vastrcat_impl(delim, ndelim, n, args);
    memcpy(r -= n, p, n);
    return r;
}

char* astrcat(const char* restrict delim, ...) {
    va_list args;
    va_start(args, delim);
    char* r = vastrcat(delim, args);
    va_end(args);
    return r;
}