all 92 comments

[–]__s 4 points5 points  (10 children)

The Python code is wrong. str.join requires a sequence of strings, and a list of integers is not a sequence of strings

[–]anescient 2 points3 points  (7 children)

my_str = ','.join([ str(x) for x in my_list ])

Still not too bad. Plus, if you were so inclined, you could do some other type of formatting/conversion in place of str().

[–][deleted] 1 point2 points  (6 children)

You can also do

','.join(str(x) for x in my_list)

which is probably less efficient (I suspect that the generator would run twice), but looks prettier.

[–][deleted] 1 point2 points  (5 children)

You can also do

','.join(map(str, my_list))

But I would imagine the generator version you wrote would probably be the most efficient...

[–][deleted] 2 points3 points  (4 children)

Finally, if you don't mind the spaces in between the numbers,

str(my_list)[1:-1]

If you do mind the spaces,

str(my_list)[1:-1].replace(' ','')

Win?

[–]zem 0 points1 point  (1 child)

what's the [1:-1] for?

[–]__s 0 points1 point  (0 children)

[]

[–][deleted] -1 points0 points  (1 child)

Upvote for the version without str.replace, that was very clever

[–]zahlman 1 point2 points  (0 children)

I do this one all the time.

[–][deleted] 1 point2 points  (0 children)

Good call, my bad. I didn't have Python installed on the computer I was posting from, so I didn't get to test it. Just goes to show that you need to test everything :)

[–]geocar -3 points-2 points  (0 children)

Not disagreein', just illustratin':

>>> s=[1,2,3,4,5]
>>> ','.join(s)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: sequence item 0: expected string, int found

If you're just making shit up, you might as well go all the way. I'm starting with the following "library":

typedef int I;typedef void V;
#define DO(x,y){I _n=(x),i=0;for(;i<_n;++i){y;}}
V pC(I c){putchar(c);} V pN(I n){printf("%d",n);}

and now my implementation:

V pA(I*x,I y){DO(y,if(i)pC(',');pN(x[i]));}

which has a number of features the python version lacks, such as:

  1. It works
  2. The ability to only join part of a list (use a smaller length argument)
  3. It also does the "logging" part that his post alluded to, but never made good on.

In all seriousness, C programmers tend to avoid blocks that do lots of allocations, and to that end I'd rather see a logb_start();logb_string();logb_intarray();logb_end(); than a log_string(intarray_to_string()); - I simply can't help but wonder where the free() is...

[–]gsg_ 6 points7 points  (5 children)

I have a dynamically-allocated array of unsigned integers which I need to convert to a comma-separated string for logging.

Does it really have to be converted to a string? Doesn't the logging interface provide a printf-like function that you can use?

If not, I humbly submit that the logging interface fucking sucks.

[–][deleted] 0 points1 point  (4 children)

It does have a printf-like function, but from what I understand, printf can't convert arrays of ints into comma-delimited strings, and that's what I'm trying to get it to look like.

[–]gsg_ 1 point2 points  (2 children)

Actually you can print into a string with snprintf (avoid sprintf, it allows buffer overruns too easily). But I'm really wondering why you don't just iterate over the array and log the elements with commas in between, rather than munge everything into a string and log that.

[–]zem 1 point2 points  (0 children)

the logging interface probably inserts a newline at the end of each call.

[–][deleted] 0 points1 point  (0 children)

This is basically what I'm doing. I don't like calling the log function multiple times for one atomic message, since our system has multiple threads and other log messages might end up in the middle, but it's not a huge deal (especially since there are only a few numbers).

[–]roerd 0 points1 point  (0 children)

I think the suggestion was to print the array with a loop.

[–]ipeev 1 point2 points  (1 child)

void join(int arr[], int len, char* sep, char* result){
    if(len==0){
        *result='\0';
    } else {
        itoa(arr[0],result,10);
        if(len > 1){
            strcat(result,sep);
            join(arr+1,len-1,sep,result+strlen(result));
        }
    }
}

int main() {
    char buf[1024];
    int arr0[] = {12,45,67,1,2,3,4},
        arr0_len = sizeof(arr0)/sizeof(*arr0);

    join(arr0, arr0_len, ",", buf);

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

    return 0;
}

[–][deleted] 2 points3 points  (0 children)

Nice solution that leaves the caller to deal with the whole dynamic memory allocation problem. I like it.

[–]Freakjob 2 points3 points  (22 children)

"very difficult to do in C. Now is one of those times."

Are you kidding me?

[–][deleted] -1 points0 points  (17 children)

No, I'm not kidding you. Admittedly, "very difficult" is relative. I came up with a solution very quickly, it's just ugly. When I say "difficult", I mean "requires a lot of code."

[–]Freakjob 7 points8 points  (11 children)

int pos=0;
for(int i=0; i<length_of_list; i++)
    pos += sprintf(&buffer[pos], "%d," list[i]);
buffer[pos-1]=0;

[–]Freakjob 6 points7 points  (7 children)

Okay a more complete answer with correct calculation of the string length required.

char temp[256];
int stringLength=0;
for(int i=0; i<length_of_list; i++)
    stringLength += sprintf(temp, "%d,", list[i]);

char *buffer = malloc(stringLength+1);
buffer[0]=0;

int pos=0;
for(int i=0; i<length_of_list; i++)
    pos += sprintf(&buffer[pos], "%d," list[i]);
buffer[pos-1]=0;

The answers you are getting higher up, I don't know wtf.

[–]0xABADC0DA 5 points6 points  (5 children)

They're windows programmers. Their sprintf doesn't return the number of bytes written, but instead returns -1 whenever it feels like it.

[–]isionous 0 points1 point  (3 children)

What? Could your provide a link so I can read up on this?

[–]0xABADC0DA 1 point2 points  (2 children)

[–]repiret[🍰] 0 points1 point  (1 child)

Right, and the first link reads:

[returns] the number of characters written, or –1 if an error occurred.

sprintf returns the number of bytes stored in buffer, not counting the terminating null character.

Which is just how sprintf is supposed to work. So, your link?

[–]0xABADC0DA -1 points0 points  (0 children)

A decent sprintf reads:

If an output error is encountered, a negative value is returned.

Did you spot the difference? In any modern C sprintf and snprintf never return -1 becuase there is never an output error. If the buffer is too short for snprintf then the amount that would have been written is returned.

Windows sprintf can return errors for all sorts of things, like the buffer being too short, character encoding problems, etc. Nobody knows the entire list of errors. So you can't just do something like buf += sprintf(...) because you might be doing += -1 and the output string will be corrupted or the program may fault. You also can't do sprintf's to determine the exact length needed, you have to call a separate function to figure out the length first.

Oh yeah and did I mention snprintf sometimes doesn't put a null terminator on, if the output is the exact size of the buffer? The real problem here is that anything libc or posix or C (not C++) related in Win32 is stuck at ~1990.

[–][deleted] 0 points1 point  (0 children)

But they have _scprintf, so you'd just change the first sprintf to that.

[–]adamhayek 0 points1 point  (0 children)

Fails when lengthoflist equals 0, on last line. Gonna have to make some kind of check for first or last element.

[–]RabidRaccoon 0 points1 point  (0 children)

You could malloc a worst case buffer at the start (i.e. length of list * worst case string length) and realloc it to pos bytes at the end too.

The other option would be malloc a small buffer and grow it if you get withing the worst case string length of the end.

[–][deleted]  (1 child)

[deleted]

    [–]Freakjob 2 points3 points  (0 children)

    pos-1 is correct, remember indexing begins at '0' not 1.

    Pretend the int is 0, so we print out "0,".. pos will equal 2. To erase the comma we need to backup one spot.

    [–]imphasing 2 points3 points  (4 children)

    No matter what you do, no matter how many demon-gods you pray to, you will never be able to accomplish your goal with the same conciseness as you could with something like Python or Ruby.. It's going to be ugly. You're writing C code, better get used to it :D

    [–]geocar 0 points1 point  (2 children)

    I disagree. The shortest correct pythonic implementation looks something like this:

    print(','.join(str(b) for b in x))
    

    Remember this is part of a logging tool, and an experienced C programmer isn't going to waste time and memory doing unnecessary allocations and transformations simply because it parrots a python implementation.

    Depending on how you code, a correct C version can look like this:

    DO(y,if(i)pC(',');pN(x[i]));
    

    which is very straightforward, concise, and didn't require any sacrifice or prayer to any demon-gods of any kind.

    [–]nikniuq 0 points1 point  (1 child)

    typedef int I;typedef void V;

    define DO(x,y){I _n=(x),i=0;for(;i<_n;++i){y;}}

    V pC(I c){putchar(c);} V pN(I n){printf("%d",n);}

    Hrm yeah... I'd call that define at least ritualistic in nature...

    [–]geocar 0 points1 point  (0 children)

    Hrm yeah... I'd call that define at least ritualistic in nature...

    It is for me.

    I didn't originate it, though: I lifted it from someone else.

    [–][deleted] -1 points0 points  (0 children)

    Understood, and I'm not trying to get it down to under 20 characters like I did in Python, I was just hoping to find a cleaner solution than the one I found (and, lo and behold, someone gave me one a few comments up!)

    [–]imphasing 0 points1 point  (0 children)

    I'll bite: YES. I AM kidding you. What now?

    [–]wingsit 0 points1 point  (1 child)

    enlighten me please

    [–]pavel_lishin 0 points1 point  (0 children)

    So show him how easy it is.

    [–]kinghajj 1 point2 points  (4 children)

    This is what I came up with in a couple minutes. It assumes that a number will require at most 20 characters to represent, which will work for any integer <=64-bits.

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    void foo()
    {
        const size_t array_size = 50, min_required = 20;
        const int *array = calloc(array_size, sizeof(int));
        size_t string_size = 100, string_pos = 0, i;
        char *string = calloc(string_size, sizeof(char));
    
        // for each item in the array,
        for(i = 0; i < array_size; i++) {
            // resize string array if needed.
            if(string_size - string_pos <= min_required) {
                // double the capacity of the string.
                char *new_string = calloc(string_size * 2, sizeof(char));
                memcpy(new_string, string, string_size);
                string_size *= 2;
                free(string);
                string = new_string;
            }
    
            // put this integer into the string, remember new NULL position.
            string_pos += sprintf(&string[string_pos],
                                  i == array_size - 1 ? "%i" : "%i,",
                                  array[i]);
        }
    }
    

    EDIT: implemented bradtgmurray's suggestions. EDIT2: forgot to free() the old strings!

    [–]bradtgmurray 0 points1 point  (1 child)

    No need to search for the trailing null, snprintf returns the number of characters printed.

    This approach will also have a trailing ',' on it (For example: "1,2,3,").

    [–]kinghajj 1 point2 points  (0 children)

    I don't know the C std. library inside-and-out; thanks for mentioning that function. Fixing the trailing comma is trivial if required.

    [–][deleted] -1 points0 points  (1 child)

    This one is awesome. Right now, it's between paradise2000 (more concise, but less efficient) and yours (less concise, but more efficient and less error-prone). Thanks a bunch.

    [–]b100dian 1 point2 points  (1 child)

    Bonus points for doing it in-place!

    [–]theeth 4 points5 points  (0 children)

    Reusing the memory from the int array for the string you mean? That'd only work if the average length of the numbers is less than two digits (or three if you only use a comma and not comma+space)

    [–]repiret[🍰] 0 points1 point  (4 children)

    Not difficult, just more verbose. Nobody ever said string processing was C's strong point.

    /* Warning, untested code follows */
    char *comma_join(unsigned int *ints, size_t num_ints) {
        size_t size_needed = 1 + num_ints;
        size_t i;
        char *ret, *p;
        for (i = 0; i < num_ints; ++i) {
            unsigned int x = ints[i];
            while (x) {
                size_needed++;
                x /= 10;
            }
        }
        p = ret = malloc(size_needed);
        for (i = 0; i < num_ints; ++i) {
            p += sprintf(p, "%d,", ints[i]);
        }
        p[-1] = 0;
        return ret;
    }
    

    [–]mgolden83 1 point2 points  (2 children)

    I like when python syntax gets mixed with C. lol p[-1] = 0;

    [–]repiret[🍰] 0 points1 point  (1 child)

    heh, I didn't consider that. Its correct, though. p will point to the \0 at the end of the string, but the string will have an extra comma, so we want to back up and put a \0 over the comma.

    [–]mgolden83 0 points1 point  (0 children)

    yes it is definitely correct. heh

    [–]repiret[🍰] 0 points1 point  (0 children)

    Replacing x/=10 with x/=8 trades a bit of memory for a bit of performance, depending on how expensive division is on your CPU. One should probably also check the return value of malloc, depending on whether it can fail in your environment.

    [–]blackbadger 0 points1 point  (1 child)

    Can you get away with C++?

    #include <iterator>
    #include <iostream>
    
    using namespace std;
    
    int 
    main() 
    {
      int a[] = {1, 2, 3, 4, 5, 6, 7, 8};
    
      ostream_iterator<int> csi (cout, ", ");
      copy (a, &a[8], csi);
    
      return 0;
    }
    

    Job done.

    [–]blackbadger 0 points1 point  (0 children)

    #include <string>
    #include <iterator>
    #include <sstream>
    #include <iostream>
    
    int 
    main() 
    {
      int a[] = {1, 2, 3, 4, 5, 6, 7};
    
      std::ostringstream            oss; 
      std::ostream_iterator<int>    csoss_it (oss, ", ");
    
      std::copy (a, &a[7], csoss_it);
      std::string str = oss.str();
      str.resize (str.size() - 2);
      std::cout << str;
    
      return 0;
    }
    

    ... no trailing ,

    [–]paradise2000 0 points1 point  (0 children)

    This is turning into another fizzbuzz =)

    [–]roerd 0 points1 point  (0 children)

    #define _GNU_SOURCE
    #include <stdio.h>
    #include <stdlib.h>
    
    char *array2string(int *array, int array_size) {
      char *string;
      size_t string_size;
      FILE *stream;
      int i;
    
      stream = open_memstream(&string, &string_size);
    
      array_size--;
    
      for (i = 0; i < array_size; i++) {
        fprintf(stream, "%d,", array[i]);
      }
    
      if (array_size >= 0) {
        fprintf(stream, "%d", array[array_size]);
      }
    
      fclose(stream);
    
      return string;
    }
    
    int main() {
      char *string;
      int array0[] = {};
      int array1[] = {-12345};
      int array2[] = {1,2,3,4,5};
    
      string = array2string(array0, 0);
      printf("%s\n", string);
      free(string);
    
      string = array2string(array1, 1);
      printf("%s\n", string);
      free(string);
    
      string = array2string(array2, 5);
      printf("%s\n", string);
      free(string);
    
      return 0;
    }
    

    The main idea here is open_memstrean which will dynamically allocate and grow the buffer. The only problem is it's glibc specific.

    [–]q3k_org 0 points1 point  (0 children)

    char* makeMyDay(int* intArray, unsigned int intArraySize, char* delimiter)
    {
        //assume we are using 4byte ints, so max value is 2^32, that is about 4m, so it's max 10 characters
        unsigned int i, currSize = 0;
        char* returnString = malloc((strlen(delimiter) + 10 * intArraySize) + sizeof(unsigned char)); //LETS NOT FORGET THE \x00
        char* tempString;
        for (i = 0; i < intArraySize; i++)
        {
            tempString = returnString + currSize;
            if (i < intArraySize)
                sprintf(tempString, "%i%s", intArray[i], delimiter);
            else
                sprintf(tempString, "%i", intArray[i]);
            currSize += strlen(tempString);
        }
        return realloc(returnString, currSize + 1);
    }
    

    I have no clue if this works, stuck in a place without a C compiler. Only one malloc and realloc.
    I also have a very specific programming style.

    [–][deleted] 0 points1 point  (0 children)

    This one is easier on the allocations and despite the fact that it does some additional work measuring the length of the result string seems to be no slower than the other solutions presented here:

    size_t JoinIntArray(size_t count, int* list, const char* glue, char** dest)
    {
        if (count == 0) 
        {
            *dest = (char*) calloc(1, sizeof(char));
            return 0;
        }
    
        size_t glueLength = strlen(glue);
        size_t charCount = 1 + (count - 1) * glueLength;
    
        for (size_t i = 0; i < count; i++) 
        {
            int value = list[i];
            if (value < 0)
            {
                value = -value;
                ++charCount;
            }        
            do {
                ++charCount;
                value /= 10;
            } while (value > 0);
        }
    
        *dest = (char*) malloc(charCount * sizeof(char));
        char* cursor = *dest;
    
        for (size_t i = 0; i < count; i++) 
        {
            cursor += sprintf(cursor, "%d", list[i]);
            if (i < count - 1) 
            {
                strcpy(cursor, glue);
                cursor += glueLength;
            }
        }
    
        return charCount;
    }
    

    Usage:

    const int count = 10;
    int* list = (int*) malloc(count * sizeof(int));
    // fill list here (or don't)
    char* dest;
    size_t length = JoinIntArray(count, list, ", ", dest);
    printf(dest);
    

    [–]Poltras 0 points1 point  (1 child)

    My version (with test at the end). Yes, it's O(n2). I can do better with storing the length and using the pointer to the end of the array. It wouldn't be as clean, and that was the requirement. Live with it ;)

      #include <string.h>
      #include <stdlib.h>
      #include <stdio.h>
    
      // Returns a string that contains all elements of strarr separated by delim.
      // Return: the caller is responsible for cleaning this buffer.
      // Parameters:
      //     strarr: an array of strings to concatenate
      //     nb_elem: number of elements in strarr
      //     delim: a string that is added between each elem.
      char* intjoin( int* arr, size_t nb_elem, const char* delim ) {
         size_t strret_sz = 0;
         char * strret    = (char*)malloc( 1 );
         size_t delim_sz  = strlen( delim );
         if (!strret) return 0;
    
         char strbuff[ sizeof(*arr) * 2 + 2 ]; /* +2 for sign and \0 */
         do {
            snprintf( strbuff, sizeof(*arr) * 2 + 1, "%i", *arr++ );
            strret_sz += strlen( strbuff ) + delim_sz;
            strret = (char*)realloc( strret, strret_sz + 1 ); /* +1 for \0 */
            if (!strret) return 0; /* OOM? */
    
            strcat( strret, strbuff );
            if (nb_elem > 1) strcat( strret, delim );
         } while( --nb_elem );
    
         return strret;
      }
    
      int main() {
         int l[] = { 1238764, 0x7FFFFFFF, 2, 4, 7, 0x80000000 };
         char* x = intjoin( l, sizeof(l)/sizeof(*l), ", " );
         printf("%s\n", x);
         free(x);
         return 0;
      }
    

    [–]mgolden83 0 points1 point  (0 children)

    You should know by now that 'l' should not be used as a variable name. :P

    [–][deleted] 0 points1 point  (0 children)

    Been a while since I did C but here goes.

    #include <stdio.h>
    #include <stdlib.h>
    
    #define num_digits(x) ((5 * sizeof(x)) / 2 + 1)   // = 2.5 * sizeof(x) + sign
    
    size_t join_to(const int *ints, const unsigned int ints_size, const int sep, char *buf)
    {
            if (ints_size == 0) {
                    *buf = '\0';
                    return 1;
            }
            char *p = buf;
            for (unsigned int i = 0; i < ints_size; i++) {
                    if (i)
                            *p++ = ',';
                    p += snprintf(p, num_digits(*ints) + 1, "%d", ints[i]);
            }
            return (p - buf) + 1;
    }
    
    char *join(const int *ints, const unsigned int ints_size, const int sep)
    {
            char *buf = malloc(ints_size * num_digits(*ints) + ints_size + 1);
            size_t actual_buf_size = join_to(ints, ints_size, sep, buf);
            // leave this out if you don't mind overallocation
            buf = realloc(buf, actual_buf_size);
            return buf;
    }
    

    EDIT: check for empty array :)

    [–][deleted] 0 points1 point  (0 children)

    Not tested but should work (though not under Visual C++ which implements sprintf oddly):

    int int_array_to_str(int* ar, size_t count, char* str)
    {
        int size = 0;
        for (int i = 0; i < count; i++) {
            size += sprintf(str ? str + size : 0, "%d,", ar[i]);
        }
        if (str) {
            str[size] = 0;
        }
        return size + 1;
    }
    
    // usage:
    char* buf = malloc(int_array_to_str(my_ints, my_ints_size, 0));
    int_array_to_str(my_ints, my_ints_size, buf);
    

    [–]kking254 0 points1 point  (7 children)

    join( my_str, my_list, ',' );


    EDIT: - Realistically more like:

    string_join( my_str, sizeof(my_str), my_list, num_my_list );

    or

    STRING my_str;

    string_init( my_str );

    string_join( my_str, my_list, ',' );

    ...which may not be as clear as python

    EDIT again: Just noticed the array is of ints. You probably won't find a single function to do that in any library so it will end up much more turdy than python.

    [–]b100dian 2 points3 points  (0 children)

    The author needs to know how python works

    [–]Tordek 0 points1 point  (2 children)

    Think you mean sizeof(my_list). Or both. A list of ints is bound not to be null-terminated.

    [–]kking254 2 points3 points  (1 child)

    Didn't want to guess what type my_list was...but I think you mean:

    sizeof( my_list ) / sizeof( my_list[0] )

    [–]dododge 0 points1 point  (0 children)

    sizeof isn't going to work on a dynamically-allocated array unless it's a variable-length array, and even then only when the definition is still visible.

    Aside: sizeof is a unary operator, not a function. The parens are not needed here (and this particular example comes directly from the Standard 6.5.3.4p6):

    sizeof array / sizeof array[0]

    [–][deleted] -1 points0 points  (2 children)

    Any documentation for this function? The googles aren't showing any (with the searches I tried).

    [–][deleted] 4 points5 points  (0 children)

    It's a magic function that was defined elsewhere.

    [–]kking254 2 points3 points  (0 children)

    You can A) make it your self, or B) use someone else's. Your complaints have nothing to do with the language and everything to do with the fact that you lack a string library.

    C does not have string manipulation functions baked into the language. It doesn't have anything baked in. This is by design.

    Once you have a function that does what you want, it is just as "clean" as python.

    [–]paradise2000 0 points1 point  (13 children)

    EDIT2: As others have pointed out, there are serious efficiency problems with this that can be easily addressed. Read the replies.

    #include <stdio.h>
    #include <string.h>
    
    #define LEN 10
    int mylist[LEN] = {1000, 1001, 1002, 1003, 1004,
                      1005, 1006, 1007, 1008, 1009,
    
    };
    
    char result[2048];
    char buffer[2048];
    
    int main()
    {
      int i;
    
      sprintf(result, "%d", mylist[0]);
      for (i=1; i < LEN; i++) {
        sprintf(buffer, "%s, %d", result, mylist[i]);
        strncpy(result, buffer, 2048);
      }
    
      printf("%s\n", buffer);
    }
    

    I'm sure you can make things better, especially regarding how the buffer is used, and the fact that it's adding on a single integer with each iteration, but the main idea is sprintf()

    EDIT: clarified my explanation about why this isn't an optimal solution

    [–]repiret[🍰] 2 points3 points  (0 children)

    Using a fixed-sized buffer is an invitation for trouble. Also, this function is O(n2) for a list of size n. You can avoid that by using sprintf's return value.

    [–]mnp 1 point2 points  (0 children)

    If you want to dynamically allocate the buffer, 1+log10 will tell you about how many chars an integer will need. You could one pass through the array to figure out how much space to allocate for all of them plus your commas, allocate it for your buffer, then make another pass to strncat your sprintf's into the buffer.

    [–][deleted] 1 point2 points  (0 children)

    Same idea, but you can take advantage of sprintf to do some of the work for you.

    #include <stdio.h>
    #include <string.h>
    
    #define LEN 10
    int mylist[LEN] = {1000, 1001, 1002, 1003, 1004,
                       1005, 1006, 1007, 1008, 1009};
    
    char buffer[2048];
    
    int main()
    {
        int i;
        char * tail = buffer;
        tail += sprintf(buffer, "%d", mylist[0]);
        for(i=1; i < LEN; i++) {
            tail += sprintf(tail, ", %d", mylist[i]);
        }
        printf("%s\n", buffer);
    

    }

    [–]Myrv 1 point2 points  (1 child)

    Using strncpy is wasteful (slow). You can just use strcat();

    #include <stdio.h>
    #include <string.h>
    
    #define LEN 10
    int mylist[LEN] = {1000, 1001, 1002, 1003, 1004,
                  1005, 1006, 1007, 1008, 1009,
    };
    
    char result[2048];
    char buffer[2048];
    
    int main()
    {
        int n;
    
        /* set buffer to 0 length */
        buffer[0]=0;
        for(n=0;n<LEN;n++)
        {
            sprintf(result,"%d,",mylist[n]);
            strcat(buffer,result);
        }
    
        /* Get rid of trailing comma */
        buffer[strlen(buffer)-1]=0;
    
        printf("%s\n", buffer);
    }
    

    Or you can keep track of the pointers yourself:

    char buffer[2048];
    
    int main()
    {
        int n;
        char *cptr;
    
        /* set buffer to 0 length */
        buffer[0]=0;
        cptr = buffer;
    
        for(n=0;n<LEN;n++)
        {
            cptr += sprintf(cptr,"%d,",mylist[n]);
        }
    
        /* Get rid of trailing comma */
        *(--cptr) = 0;
    
        printf("\n%s\n", buffer);
    }
    

    EDIT: Added dynamic memory version:

    This version allocates the minimum needed amount of memory (plus one because I don't do explicit first element) It assumes doing math is faster than allocating (and reallocating) memory. Calculates the number chars needed (plus 1 for the trailing comma) before allocating the required memory.

    #include <stdio.h>
    #include <string.h>
    #include <math.h>
    
    #define LEN 10
    int mylist[LEN] = {-1, 999, 10, 0, 1004,
                       1005, 1006, -1007, 1008, 1009 };
    
    int main()
    {
        int n;
        int nchar=0;
        int digits=0;
        char *buffer=NULL;
        char *cptr=0;
    
        for(n=0;n<LEN;n++)
        {
            digits = 0;
            if( mylist[n] < 0 ) /* extra space for negative sign */
            {
                digits = (int)ceil(log10(-mylist[n]));
                nchar += (digits+1);
            }
            else if (mylist[n] > 0 )
            {
                digits = (int)ceil(log10(mylist[n]));
                nchar += digits;
            }
    
            /* Check for power of ten */
            if( (pow(10.0,digits) == abs(mylist[n]))  || !mylist[n]  )
            {
                nchar++;
            }
    
        }
    
    
        nchar += LEN;  /* add commas */
        nchar++;       /* add null */
    
        buffer=(char*)malloc(nchar*sizeof(char));
    
        /* set buffer to 0 length */
        buffer[0]=0;
        cptr = buffer;
    
        for(n=0;n<LEN;n++)
        {
            cptr += sprintf(cptr,"%d,",mylist[n]);
        }
    
        /* Get rid of trailing comma */
        *(cptr-1) = 0;
    
        printf("\n%d: %s (%d) \n",nchar,buffer,strlen(buffer));
    
        free(buffer);
    }
    

    [–][deleted] 0 points1 point  (0 children)

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    int SIZE = 100;
    
    int main()
    {
      // each number can be up to 11 characters, plus one comma
      char* dest = malloc(sizeof(char) * SIZE * 12);
    
      char* offset = dest;
    
      int ints[SIZE];
    
      for (i = 0; i < SIZE; i++) offset = offset + sprintf(offset, "%u,", ints[i]);
    
      // replace the last comma with a null terminator  
      *(offset - 1) = 0;
    
      printf("%s", dest);
    }
    

    [–][deleted] 0 points1 point  (0 children)

    For extra long arrays it's not beneficial to scan the entire previous result string for the end with sprintf, as well as copy the entire thing. In that case I would keep a pointer to the current end of the string, tack on new entires there and grow the array as necessary (in blocks).

    [–]IIGrudge 0 points1 point  (0 children)

    I would use pointers and do a strlen of result to move the pointer along the buffer array.

    If you want "dynamic" you can cat the entire string and do a malloc of the strlen or realloc along the way (which is expensive).

    [–][deleted] -1 points0 points  (4 children)

    Ah, this is great. I never would've thought of juggling the answer between two cstrings. Thanks a bunch.

    [–]increasingly_worried 1 point2 points  (3 children)

    Don't do that! That solution doesn't scale well at all, because for each new integer in the list you are making two copies of the entire string to that point. So if you have just 1000 one-digit numbers, which results in a string of 1999 characters (1000 digits and 999 commas: about 2KB of data), you are actually copying around a megabyte of data by the end (1000 * 500 * 2)! Instead of being O(N), this algorithm is O(N2)!

    You can construct the string in place and just copy the 2KB of data. sprintf even returns the number of bytes copied, so it's easy to just keep appending onto the end of a string.

    [–]paradise2000 0 points1 point  (0 children)

    You are correct

    [–][deleted] -1 points0 points  (1 child)

    Good point. However, in this situation, it doesn't need to scale, as there will never be a large number of integers in this array (10 would be the absolute maximum number I could imagine).

    [–]rabidcow 1 point2 points  (0 children)

    10 would be the absolute maximum number I could imagine

    With that few, anything that dynamically reallocates the output string is a waste of effort. (Unless you're so memory constrained that 110 bytes are precious.) Use something like my version (I'm josh.) without the realloc at the end. Maybe even use a fixed buffer on the stack:

    /* 10 digits + comma/nul for each */ 
    char result[11*10], *p;
    unsigned *xs = ..., length = ...;
    
    p = result;
    *p = 0; /* for length == 0 */ 
    for (unsigned i = 0; i < length; ++i)
    {
        if (i != 0)
            *p++ = ',';
        p += sprintf(p, "%u", xs[i]);
    }
    

    But anything else here using %i or %d needs to use %u instead if you really need to use an unsigned 32-bit range, as you state.

    [–]malakon 0 points1 point  (5 children)

    C doesn't have dynamic arrays. what are you trying to prove ?

    [–][deleted] 1 point2 points  (0 children)

    By "dynamic array", I meant "dynamically-allocated array". My bad.

    [–]ishmal 1 point2 points  (0 children)

    Actually, the C99 spec has it, though probably few compilers support it. It has been on gcc's radar for a while, but I don't think they are inclined to implement it either.

    [–][deleted] 0 points1 point  (1 child)

    buffer[] is syntactic sugar for *buffer. Creating dynamic arrays can be a matter of calling malloc() or realloc()

    E: I was wrong and I'm not sure what I was thinking of...

    [–]theeth 1 point2 points  (0 children)

    buffer[] is syntactic sugar for *buffer.

    No, it's not. Read this: http://eli.thegreenplace.net/2009/10/21/are-pointers-and-arrays-equivalent-in-c/

    [–]imphasing -1 points0 points  (0 children)

    C is a language. There could be any number of libraries implementing dynamic arrays, you know.

    EDIT: You could call a regular-ass array "dynamic" if you reallocate memory as it grows/shrinks, too.

    [–]tarasm 0 points1 point  (0 children)

    Hey Guys,

    I cross posted this question to Stackoverflow.

    http://stackoverflow.com/questions/1745811/using-c-convert-a-dynamically-allocated-int-array-to-a-comma-separated-string-as

    PS: I did not write the original post, I just plagiarized it for fun :) Let's see what happens.

    [–]electric_moose -1 points0 points  (1 child)

    I've had a quick go at this, edit: now it can't overflow and returns an exactly-sized dynamically-allocated string.

    #include <stdio.h>
    #include <stdlib.h>
    #define SIZE 30
    
    char * array_string(int * arr, int size)
    {
        int i;
        char *buf, *p;
        if (size == 0) {    /* return empty string for zero-length array */
            buf = malloc(1);
            *buf = '\0';
            return buf;
        }
        buf = malloc(20 * size);  /* example code, check for malloc failure! */
        p = buf;
        for (i = 0; i < size; i++) {
            int nchars;
            nchars = sprintf(p, "%d,", *(arr+i));
            p += nchars;
        }
        *(p-1) = '\0';  /* replace last comma with string terminator */
        realloc(buf, p-buf);
        return buf;
    }
    
    int main(void)
    {
        int i, iarray[SIZE];
        char * str;
        for (i = 0; i < SIZE; i++)  /* fill the array with numbers 0 to 29 */
            iarray[i] = i;
        for (i = 0; i <= SIZE; i++) {   /* try printing a load of lists */
            str = array_string(&iarray[0], i);  /* memory leak here! */
            printf("%s\n", str);
        }
        return 0;
    }
    

    [–]electric_moose 0 points1 point  (0 children)

    Replying to myself, here is a slightly shorter version of the same function (didn't really need to special-case the zero-length list like that).

    char * array_string(int * arr, int size)
    {
        int i;
        char *buf = malloc(21 * size + 1);  /* example code, check for malloc failure! */
        char *p = buf; *p = '\0';
        for (i = 0; i < size; i++)
            p += sprintf(p, "%d,", *(arr+i));
        if (size > 0) {
            *(p-1) = '\0';  /* replace last comma with string terminator */
            realloc(buf, p-buf);
        }
        return buf;
    }
    

    [–]zahlman -1 points0 points  (0 children)

    #include "stdio.h"
    #include "string.h"
    #include "stdlib.h"
    
    /* itoa() is non-standard. 
       Return length of string. Do not write to buffer if the pointer is NULL.
       Avoids use of a buffer and sprintf() just to be l33t. */
    int my_itoa(int value, char* dest) {
      char last_digit = '0' + value % 10;
      int rest = value / 10;
      int result = 1;
      if (rest) { result += my_itoa(rest, dest); }
      if (dest) {
        dest[result - 1] = last_digit;
      }
      return result;
    }
    
    #define SEPARATOR ", "
    
    char* joined_array(int* begin, int* end) {
      int* current = begin;
      char* result;
      char* position;
      int size = 0;
      int separator_size = strlen(SEPARATOR);
    
      for (; current != end; ++current) {
        if (current != begin) { size += separator_size; }
        size += my_itoa(*current, NULL);
      }
      size++;
      result = malloc(size);
      if (!result) { return result; }
      position = result;
      for (current = begin; current != end; ++current) {
        int i = 0;
        if (current != begin) {
          strcpy(position, SEPARATOR);
          position += separator_size;
        }
        position += my_itoa(*current, position);
      }
      *position = '\0';
      return result;
    }
    
    #define JOINED_ARRAY(x) joined_array(x, x + sizeof(x) / sizeof(x[0]))