Given a base type T, this can be augmented with * or [], each meaning pointer and array. For example, []*T means "array of pointer to T" and *[]T means "pointer to array of T".

Let's call * and [] type modifiers. C has a way of ordering these modifiers tied to the evaluation order. []*T in C-style becomes T *[], and *[]T becomes T (*)[]. You may be able to understand how the conversion works by having a look at the examples below. An explanation is also given at the end of this post.

* -> *
[] -> []
[]* -> *[]
*[] -> (*)[]
*[]* -> *(*)[]
[]*[] -> (*[])[]
*[][]* -> *(*)[][]
[]**[] -> (**[])[]
[]*[]* -> *(*[])[]
*[]*[] -> (*(*)[])[]

Your program or function should process an input string to an output string as the examples above. The input will only contain * and [] without whitespaces.

This challenge is this challenge in reverse, simplified.

Rules for C-fix:

  • All of the *s always come before all of the []s (in real C code, the variable name comes between the last * and the first []).
  • Evaluation starts in the middle, where the variable name would be.
  • If there is both a * on the left and a [] on the right, without any parentheses to determine the order, the [] is bound first, and comes first in prefix:
    • C-fix *[]
      = C *a[] (where a is the variable name) = "array of pointers" =
      prefix []*.
  • In order to change the order of evaluation so that a * gets bound first, it must be put in parentheses (with where the variable name would be):
    • prefix *[]
      = "pointer to an array" = C (*a)[](where a is the variable name) =
      C-fix (*)[].

From the last example, (*(*)[])[] in actual C code would be something like int (*(*a)[])[] (where a is the variable name). The evaluation starts from a and [] is bound first unless a set of parentheses blocks the binding.

If you put int (*(*a)[])[] to cdecl.org, the output is "declare a as pointer to array of pointer to array of int". This is because:

  • The first * is bound first due to the parentheses.
  • There are no parentheses between the variable name and the [], causing that to be bound before the next *.
  • Then, the next * is bound because it is in the parentheses with the variable name, whereas the remaining [] is not.
  • Finally, the remaining [] is bound.

This is *[]*[]int a in prefix. Hence, *[]*[] -> (*(*)[])[].

  • 1
    \$\begingroup\$ "The pattern is straightforward" - in that case please just explain it! \$\endgroup\$ Apr 10, 2022 at 11:54
  • \$\begingroup\$ @JonathanAllan Umm, I thought this is one of the cases where explaining in plain English makes it more complicated, or else if I provide a formal definition, that definition basically becomes a solution with some tweaks. \$\endgroup\$
    – xiver77
    Apr 10, 2022 at 12:13
  • 2
    \$\begingroup\$ Not knowing this I can't extract the rules from the examples. All I can do is assume the one answer now is correct and implement something that has the same effect. Hence I have -1 and VTC until I can understand the spec. \$\endgroup\$ Apr 10, 2022 at 12:17
  • 3
    \$\begingroup\$ ...try forgetting C entirely and just talking about what this challenge is actually asking of us maybe? \$\endgroup\$ Apr 10, 2022 at 19:36
  • 1
    \$\begingroup\$ If you can confirm the Curry answer does the correct thing I'd be happy to edit in an explanation that I find satisfactorily clear. \$\endgroup\$
    – Wheat Wizard
    Apr 11, 2022 at 3:19

5 Answers 5


Curry (PAKCS), 90 bytes

f s@(""?"[]")=s
f(s++"*")='*':f s
f(s++"*[]")="(*"++f s++")[]"

Try it online!

  • 1
    \$\begingroup\$ You can save 11 bytes with some weaker pattern matching (I think) \$\endgroup\$
    – allxy
    Apr 12, 2022 at 10:28
  • \$\begingroup\$ @allxy In Curry, a function may return multiple values at the same time. When there are multiple matching rules, Haskell will choose the first one, while Curry will choose all of them. So if you add the rule f s=s, then f "[]*" would have two return values: "*[]" and "[]*": Try it online!. \$\endgroup\$
    – alephalpha
    Apr 12, 2022 at 10:49
  • \$\begingroup\$ Oh. That's... interesting... \$\endgroup\$
    – allxy
    Apr 12, 2022 at 19:40

Retina 0.8.2, 52 bytes


Try it online! Link includes test cases. Explanation:


Process any initial []s or *s into an output line.


Repeat until there is nothing left to process.


Delete the original input line once there is nothing left.


Process some more []s and *s.


Charcoal, 27 bytes


Try it online! Link is to verbose version of code. Explanation:


Loop over all of the input characters.


If the current character is a *, then prepend it. Otherwise, append it, but if the output string starts with a * then wrap it in () first.


Output the final string.


Python 3.8+, 92 83 bytes

f=lambda p,c="":f(p[1:],["*"+c,[f"({c})",c][c[:1]!="*"]+p[0]][p[0]>"*"])if p else c

Try it online!


C (clang), 119 117 bytes

-2 bytes thanks to @ceilingcat

*b;f(char*a,l){return l&&asprintf(&b,a[--l]<43?"*%*s":a[l]<93?:--l&&a[l-1]<43?l--,"(*%*s)[]":"%*s[]",l,f(a,l))?b:"";}

Try it online! Takes input as a character array and its length; returns an allocated string.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.