Fastest way to convert 2D-array into char* array and copy a char into end of string

若如初见. 提交于 2019-12-25 06:55:34

问题


I'm looking for an example code or how to improve the below code (that it's very slow IMO, but it's that I can write) to the fastest way to convert an 2D-array into a char* and copy a char to it.

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;
}

calling

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");
}

How can this be optimised?


回答1:


I agree with the Shawn, a single malloc call is probably more advantageous. I was writing up my own take on your code while he was posting his answer:

#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;
}

I made some changes depending on what I thought you were trying to accomplish, the first argument to join is the character delimiter used to separate combined strings, the second is the number of string in arr, and the third is obviously the array.

The code should compile and run, yeilding "assdasd bgsfsdf asdasisc", that is, what I mashed on my keyboard when populating the array to test :P




回答2:


If you can bound the total size of the strings in arr (e.g., 2048). With this you can remove the overhead of iterations in strcpy and strlen functions:

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:


#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;
}



回答4:


Instead of repeated calls to realloc, you could do a first loop across arr to determine the total length then call malloc just the once. After that it's just a matter of looping through arr again and doing calls to memcpy with the correct offsets.

Something like this perhaps (note that this is untested and may contain errors):

/* 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;
}


来源:https://stackoverflow.com/questions/11583613/fastest-way-to-convert-2d-array-into-char-array-and-copy-a-char-into-end-of-str

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!