将2D数组转换为char *数组并将char复制到字符串结尾的最快方法

时间:2012-07-20 16:42:38

标签: c optimization string-concatenation

我正在寻找一个示例代码或如何改进下面的代码(它是非常慢的IMO,但我可以编写)以最快的方式将2D数组转换为char*和将char复制到其中。

char*
join(int c, size_t arrsize, const char* arr[])
{
  char *buf, *tbuf, *val;
  size_t i, vsize, total;

  buf = malloc(1);
  for(i = total = 0; i < arrsize; ++i) {
    val = arr[i];
    vsize = strlen(val);

    if((tbuf = realloc(buf, total + vsize + 2)) == NULL) {
      if(buf != NULL)
        free(buf);
      return NULL;
    }

    buf = tbuf;

    memcpy(buf + total, val, vsize);
    total += vsize;

    buf[total] = c;
    total += 1;
  }

  buf[total] = '\0';
  return buf;
}

致电

const char *foo[] = { "a", "b", "c"};
char *baa = join(' ', 2, foo); //a b c
if(baa) {
  printf("%s\n", baa);
    free(baa);
} else {
    printf("No memory\n");
}

如何优化?

4 个答案:

答案 0 :(得分:1)

我同意Shawn,单个malloc调用可能更有利。在他发布答案的时候,我正在编写自己的代码:

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

char* join(char delimiter, size_t arrsize, const char* arr[]) {
    size_t i;
    size_t total;
    char* joined;

    for (i = total = 0; i < arrsize; i++) {
        if (arr[i] != NULL) 
            total += strlen(arr[i]) + 1; // size of c-style string + delimiter
    }

    // Note that last delimiter will actually be null termination
    joined = (char*)malloc(sizeof(char) * total);

    if (joined != NULL) {
            // first character isn't guaranteed to be null termination
            // set it so strcat works as intended, just in case
            joined[0] = '\0';
        for (i = 0; i < arrsize; i++) {
            if (arr[i] != NULL) {
                strcat(joined, arr[i]);

                if ((i + 1) != arrsize) 
                    strncat(joined, &delimiter, 1);
        }
    }

    return joined;
}

int main(int argc, char** argv) {
    const char* foo[] = { "aasdasd", "bgsfsdf", "asdasisc" };

    char* baa = join(' ', 3, foo);

    if (baa != NULL) {
        printf("%s\n", baa);
        free(baa);
    } else {
        printf("No memory\n");
    }

    return 0;
}

我做了一些改变,取决于我认为你想要完成的事情,加入的第一个参数是用于分隔组合字符串的字符分隔符,第二个是arr中字符串的数量,第三个显然是数组

代码应该编译运行,yeilding“assdasd bgsfsdf asdasisc”,也就是说,当我填充数组进行测试时,我在键盘上捣碎了:P

答案 1 :(得分:0)

而不是重复调用realloc,您可以在arr之间进行第一次循环以确定总长度,然后只调用一次malloc。在此之后,只需再次循环arr并使用正确的偏移调用memcpy

或许这样的事情(注意这是未经测试并且可能包含错误):

/* join strings in arr with c as separator */
char* join(int c, size_t arrsize, const char* arr[]) {
  char *buf;
  size_t i, len, total = 0;

  /* determine total length of all strings */
  for (i = 0; i < arrsize; ++i) {
    total += strlen(arr[i]);
  }

  /* allocate mem */
  buf = malloc(total + arrsize);
  if (!buf) return NULL;

  /* copy in all strings from arr */
  total = 0;
  for (i = 0; i < arrsize; ++i) {
    len = strlen(arr[i]);
    memcpy(buf + total, arr[i], len);
    total += len;

    /* append separator (or NUL if last string) */
    buf[total++] = (i == arrsize-1) ? '\0' : c;
  }

  return buf;
}

答案 2 :(得分:0)

如果你可以用arr限制字符串的总大小(例如,2048)。有了这个,您可以删除strcpy和strlen函数中迭代的开销:

char*
join(int c, size_t arrsize, const char* arr[])
{
  char *buffer;
  size_t i, vsize;
  char *b;

  buffer = malloc(2048);
  b = buffer;
  vsize = 0;
  for(i = 0; i < arrsize; ++i) {
    char *p = arr[i];
    while (*p) {
      *b = *p; 
      b++; p++;
      vsize++;
    } 
    *b = c; b++;
  }

  buffer[vsize++] = '\0';
  return realloc(buffer, vsize);
}

答案 3 :(得分:0)

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

char* join(char c, size_t arrsize, const char* arr[]){
    size_t i, total, len[arrsize];
    char *buff, *ret;

    for(total=i=0;i<arrsize;++i)
        total+=(len[i]=strlen(arr[i]));
    if(NULL==(ret=buff=(char*)malloc((total + arrsize)*sizeof(char))))
        return NULL;
    for(i=0;i<arrsize;++i){
        memcpy(buff, arr[i], len[i]);
        buff+=len[i];
        *buff++=c;
    }
    *--buff='\0';
    return ret;
}

int main(){
    const char *foo[] = { "a", "b", "c"};
    char *baa = join(' ', sizeof(foo)/sizeof(char*), foo); //a b c
    if(baa) {
        printf("\"%s\"\n", baa);
        free(baa);
    } else {
        printf("No memory\n");
    }
    return 0;
}