Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to allocate array which is passed to a function by name

Tags:

arrays

bash

I want to create a function which iterates through an array and inserts the given value, if its not yet included. I am using this function on two different parts of my code and so I have to use different arrays. Therefore I am delivering the array names to the function. Now I can't figure out how to allocate a slot of the array to store the element at this place.

Here is my code:

name=("hello" "world")

function f {
    array_name=$2[@]
    array=("${!array_name}")
    length=${#array_name[@]}
    for (( i = 0; i <= $length; i++ )); do
        if [[ "${array[i]}" = "$1" ]];
            break;
        fi
        if [[ "$i" = "$length" ]]; then
            ${2[$length+1]=$1};
        fi
    done
}

f "test" "name"

Edit: I want the array to append the given value so something like this

for i in ${name[@]}
do
    echo $i
done

would have this output:

hello
world
test

but apparently "${2[$length+1]=$1}" is not working.

(Idea for passing the array is from here: bash how to pass array as an argument to a function)

like image 368
telina Avatar asked Apr 22 '14 12:04

telina


People also ask

How is array passed to called function?

To pass an entire array to a function, only the name of the array is passed as an argument. result = calculateSum(num); However, notice the use of [] in the function definition. This informs the compiler that you are passing a one-dimensional array to the function.

How an array is passed to the called function call by value?

Answer: An array can be passed to a function by value by declaring in the called function the array name with square brackets ( [ and ] ) attached to the end. When calling the function, simply pass the address of the array (that is, the array's name) to the called function.

Can you pass Dynamically allocated array to function?

3.4 Passing dynamic arrays to functionsDynamic arrays can also be passed to functions in the same way as static arrays.

When array is passed to function and is passed?

In case of an array (variable), while passed as a function argument, it decays to the pointer to the first element of the array. The pointer is then passed-by-value, as usual.

How do you pass an array to a function?

To pass multidimensional arrays to a function, only the name of the array is passed to the function (similar to one-dimensional arrays). Note: In C programming, you can pass arrays to functions, however, you cannot return arrays from functions.

How arrays are passed to functions in C/C++?

How arrays are passed to functions in C/C++. In C, when we pass an array to a function say fun(), it is always treated as a pointer by fun(). Below example demonstrates the same. unsigned int n = sizeof(arr)/sizeof(arr[0]); printf("nArray size inside fun() is %d", n); int arr[] = {1, 2, 3, 4, 5, 6, 7, 8};

How is an array passed from one language to another?

If you don't take any particular actions, an array will be passed by value, with a complete copy of the array. And in the earliest languages, like Fortran or Algol, each language often had its own very particular ways of passing arrays, although in general, they followed the same rules as other types.

How to pass multidimensional arrays to a function in C++?

To pass multidimensional arrays to a function, only the name of the array is passed to the function (similar to one-dimensional arrays). Notice the parameter int num [2] [2] in the function prototype and function definition:


1 Answers

If I understand correctly you want to append a value to an array if this value is not yet in the array, but the tricky part is that the array name is passed to the function.

Method 1

One possibility is to see the problem from a different viewpoint: you can pass to the function the value to be inserted and the full array, and the function will set a global variable that you will recover after its execution. For our test example we'll use:

array=( hello world "how are you today?" )

and we'll try to insert test and hello (so that hello will not be inserted):

f() {
# This function will set the global variable _f_out to an array obtained from
# the positional parameters starting from position 2, with $1 appended if and
# only if $1 doesn't appear in the subsequent positional parameters
    local v=$1 i
    shift
    _f_out=( "$@" )
    for i; do [[ $i = $v ]] && return; done
    _f_out+=( "$v" )
}

Let's use it:

$ array=( hello world "how are you today?" )
$ f test "${array[@]}"
$ array=( "${_f_out[@]}" )
$ printf '%s\n' "${array[@]}"
hello
world
how are you today?
test
$ f hello "${array[@]}"
$ array=( "${_f_out[@]}" )
$ printf '%s\n' "${array[@]}"
hello
world
how are you today?
test

It works.

Remark. I used for i; do. It's a nice shortcut for for i in "$@"; do.

Method 2

You really want to fiddle with simili-pointers and do the appending in place (this is not really in the spirit of Bash—that's why it's a bit clumsy). The tool for that is to use printf with the -v option: from help printf:

-v var    assign the output to shell variable VAR rather than
          display it on the standard output

The good thing is that it also works with array fields.

Warning: you might see other methods that use eval. Avoid them like the plague!

f() {
    local array_name=$2[@] i
    local array=( "${!array_name}" )
    for i in "${array[@]}"; do [[ $i = $1 ]] && return; done
    # $1 was not found in array, so let's append it
    printf -v "$2[${#array[@]}]" '%s' "$1"
}

and let's try it:

$ array=( hello world "how are you today?" )
$ f test array
$ printf '%s\n' "${array[@]}"
hello
world
how are you today?
test
$ f hello array
$ printf '%s\n' "${array[@]}"
hello
world
how are you today?
test

It works too.

Note. With both methods you can very easily have a return code of the function, e.g., 0 (success) if the value was inserted, and 1 (failure) if the value was already there (or the other way round)—the adaptation is straightforward and left as an exercise. This might be useful in Method 1 to determine whether you need to update array to the returned value _f_out or not. In that case, you could even slightly modify f so that it doesn't even set _f_out when the value is already in the array.

Caveat. In both methods shown I assumed that your arrays have contiguous indices that start at 0 (i.e., non-sparse arrays). I think it's a safe assumption here; but if it is not the case, these methods are broken: the first one will (after reassignment) transform the array into a non-sparse one, and the second one might overwrite fields (as, for an array a, ${#a[@]} expands to the number of elements in the array, not the highest index + 1 found in the array).

like image 97
gniourf_gniourf Avatar answered Oct 26 '22 12:10

gniourf_gniourf