I would like to define a custom structure that contains two dynamically allocatable integer arrays a and b. In order to allocate memory for the arrays and initialise arrays with values I have written a "constructor" function initp. My approach is presented below.
A custom structure called pair:
typedef struct {
...
int l; // length of compositions
int k; // no. of elements in compositions
int *a; // composition 1
int *b; // composition 2
} pair;
A function to initialise custom structure:
int initp(..., int l, int k, int a[], int b[], pair *f) {
...
f->l = l;
f->k = k;
// allocate composition arrays
f->a = (int *) calloc(l, sizeof(int));
f->b = (int *) calloc(l, sizeof(int));
// initialise composition arrays
for (int i = 0; i < k; i++) {
f->a[i] = a[i];
f->b[i] = b[i];
}
}
A function call in the main program:
// initialise pairs
pair f1, f2;
initp(..., 10, 2, (int[]){3, 4}, (int[]){7, 6}, &f1);
initp(..., 10, 1, (int[]){4}, (int[]){9}, &f2);
I'm on a mission to write an "elegant" code. Therefore, the questions I have are:
Is it possible to avoid specifying the no. of elements in arrays a and b passed to the initp? This is the parameter k. In the above examples it is 2 and 1.
Is it possible to avoid "explicit" casting with (int[]) in the function call?
Please let me know, if you have general comments and criticism on improving the quality of the code.
Is it possible to avoid specifying the no. of elements in arrays a and b passed to the initp?
No.
Alternative: Create a macro INITP(l, a, b, f) with macro magic determines the a, b are truly arrays, their array element counts, insure their counts are equal and then calls initp().
I am not fan of this approach, but it is do-able - with limitations.
Note: for size information, consider size_t vs. int.
Is it possible to avoid "explicit" casting with (int[]) in the function call?
With (int[]){3, 4}, (int[]) is not a cast. It is simply the form of a compound literal and is required to form one.
if you have general comments and criticism on improving the quality of the code.
For working code, consider Code review for a deeper review.
I'd assign each array in turn - usually as fast or faster than interlacing.
memcpy(f->a, a, sizeof f->a[0] * k);
memcpy(f->b, b, sizeof f->b[0] * k);
Handle allocation failures.
Create a initp() companion like void uninitp(pair *f).
Improve allocation for clarity, review and maintenance.
// f->a = (int *) calloc(l, sizeof(int));
f->a = calloc(l, sizeof f->a[0]);
const, restrict considerations.
Hmmm, this is getting to be too full a review for here, so will end now.
Related
I have a function concat to concatenate the matrix mat1 to form mat2. Here mat1 and mat2 uses fixed dimensions (i.e DIM1 = 2, DIM2 = 2, DIM3 = 3, DIM1_1 = 4) but in practice I need them to be of variable dimensions, so I declared the size of 3d array to max size as commented in my code below (i.e DIM2 = 20, DIM3 = 30) but the program gives garbage value when I do this. Could someone please advise on how to use variable sized 3d arrays without using malloc() ?
#include <stdio.h>
#include <string.h>
//!< Dimensions of a 3d array
#define DIM1 2
#define DIM2 2
#define DIM3 3
#define DIM1_1 4
void Concat(int (*mat1)[DIM2][DIM3], int (*mat2)[DIM2][DIM3], int len);
// void Concat(int (*mat1)[20][30], int (*mat2)[20][30], int len);
int main()
{
int mat1[DIM1][DIM2][DIM3] = {{{1,2,3},{4,5,6}},{{1,2,3},{4,5,6}}};
int mat2[DIM1_1][DIM2][DIM3];
Concat(mat1,mat2,2);
return 0;
}
// void Concat(int (*mat1)[20][30], int (*mat2)[20][30], int len){
void Concat(int (*mat1)[DIM2][DIM3], int (*mat2)[DIM2][DIM3], int len){
/*concatenate mat1 to mat2 */
memcpy(mat2[0], mat1, DIM1*DIM2*DIM3 * sizeof mat1);
memcpy(mat2[0+len], mat1, DIM1*DIM2*DIM3 * sizeof mat1);
}
I declared the size of 3d array to max size as commented in my code below (i.e DIM2 = 20, DIM3 = 30) but the program gives garbage value when I do this.
And I hope that before getting garbage values at runtime, your compiler warned you about the type mismatch that you created that way. If it didn't, then you would be well served by figuring out how to turn up the warning level, or else by choosing a more helpful compiler.
Either way, the parameters to your Concat() function are pointers to 2D arrays of specific dimensions. If the actual arguments are pointers to something else, even arrays of different dimension, then it should not come as a surprise that the results are poor. In fact, this produces a violation of the so-called "strict aliasing rule", and the behavior is therefore undefined.
Could someone please advise on how to use variable sized 3d arrays without using malloc() ?
I interpret you to mean you want a single function that works for arrays of various dimensions, not that any individual array has dimensions that change over time. There are several things you can do, but here are some good alternatives:
If your implementation supports VLAs (mandatory in C99, but optional since C11) then you can use them to support your Concat() function. This kind of thing is one of my favorite uses for VLAs, inasmuch as it sidesteps the biggest practical concern with their usage, which revolves around space available for their automatic allocation. Such an approach might look like this:
void Concat(size_t dim1, size_t dim2, size_t dim3 int (*source)[dim2][dim3],
int (*dest)[dim2][dim3]) {
size_t source_size = dim1 * sizeof(*source);
memcpy(dest, source, source_size);
memcpy(dest + dim1, source, source_size);
}
You will note that this requires you to pass all the dimensions of the source array as separate arguments, and that all dimensions but the first match for the two arrays. You would use that pretty simply:
int mat1[DIM1][DIM2][DIM3] = /* ... */
int mat2[DIM1 * 2][DIM2][DIM3];
Concat(DIM1, DIM2, DIM3, mat1, mat2);
Of course, you can use the same function, in the same program, to concatenate pairs of arrays of various dimensions, provided the constraints already described are satisfied.
If you cannot or do not want to rely on VLAs, then your best alternative might be simply to adapt the above to that case, like so:
void Concat(size_t dim1, size_t dim2, size_t dim3, void *source, void *dest) {
size_t source_size = dim1 * dim2 * dim3 * sizeof(int);
memcpy((char *) dest, source, source_size);
memcpy((char *) dest + source_size, source, source_size);
}
You could call that function the same way as the previous.
If you want to be even more general, and at the same time provide a simpler function signature, you could convert the above to concatenate arbitrary objects:
void Concat(size_t source_size, void *source, void *dest) {
memcpy((char *) dest, source, source_size);
memcpy((char *) dest + source_size, source, source_size);
}
This achieves complete generality by putting responsibility on the caller for computing and passing the size of the source object, in bytes, though that's not necessarily a big problem. For example,
int mat1[DIM1][DIM2][DIM3] = /* ... */
int mat2[DIM1 * 2][DIM2][DIM3];
Concat(sizeof(mat1), mat1, mat2);
I'm sorry, but it cannot be done (without knowing the maximum length in advance). When your function makes mat1, it reserves precisely 2*2*3 ints-worth of memory on the stack for the array, and sticks each sub-array right next to each other. If statically allocated, there's no way to change this after it's been done.
However... with dynamic memory allocation (i.e. malloc and friends) it's possible to do this. Specifically, using realloc to allocate extra space.
Sorry.
I want to declare a global 2d array in C, and allocate contiguous memory at runtime because the minor dimension is unknown at compile time.
I would like to dereference the array with 2-indices notation A[i][j].
If the array wasn't global c99 notation "double A[m][n]" would be handy but in my case does not apply.
What would be the right strategy?
#include <stdio.h>
#include <stdlib.h>
//TO DO
//DECLARE array here
void fun1() {
array[3][2] = 42.0;
}
int main(int argc,char *argv[])
{
int rows = atol(argv[1]);
int cols = atol(argv[2]);
//TO DO
//Allocate memory for array here
fun1();
printf("Array[3][2]=%f\n",array[3][2]);
return(0);
}
Unfortunately, it not quite possible in C to achieve what you are asking for.
There is a slightly ugly solution with a macro. Since the macro refers to both the global array itself and a global variable containing its second dimension, you have to be careful to not shadow the globals in any function which uses the macro. Here, I used clunky names ending with underscores to try to avoid name reuse.
Other than that, it should work:
void* global_array_void_;
size_t global_array_minor_dim_;
#define global_array ((double(*)[global_array_minor_dim_])global_array_void_)
Before you can use the macro, you need to allocate it and initialize the global variables:
void init_global_array(int rows, int cols) {
global_array_minor_dim_ = cols
global_array_void_ = malloc(rows * cols * sizeof global_array[0][0]);
}
From then on, you can use use global_array as though it were a regular array:
void f(int r, int c, double v) {
global_array[r][c] = v;
}
Live on coliru.
The type in the cast ((double (*)[cols])(array_void_)) might not be obvious. It represents a pointer to an array of cols doubles, which is what double[][cols] would decay to as a pointer. Note that double[][cols] does not decay to double**, which is a completely different (and incompatible) type.
With that definition, sizeof global_array[r] has the correct value: cols * sizeof(double). Contrast that with sizeof argv[i].
A more traditional way of doing this is to use a function to compute the precise index. That still depends on the minor dimension being available:
double* global_array;
size_t global_array_minor_dim_;
void init_global_array(int rows, int cols) {
global_array_minor_dim_ = cols
global_array_void_ = malloc(rows * cols * sizeof global_array[0][0]);
}
double* global_array_at(int r, int c) {
return &global_array[r * global_array_minor_dim_ + c];
}
Now you can use *global_array_at(r, c) as a replacement for global_array[r][c]. In C, it's impossible to eliminate the * and still have assignment work (in C++, the function could have returned a double& instead of a double*), but this could be solved, once again, with a macro.
Here is a sample for you to follow:
#include <stdlib.h>
void main(void)
{
int **f;
int n = 2, m = 3;
f = (int **)malloc(sizeof(int)*n *m);
f[1][2] = 3;
}
So... I have a dynamically allocated array on my main:
int main()
{
int *array;
int len;
array = (int *) malloc(len * sizeof(int));
...
return EXIT_SUCCESS;
}
I also wanna build a function that does something with this dynamically allocated array.
So far my function is:
void myFunction(int array[], ...)
{
array[position] = value;
}
If I declare it as:
void myFunction(int *array, ...);
Will I still be able to do:
array[position] = value;
Or I will have to do:
*array[position] = value;
...?
Also, if I am working with a dynamically allocated matrix, which one is the correct way to declare the function prototype:
void myFunction(int matrix[][], ...);
Or
void myFunction(int **matrix, ...);
...?
If I declare it as:
void myFunction(int *array, ...);
Will I still be able to do:
array[position] = value;
Yes - this is legal syntax.
Also, if I am working with a dynamically allocated matrix, which one
is correct to declare the function prototype:
void myFunction(int matrix[][], ...);
Or
void myFunction(int **matrix, ...);
...?
If you're working with more than one dimension, you'll have to declare the size of all but the first dimension in the function declaration, like so:
void myFunction(int matrix[][100], ...);
This syntax won't do what you think it does:
void myFunction(int **matrix, ...);
matrix[i][j] = ...
This declares a parameter named matrix that is a pointer to a pointer to int; attempting to dereference using matrix[i][j] will likely cause a segmentation fault.
This is one of the many difficulties of working with a multi-dimensional array in C.
Here is a helpful SO question addressing this topic:
Define a matrix and pass it to a function in C
Yes, please use array[position], even if the parameter type is int *array. The alternative you gave (*array[position]) is actually invalid in this case since the [] operator takes precedence over the * operator, making it equivalent to *(array[position]) which is trying to dereference the value of a[position], not it's address.
It gets a little more complicated for multi-dimensional arrays but you can do it:
int m = 10, n = 5;
int matrixOnStack[m][n];
matrixOnStack[0][0] = 0; // OK
matrixOnStack[m-1][n-1] = 0; // OK
// matrixOnStack[10][5] = 0; // Not OK. Compiler may not complain
// but nearby data structures might.
int (*matrixInHeap)[n] = malloc(sizeof(int[m][n]));
matrixInHeap[0][0] = 0; // OK
matrixInHeap[m-1][n-1] = 0; // OK
// matrixInHeap[10][5] = 0; // Not OK. coloring outside the lines again.
The way the matrixInHeap declaration should be interpreted is that the 'thing' pointed to by matrixInHeap is an array of n int values, so sizeof(*matrixInHeap) == n * sizeof(int), or the size of an entire row in the matrix. matrixInHeap[2][4] works because matrixInHeap[2] is advancing the address matrixInHeap by 2 * sizeof(*matrixInHeap), which skips two full rows of n integers, resulting in the address of the 3rd row, and then the final [4] selects the fifth element from the third row. (remember that array indices start at 0 and not 1)
You can use the same type when pointing to normal multidimensional c-arrays, (assuming you already know the size):
int (*matrixPointer)[n] = matrixOnStack || matrixInHeap;
Now lets say you want to have a function that takes one of these variably sized matrices as a parameter. When the variables were declared earlier the type had some information about the size (both dimensions in the stack example, and the last dimension n in the heap example). So the parameter type in the function definition is going to need that n value, which we can actually do, as long as we include it as a separate parameter, defining the function like this:
void fillWithZeros(int m, int n, int (*matrix)[n]) {
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
matrix[i][j] = 0;
}
If we don't need the m value inside the function, we could leave it out entirely, just as long as we keep n:
bool isZeroAtLocation(int n, int (*matrix)[n], int i, int j) {
return matrix[i][j] == 0;
}
And then we just include the size when calling the functions:
fillWithZeros(m, n, matrixPointer);
assert(isZeroAtLocation(n, matrixPointer, 0, 0));
It may feel a little like we're doing the compilers work for it, especially in cases where we don't use n inside the function body at all (or only as a parameter to similar functions), but at least it works.
One last point regarding readability: using malloc(sizeof(int[len])) is equivalent to malloc(len * sizeof(int)) (and anybody who tells you otherwise doesn't understand structure padding in c) but the first way of writing it makes it obvious to the reader that we are talking about an array. The same goes for malloc(sizeof(int[m][n])) and malloc(m * n * sizeof(int)).
Will I still be able to do:
array[position] = value;
Yes, because the index operator p[i] is 100% identical to *(ptr + i). You can in fact write 5[array] instead of array[5] and it will still work. In C arrays are actually just pointers. The only thing that makes an array definition different from a pointer is, that if you take a sizeof of a "true" array identifier, it gives you the actual storage size allocates, while taking the sizeof of a pointer will just give you the size of the pointer, which is usually the system's integer size (can be different though).
Also, if I am working with a dynamically allocated matrix, which one is the correct way to declare the function prototype: (…)
Neither of them because those are arrays of pointers to arrays, which can be non-contigous. For performance reasons you want matrices to be contiguous. So you just write
void foo(int matrix[])
and internally calculate the right offset, like
matrix[width*j + i]
Note that writing this using the bracket syntax looks weird. Also take note that if you take the sizeof of an pointer or an "array of unspecified length" function parameter you'll get the size of a pointer.
No, you'd just keep using array[position] = value.
In the end, there's no real difference whether you're declaring a parameter as int *something or int something[]. Both will work, because an array definition is just some hidden pointer math.
However, there's is one difference regarding how code can be understood:
int array[] always denotes an array (it might be just one element long though).
int *pointer however could be a pointer to a single integer or a whole array of integers.
As far as addressing/representation goes: pointer == array == &array[0]
If you're working with multiple dimensions, things are a little bit different, because C forces you declare the last dimension, if you're defining multidimensional arrays explicitly:
int **myStuff1; // valid
int *myStuff2[]; // valid
int myStuff3[][]; // invalid
int myStuff4[][5]; // valid
Is it possible to write a function which accept 2-d array when the width is not known at compile time?
A detailed description will be greatly appreciated.
You can't pass a raw two-dimensional array because the routine won't know how to index a particular element. The 2D array is really one contiguous memory segment.
When you write x[a][b] (when x is a 2d array), the compiler knows to look at the address (x + a * width + b). It can't know how to address the particular element if you don't tell it the width.
As an example, check http://www.dfstermole.net/OAC/harray2.html#offset (which has a table showing how to find the linear index for each element in an int[5][4])
There are two ways to work around the limitation:
1) Make your program work with pointer-to-pointers (char *). This is not the same as char[][]. A char * is really one memory segment, with each value being a memory address to another memory segment.
2) Pass a 1d pointer, and do the referencing yourself. Your function would then have to take a "width" parameter, and you could use the aforementioned formula to reference a particular point
To give a code example:
#include <stdio.h>
int get2(int *x) { return x[2]; }
int main() {
int y[2][2] = {{11,12},{21,22}};
printf("%d\n", get2((int *)y));
}
This should print out 21, since y is laid out as { 11, 12, 21, 22 } in memory.
C supports variable-length arrays. You must specify the width from a value known at run-time, which may be an earlier parameter in the function declaration:
void foo(size_t width, int array[][width]);
One way is use the good old "pointer to array of pointers to arrays" trick coupled with a single continuous allocation:
/* Another allocation function
--------------------------- */
double ** AnotherAlloc2DTable(
size_t size1, /*[in] Nb of lines */
size_t size2 /*[in] Nb of values per line */
)
{
double ** ppValues;
size_t const size1x2 = size1*size2;
if(size1x2 / size2 != size1)
return NULL; /*size overflow*/
ppValues = malloc(sizeof(*ppValues)*size1);
if(ppValues != NULL)
{
double * pValues = malloc(sizeof(*pValues)*size1x2);
if(pValues != NULL)
{
size_t i;
/* Assign all pointers */
for(i=0 ; i<size1 ; ++i)
ppValues[i] = pValues + (i*size2);
}
else
{
/* Second allocation failed, free the first one */
free(ppValues), ppValues=NULL;
}
}/*if*/
return ppValues;
}
/* Another destruction function
---------------------------- */
void AnotherFree2DTable(double **ppValues)
{
if(ppValues != NULL)
{
free(ppValues[0]);
free(ppValues);
}
}
Then all you have to do is pass a char ** to your function. The matrix is continuous, and usable as mat[x][y].
Possible accessor functions:
int get_multi(int rows, int cols, int matrix[][cols], int i, int j)
{
return matrix[i][j];
}
int get_flat(int rows, int cols, int matrix[], int i, int j)
{
return matrix[i * cols + j];
}
int get_ptr(int rows, int cols, int *matrix[], int i, int j)
{
return matrix[i][j];
}
An actual multi-dimensional array and a fake one:
int m_multi[5][7];
int m_flat[5 * 7];
Well-defined ways to use the accessor functions:
get_multi(5, 7, m_multi, 4, 2);
get_flat(5, 7, m_flat, 4, 2);
{
int *m_ptr[5];
for(int i = 0; i < 5; ++i)
m_ptr[i] = m_multi[i];
get_ptr(5, 7, m_ptr, 4, 2);
}
{
int *m_ptr[5];
for(int i = 0; i < 5; ++i)
m_ptr[i] = &m_flat[i * 7];
get_ptr(5, 7, m_ptr, 4, 2);
}
Technically undefined usage that works in practice:
get(5, 7, (int *)m_multi, 4, 2);
[Warning - this answer addresses the case where the number of columns - the WIDTH - is known]
When working with 2D arrays, the compiler needs to know the number of columns in your array in order to compute indexing. For instance, if you want a pointer p that points to a range of memory to be treated as a two-dimensional set of values, the compiler cannot do the necessary indexing arithmetic unless it knows how much space is occupied by each row of the array.
Things become clearer with a concrete example, such as the one below. Here, the pointer p is passed in as a pointer to a one-dimensional range of memory. You - the programmer - know that it makes sense to treat this as a 2D array and you also know (must know) how many columns are there in this array. Armed with this knowledge, you can write code to create q, that is treated by the compiler as a 2D array with an unknown number of rows, where each row has exactly NB columns.
I usually employ this when I want the compiler to do all the indexing arithmetic (why do it by hand when the compiler can do it?). In the past, I've found this construct to be useful to carry out 2D transposes from one shape to another - note though that generalized 2D transposes that transpose an MxN array into an NxM array are rather beastly.
void
WorkAs2D (double *p)
{
double (*q)[NB] = (double (*)[NB]) p;
for (uint32_t i = 0; i < NB; i++)
{
for (uint32_t j = 0; j < ZZZ; j++) /* For as many rows as you have in your 2D array */
q[j][i] = ...
}
}
I believe a nice solution would be the use of structures.
So I have an example for 1d-Arrays:
Definition of the struct:
struct ArrayNumber {
unsigned char *array;
int size;
};
Definition of a function:
struct ArrayNumber calcMultiply(struct ArrayNumber nra, struct ArrayNumber nrb);
Init the struct:
struct ArrayNumber rs;
rs.array = malloc(1);
rs.array[0] = 0;
rs.size = 1;
//and adding some size:
rs.size++;
rs.array = realloc(rs.array, rs.size);
hope this could be a solution for you. Just got to change to a 2d Array.
In C, is it not possible to make the return type an array? I'm starting to learn about pointers in my operating systems course and I need to make a function that takes 2 arrays as parameters and returns an array containing only the elements that are in both parameter arrays.
This is what I have so far for my C function that returns an array:
#include <stdio.h>
main()
{
printf("Hello world");
int array1[4] = {1, 2, 3, 4};
int array2[4] = {3, 4, 5, 6};
int* inter = intersection(array1, array2);
printf(inter); // <-- also, I don't know how I could get this to work for testing
//freezes program so it doesn't terminate immediately upon running:
getchar();
}
int* intersection(int array1[], int array2[])
{
int arrayReturn[sizeof(array1) + sizeof(array2)];
int count = 0;
for(int i = 0; i < 4; i++)
{
for(int j = 0; j < 4; j++)
{
if(array1[i]==array2[j])
{
arrayReturn[count] = array1[i];
count = count + 1;
}
}
}
return arrayReturn;
}
Another question I have is how could I test this function in the main() method using a printf() statement?
The reason why I need to do this is because we're learning about processes and memory allocation and pointers play a big role in OS development. My professor told me that pointers are so difficult to understand that they leave pointers out of many programming languages.
here we go
#include <stdio.h>
/* declare function, you need to capture array size as well, and also allow
to get result target pointer, result space info and pointer to place where the
size of result will be captured */
int* intersection(int * array1, int a1len , int * array2, int a2len, int* result, int *resultsize, int resultspace);
main()
{
printf("Hello world\n");
int array1[4] = {1, 2, 3, 4};
int array2[4] = {3, 4, 5, 6};
int arrayr[32]; /*result will be in this table */
int resultsize;
int resultspace = 32;
int i;
/* here comes confusion - int resultsize means it will be read as integer,
so we need to write &resultsize to get the pointer,
array declaration like int arrayr[number] is actually understood by system
as a pointer to an integer, pointing to first element of array,
allowing you to use indexes
so arrayr[3] actually means *(arrayr + 3 * sizeof(int))
*/
int* inter = intersection(array1, 4, array2, 4, arrayr, &resultsize, resultspace);
/* inter is now a pointer to arrayr */
for (i = 0; i<resultsize; i=i+1) {
printf("%d\n", inter[i]);
}
//freezes program so it doesn't terminate immediately upon running:
getchar();
}
int* intersection(int * array1, int a1len , int * array2, int a2len, int* result, int *resultsize, int resultspace)
{
/* as we received a pointer to resultsize (*resultsize)
we need to de-reference it using "*" to get or set the actual value */
*resultsize = 0;
int i, j;
for(i = 0; i < a1len; i++)
{
for(j = 0; j < a2len; j++)
{
if(array1[i]==array2[j])
{
result[*resultsize] = array1[i];
*resultsize = *resultsize + 1;
if (resultspace == *resultsize)
return result;
}
}
}
return result;
}
In C, is it not possible to make the return type an array?
No. Some of the characteristics that differentiate arrays from pointers are:
sizeof array evaluates to n * sizeof *array, where n is the number of elements, instead of the size of a pointer.
&array evaluates to a pointer to an array, instead of a pointer to a pointer.
You can use an array to initialise a pointer, eg. int *ptr = (int[]){ 1, 2, 3, 4 };, but you can't use a pointer to initialise an array, eg. int array[4] = ptr;.
You can't assign to an array eg. int array[4]; array = (int[]){ 1, 2, 3, 4 };, but you can assign to a pointer: int *ptr; ptr = (int[]){ 1, 2, 3, 4 };, unless the pointer is declared as a const pointer to int, eg. int * const ptr = NULL; ptr = (int[]){ 1, 2, 3, 4 };
I'm starting to learn about pointers in my operating systems course
and I need to make a function that takes 2 arrays as parameters and
returns an array containing only the elements that are in both
parameter arrays.
This isn't possible. Firstly, your array arguments are actually pointer arguments. Look at sizeof array1 and sizeof array2. Try to initialise an array with them. Try to assign to them. How many of the tests above seem to indicate that they're pointers? When you pass an array to a function, the array expression evaluates to a pointer to the first element of the array. Perhaps you'd want to declare your function to accept pointer to arrays, eg:
int *intersection(size_t sz1, int (*array1)[sz1], // array1 is a pointer to int[sz1]
size_t sz2, int (*array2)[sz2]) // array2 is a pointer to int[sz2]
{ ... }
Secondly, your function clearly returns a pointer value, not an array. Regarding that return value, arrayReturn is declared inside intersection as an array that has automatic storage duration, and so it will be destroyed when intersection returns. When main attempts to use that value, it'll be attempting to use a destroyed array. Returning an array using automatic storage duration isn't possible. Returning a fixed-size struct using automatic storage duration is possible, but this isn't helpful for your problem because your return value would need to be dynamic in size.
Another question I have is how could I test this function in the
main() method using a printf() statement?
You can't do anything with the return value of that function, because using an object that has been destroyed is undefined behaviour.
The reason why I need to do this is because we're learning about
processes and memory allocation and pointers play a big role in OS
development.
The C programming language is independant of OS implementations; It doesn't matter if an OS delays the destruction of objects with automatic storage duration. If you use a destroyed object, you're invoking undefined behaviour.
My professor told me that pointers are so difficult to understand that
they leave pointers out of many programming languages.
Has he/she written out his/her lesson plan? If not, then he/she is missing a crucial point where improvement can be identified. How successful has his/her written lesson plan been in the past? If it's been 100% successful, it doesn't make sense to be using words like "difficult"; Why would you want to unnecessarily trigger overwhelming feelings in students? If parts are too complex, then it makes more sense to identify and clarify those parts, rather than identifying those parts and specifying them as "difficult". It also makes no sense to mention other programming languages in a course about C.
When a professor's lesson plan becomes fairly successful, it becomes feasible to publish it as a book. One example is K&R's "The C Programming Language, Second Edition". Do you have a book?