How do I know where the end of the array is?
If you aren't passing the size of the array as a separate parameter (which you should be), then you'll have to use some sort of a sentinel value (the way C strings use a 0 after the last character in the string).
I think I'm supposed to pass pointers to the first element of the array because I don't think C will let the values of an array be passed, but a little unsure.
C's array semantics are a little tricky. Except when it is the operand of the sizeof, _Alignof, or unary & operators, or is a string literal being used to initialize an array in a declaration, an expression of type "N-element array of T" will be converted to an expression of type "pointer to T", and the value of the expression will be the address of the first element in the array. So, given the code
int arr1[10];
foo(arr1); // equivalent to foo(&arr1[0]);
the expression arr1 in the call to foo will be converted from "10-element array of int" to "pointer to int", and the value received by foo is the address of the first element of the array:
void foo(int *a)
{
// do stuff with a[i]
}
The expression a[i] is interpreted as *(a + i); we find the address of the i'th element following a and dereference the result.
This is a long-winded way of saying you'll use the [] operator on the arguments to your function as though they were regular arrays.
When returning the array to the main function, how can I return the resulting function without the memory being cleared up?
Not exactly clear what you mean here. Note that the following code won't work:
int *foo(int *a1, int *a2)
{
int a3[SOME_SIZE];
// copy elements from a1 and a2 to a3;
return a3;
}
Once foo exits, the array a3 ceases to exist; that memory is reclaimed by the system, so the pointer value you return is no longer valid. You have three options:
First, you can pass the target array as a third argument:
int main(void)
{
int arr1[N];
int arr2[M];
int arr3[K];
...
foo(arr1, arr2, arr3);
...
}
void foo(int *a1, int *a2, int *result) { ... }
with the precondition that result points to an array large enough to hold all the elements you find (it should be as big as the larger of the two source arrays). If you don't want to mess with dynamic memory management, this is the way to go.
Secondly, you can allocate the target array dynamically in the function:
int main(void)
{
int a1[M];
int a2[N];
int *a3;
...
a3 = foo(a1, a2);
...
free(a3);
}
int *foo(int *a1, int *a2)
{
int *result = malloc(sizeof *result * SOME_SIZE);
...
if (element_in_both_arrays())
result[n++] = element_from_both_arrays();
...
return result;
}
You'll have to remember to deallocate the memory once you're done with it.
Finally, you can declare the target array as a global variable (i.e., at file scope). I'm not going to present an example, because you don't want to do that.
Anytime you're passing arrays to functions or returning dynamically allocated buffers, you really need to pass array sizes as separate parameters. In general, it's impossible to determine how many elements are in an array based on a pointer value alone. You can use sentinel values, but they only tell you the logical size of an array, not its physical size. For example:
char buffer[1024] = "foo";
The logical size of buffer is 3 (the length of the string), but its physical size is 1 kilobyte.
NULL? :) Also, I agree with LihO. This is pretty basic stuff, you should get a book. It'll answer your question and much more.