The basic idea you have is good, to iterate simultaneously using index of an array. But the code has many elementary errors and it also doesn't do what the examples show. I suggest to first make a thorough pass through a modern and reputable Perl tutorial.
The examples indicate that you want to concatenate (see . operator) elements at each index
use warnings;
use strict;
use feature 'say';
my @a1 = ('a', 'b');
my @a2 = (1, 2);
my @a3 = ('!', '?');
my @res;
foreach my $i (0..$#a1) {
push @res, $a1[$i] . $a2[$i] . $a3[$i];
}
say for @res;
where $#a1 is the index of the last element of array @a1. This assumes that all arrays are of the same size and that all their elements are defined.
This exact work can be done using map in one statement
my @res = map { $a1[$_] . $a2[$_] . $a3[$_] } 0..$#a1;
with the same, serious, assumptions. Even if you knew they held, do you know for sure, in every run on any data? For a robust approach see the answer by mwp.
There is also each_array from List::MoreUtils, providing a "simultaneous iterator" for all arrays
my $ea = each_array(@a1, @a2, @a3);
my @res;
while ( my ($e1, $e2, $e3) = $ea->() ) {
push @res, $e1 . $e2 . $e3
}
which is really useful for more complex processing.
A quick run through basics
Always have use warnings; and use strict; at the beginning of your programs. They will catch many errors that would otherwise take a lot of time and nerves.
Don't use single-letter variable names. We quickly forget what they meant and the code gets hard to follow, and they make it way too easy to make silly mistakes.
Array's size is not given by length. It is normally obtained using context -- when an array is assigned to a scalar the number of its elements is returned. For iteration over indices there is $#ary, the index of the last element of @ary. Then the list of indices is 0 .. $#ary, using the range (..) operator
The sigil ($, @, %) at the beginning of an identifier (variable name) indicates the type of the variable (scalar, array, hash). An array element is a scalar so it needs $ -- $ary[0]
The push doesn't return array elements but it rather adds to the array in its first argument the scalars in the list that follows.
The print @array; prints array elements without anything between them. When you quote it spaces are added, print "@array\n";. Note the handy feature say though, which adds the new line.
$i = length(@a); for (0..$1) { @array = push(@array, @a[$i], @s[$i]; } print @array;