Expand a C array

Vim, 54, 52, 49 47 keystrokes


2wa0<esc>qqYp<c-a>6ldf @qq@q$dT]dd:%norm dwf{xwC;<CR>gg"0P

Explanation:

2wa0<esc>                     'Move 2 words forward, and insert a 0.
         qq                   'Start recording in register Q
           Yp                 'Duplicate the line
             <c-a>6l          'Increment the next number then move 6 spaces right
                    df        'Delete until the next space
                       @qq@q  'Recursively call this macro

Now our buffer looks like this:

int foo[0] = {4, 8, 15, 16, 23, 42};
int foo[1] = {8, 15, 16, 23, 42};
int foo[2] = {15, 16, 23, 42};
int foo[3] = {16, 23, 42};
int foo[4] = {23, 42};
int foo[5] = {42};
int foo[6] = {42};

and our cursor is on the last line.

Second half:

$                           'Move to the end of the line
 dT]                        'Delete back until we hit a ']'
    dd                      'Delete this whole line.
      :%norm         <CR>   'Apply the following keystrokes to every line:
             dw             'Delete a word (in this case "int")
               f{x          '(f)ind the next '{', then delete it.
                  wC;       'Move a word, then (C)hange to the end of this line, 
                            'and enter a ';'
                             

Now everything looks good, we just need to add the original array-declaration. So we do:

gg        'Move to line one
  "0P     'Print buffer '0' behind us. Buffer '0' always holds the last deleted line,
          'Which in this case is "int foo[6];"

Pyth, 44 bytes

++Khcz\]lJ:z"-?\d+"1"];"VJs[ecKd~hZ"] = "N\;

Test suite

Regular expression and string chopping. Not particularly clever.

Explanation:

++Khcz\]lJ:z"-?\d+"1"];"VJs[ecKd~hZ"] = "N\;
                                                Implicit: z = input()
    cz\]                                        Chop z on ']'
   h                                            Take string before the ']'
  K                                             Store it in K
 +                                              Add to that
         :z"-?\d+"1                             Find all numbers in the input
        J                                       Store them in J
       l                                        Take its length.
+                  "];"                         Add on "];" and print.
                       VJ                       For N in J:
                         s[                     Print the following, concatenated:
                            cKd                 Chop K on spaces.
                           e                    Take the last piece (array name)
                               ~hZ              The current interation number
                                  "] = "        That string
                                        N       The number from the input
                                         \;     And the trailing semicolon.

Retina, 108 104 100 69 bytes

Byte count assumes ISO 8859-1 encoding.

].+{((\S+ ?)+)
$#2];$1
+`((\w+\[).+;(\S+ )*)(-?\d+).+
$1¶$2$#3] = $4;

Beat this, PowerShell...

Code explanation

First line: ].+{((\S+ ?)+)

First, we need to keep the type, array name, and opening bracket (it saves a byte), so we don't match them. So we match the closing bracket, any number of characters, and an opening curly brace: ].+{. Then we match the number list. Shortest I've been able to find so far is this: ((\S+ ?)+). We match any number of non-space characters (this includes numbers, possible negative sign, and possible comma), followed by a space, that may or may not be there: \S+ ?. This group of characters is then repeated as many times as needed: (\S+ ?)+ and put into the large capturing group. Note that we don't match the closing curly brace or semicolon. Third line explanation tells why.

Second line: $#2];$1

Since we only matched a part of input, the unmatched parts will still be there. So we put the length of the list after the unmatched opening bracket: $#2. The replace modifier # helps us with that, as it gives us the number of matches a particular capturing group made. In this case capturing group 2. Then we put a closing bracket and a semicolon, and finally our whole list.

With input short array[] = {4, 3, 2, 1};, the internal representation after this replacing is:

short array[4];4, 3, 2, 1};

(note the closing curly brace and semicolon)

Third line: +`((\w+[).+;(\S+ )*)(-?\d+).+

This is a looped section. That means it runs until no stage in the loop makes a change to the input. First we match the array name, followed by an opening bracket: (\w+\[). Then an arbitrary number of any characters and a semicolon: .+;. Then we match the list again, but this time only numbers and the comma after each number, which have a space following them: (\S+ )*. Then we capture the last number in the list: (-?\d+) and any remaining characters behind it: .+.

Fourth line: $1¶$2$#3] = $4;

We then replace it with the array name and list followed by a newline: $1¶. Next, we put the array name, followed by the length of previously matched list, without the last element (essentially list.length - 1): $2$#3. Followed by a closing bracket and assigment operator with spaces, and this followed by the last element of our number list: ] = $4;

After first replacing, the internal representation looks like this:

short array[4];4, 3, 2, 
array[3] = 1;

Note that the closing curly brace and the semicolon disappeared, thanks to the .+ at the end of third line. After three more replacings, the internal representation looks like this:

short array[4];
array[0] = 4;
array[1] = 3;
array[2] = 2;
array[3] = 1;

Since there's nothing more to match by third line, fourth doesn't replace anything and the string is returned.

TL;DR: First we change up the int list format a bit. Then we take the last element of the list and the name, and put them after the array initialization. We do this until the int list is empty. Then we give the changed code back.

Try it online!