Environment variables are simple key-value pairs of strings. An array can not be an environment variable.
However, you may pass the values of your a array to your bash -c script:
bash -c 'printf "%s\n" "$@"' bash "${a[@]}"
or, if you want to call the array b in the script:
bash -c 'b=( "$@" ); printf "%s\n" "${b[@]}"' bash "${a[@]}"
In both of these cases, the elements of array a are passed on the command line of the script. This means that they will show up in "$@" (in "$1", "$2", etc.) inside your bash -c script.
What's happening in your question is that the command
a=('Apple Tomato' 'Banana Carrot') bash -c '...'
sets the variable a to the string (Apple Tomato Banana Carrot). This is the value of the environment variable a in the bash -c script:
$ a=('Apple Tomato' 'Banana Carrot') bash -c 'printf "%s\n" "$a"'
(Apple Tomato Banana Carrot)
If you really needed to pass the data as an environment variable, you may do so by deciding on a delimiter and then flattening your array into a single string.
For example, using :
IFS=:
b="${a[*]}" bash -c 'set -f; IFS=:; a=( $b ); printf "%s\n" "${a[@]}"'
This constructs the string Apple Tomato:Banana Carrot and creates the environment variable b with this string as its value for the bash -c script.
That script then splits b on : again, and assigns the split up words to its own a array.
I need to use set -f in the script to avoid invoking filename globbing on the split up words when using $b unquoted.
You then also want to restore the original value of IFS in both the bash -c and the parent shell (you may want store the old value in a variable to make this easier). You may also want to enable filename globbing again in the bash -c script, with set +f.
ifs=$IFS; IFS=:
b="${a[*]}" bash -c 'set -f; ifs=$IFS; IFS=:; a=( $b ); IFS=$ifs; unset ifs; set +f; printf "%s\n" "${a[@]}"'
IFS=$ifs; unset ifs