Asked  7 Months ago    Answers:  5   Viewed   31 times

What is the difference between the two functions in C?

void f1(double a[]) {
   //...
}

void f2(double *a) {
   //...
}

If I were to call the functions on a substantially long array, would these two functions behave differently, would they take more space on the stack?

 Answers

56

First, some standardese:

6.7.5.3 Function declarators (including prototypes)
...
7 A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to type’’, where the type qualifiers (if any) are those specified within the [ and ] of the array type derivation. If the keyword static also appears within the [ and ] of the array type derivation, then for each call to the function, the value of the corresponding actual argument shall provide access to the first element of an array with at least as many elements as specified by the size expression.

So, in short, any function parameter declared as T a[] or T a[N] is treated as though it were declared T *a.

So, why are array parameters treated as though they were declared as pointers? Here's why:

6.3.2.1 Lvalues, arrays, and function designators
...
3 Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.

Given the following code:

int main(void)
{
  int arr[10];
  foo(arr);
  ...
}

In the call to foo, the array expression arr isn't an operand of either sizeof or &, so its type is implicitly converted from "10-element array of int" to "pointer to int" according to 6.2.3.1/3. Thus, foo will receive a pointer value, rather than an array value.

Because of 6.7.5.3/7, you can write foo as

void foo(int a[]) // or int a[10]
{
  ...
}

but it will be interpreted as

void foo(int *a)
{
  ...
}

Thus, the two forms are identical.

The last sentence in 6.7.5.3/7 was introduced with C99, and basically means that if you have a parameter declaration like

void foo(int a[static 10])
{
  ...
}

the actual parameter corresponding to a must be an array with at least 10 elements.

Tuesday, June 1, 2021
 
tplaner
answered 7 Months ago
70
  • Changing Values:
    • array_map cannot change the values inside input array(s) while array_walk can; in particular, array_map never changes its arguments.
  • Array Keys Access:
    • array_map cannot operate with the array keys, array_walk can.
  • Return Value:
    • array_map returns a new array, array_walk only returns true. Hence, if you don't want to create an array as a result of traversing one array, you should use array_walk.
  • Iterating Multiple Arrays:
    • array_map also can receive an arbitrary number of arrays and it can iterate over them in parallel, while array_walk operates only on one.
  • Passing Arbitrary Data to Callback:
    • array_walk can receive an extra arbitrary parameter to pass to the callback. This mostly irrelevant since PHP 5.3 (when anonymous functions were introduced).
  • Length of Returned Array:
    • The resulting array of array_map has the same length as that of the largest input array; array_walk does not return an array but at the same time it cannot alter the number of elements of original array; array_filter picks only a subset of the elements of the array according to a filtering function. It does preserve the keys.

Example:

<pre>
<?php

$origarray1 = array(2.4, 2.6, 3.5);
$origarray2 = array(2.4, 2.6, 3.5);

print_r(array_map('floor', $origarray1)); // $origarray1 stays the same

// changes $origarray2
array_walk($origarray2, function (&$v, $k) { $v = floor($v); }); 
print_r($origarray2);

// this is a more proper use of array_walk
array_walk($origarray1, function ($v, $k) { echo "$k => $v", "n"; });

// array_map accepts several arrays
print_r(
    array_map(function ($a, $b) { return $a * $b; }, $origarray1, $origarray2)
);

// select only elements that are > 2.5
print_r(
    array_filter($origarray1, function ($a) { return $a > 2.5; })
);

?>
</pre>

Result:

Array
(
    [0] => 2
    [1] => 2
    [2] => 3
)
Array
(
    [0] => 2
    [1] => 2
    [2] => 3
)
0 => 2.4
1 => 2.6
2 => 3.5
Array
(
    [0] => 4.8
    [1] => 5.2
    [2] => 10.5
)
Array
(
    [1] => 2.6
    [2] => 3.5
)
Wednesday, March 31, 2021
 
cbcp
answered 9 Months ago
95

When passing an array as a parameter, this

void arraytest(int a[])

means exactly the same as

void arraytest(int *a)

so you are modifying the values in main.

For historical reasons, arrays are not first class citizens and cannot be passed by value.

Tuesday, June 1, 2021
 
Gigamegs
answered 7 Months ago
60

Oneword answer for your question is Closures

The Default Syntax for closures is () -> ()

Instead of Selector you could directly mention the method definition

func showConfirmBox(msg:String, title:String,
    firstBtnStr:String, firstSelector:(sampleParameter: String) -> returntype,
    secondBtnStr:String, secondSelector:() -> returntype,
    caller:UIViewController) {
    //Your Code
}

But using this will create readability problems so i suggest you to use typeAlias

typealias MethodHandler1 = (sampleParameter : String)  -> Void
typealias MethodHandler2 = ()  -> Void

func showConfirmBox(msg:String, title:String,
                    firstBtnStr:String, firstSelector:MethodHandler1,
                    secondBtnStr:String, secondSelector:MethodHandler2) {

    // After any asynchronous call
    // Call any of your closures based on your logic like this
    firstSelector("FirstButtonString")
    secondSelector()
}

You can call your method like this

func anyMethod() {
   //Some other logic 

   showConfirmBox(msg: "msg", title: "title", firstBtnStr: "btnString", 
         firstSelector: { (firstSelectorString) in
              print(firstSelectorString) //this prints FirstButtonString
         }, 
         secondBtnStr: "btnstring") { 
           //Invocation comes here after secondSelector is called

         }
}
Tuesday, September 7, 2021
 
Gordnfreeman
answered 3 Months ago
30

The main problem here is that you're trying to use realloc with a stack-allocated array. You have:

ent a[mSize];

That's automatic allocation on the stack. If you wanted to use realloc() on this later, you would create the array on the heap using malloc(), like this:

ent *a = (ent*)malloc(mSize * sizeof(ent));

So that the malloc library (and thus realloc(), etc.) knows about your array. From the looks of this, you may be confusing C99 variable-length arrays with true dynamic arrays, so be sure you understand the difference there before trying to fix this.

Really, though, if you are writing dynamic arrays in C, you should try to use OOP-ish design to encapsulate information about your arrays and hide it from the user. You want to consolidate information (e.g. pointer and size) about your array into a struct and operations (e.g. allocation, adding elements, removing elements, freeing, etc.) into special functions that work with your struct. So you might have:

typedef struct dynarray {
   elt *data;
   int size;
} dynarray;

And you might define some functions to work with dynarrays:

// malloc a dynarray and its data and returns a pointer to the dynarray    
dynarray *dynarray_create();     

// add an element to dynarray and adjust its size if necessary
void dynarray_add_elt(dynarray *arr, elt value);

// return a particular element in the dynarray
elt dynarray_get_elt(dynarray *arr, int index);

// free the dynarray and its data.
void dynarray_free(dynarray *arr);

This way the user doesn't have to remember exactly how to allocate things or what size the array is currently. Hope that gets you started.

Sunday, November 7, 2021
 
Assassin
answered 1 Month ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share