I am currently doing the fifteen exercise in CS50's Problem set 3. However, I am stuck in figuring out the syntax to pass a multi-dimensional array as an argument to a function. For instance, the following code (which prints out some numbers in an array) compiles and works:
#include <stdio.h>
void func(int array[], int size);
int main()
{
int size = 3;
int array[3] = {1,2,3};
func(array,size);
printf("Done\n");
}
void func(int array[], int size)
{
printf("%i %i %i\n", array[0],array[1], array[2]);
}
But this doesn't:
#include <stdio.h>
void func(int array[][], int size);
int main()
{
int size = 3;
int array[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
func(array,size);
printf("Done");
}
void func(int array[][], int size)
{
printf("%i %i %i\n", array[0][0],array[1][1], array[2][2]);
}
This is the error provided by clang:
test.c:3:20: error: array has incomplete element type 'int []'
void func(int array[][], int size);
^
test.c:13:20: error: array has incomplete element type 'int []'
void func(int array[][], int size)
Can anyone explain to me what's wrong with my syntax? I don't quite understand the error messages given to me by clang.
The function func() expects a pointer to int but you are passing a pointer to an array. Hence, the errrors.
It's because an array gets converted into a pointer to its first element when you pass it to a function.
You can change the function prototype and definition to receive a pointer to an array:
void func(int (*array)[3], int size);
int main()
{
int size = 3;
int array[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
func(array,size);
printf("Done");
}
void func(int (*array)[3], int size) {
...
}
Note that your array is initialized with size 3x3. So the array size has to 3x3 at least.
C99 allows to you pass dimensions. So you can write it like this too:
void func(int x, int y, int a[x][y]);
int main()
{
int size = 3;
int array[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
func(3, 3, array);
printf("Done");
}
void func(int x, int y, int array[x][y])
{
printf("%i %i %i\n", array[0][0],array[1][1], array[2][2]);
}
An array is not a type in C! Internally, it is always handled as a pointer, hence, a pointer to the array is passed as argument and not the array itself.
If you intend to pass arrays as arguments (and not just pointers), you should rethink your design!
If you still need to do this wrap the array into a structure and pass the structure.
struct astruct
{
int size;
int array[3];
};
A declaration like int a[][] isn't sensible, since the compiler must know the size of all dimensions (except of the outermost) to calculate the memory address on access.
I.e. if an array is declared as
int array[][a][b];
The memory address for access to
array[2][1][3];
is calculated by
base_address + (2*a*b + 1*b + 3) * sizeof int
Without knowing a and/or b, this calculation would not be possible.
Simply tell the function to expect a multi-dimensional array:
void func (int array[3][3], int size);
Or if you want the function to be completely flexible:
void func (int x, int y, int array[x][y]);
You need to specify size of array when declaring prototype as well as while defining function . Right now it is of incomplete type .
Try this instead -
void func(int array[][3], int size)
Related
I am trying to print an array through a function by using call by reference but keep getting a warning:
passing argument 1 of 'test' from incompatible pointer type [-Wincompatible-pointer-types]
I tried replacing test(&arr, n); with test(arr, n);, test(*arr, n);, test(&arr[], n);, test(*arr[], n);, test(&arr[], n);
but nothing worked, what am I doing wrong?
#include<stdio.h>
void test(int *a[], int b);
void main()
{
int arr[]={1, 2, 3, 4, 5}, i, n=5;
test(&arr, n);
}
void test(int *d[], int n)
{
int i;
for(i=0; i<n; i++)
{
printf("%d", *d[i]);
}
}
How do you pass an array to a function
Just by using a pointer of the array element type:
void test(int *a, int b);
If you then pass an array to the function:
test(arr);
... the C compiler will pass a pointer to the first element of the array (&(arr[0])) to the function.
Note that you don't use the & in this case.
Inside the function you can use array operations:
void test(int * arr)
{
arr[3] = arr[2];
}
(In your case: printf("%d\n", arr[n]);)
(This is true for any kind of pointer data type with exception of void *. The C compiler assumes that the pointer points to the first element of an array if you use array operations with pointer data types.)
"passing argument 1 of 'test' from incompatible pointer type"
As far as I know, [] in a function argument is not interpreted as array, but as pointer. For this reason, ...
void test(int *a[], int b);
... is interpreted as:
void test(int **a, int b);
... which means that the C compiler expects a pointer to an array of pointers (int *), not to an array of integers (int).
It's much simpler than that. In the example below I'm using size_t to express array size, it's an unsigned integer type specifically meant to be used for that purpose.
#include <stdio.h>
// you can use the size parameter as array parameter size
void test (size_t size, int arr[size]);
int main (void) // correct form of main()
{
int arr[]={1, 2, 3, 4, 5};
test(5, arr);
}
void test (size_t size, int arr[size])
{
for(size_t i=0; i<size; i++) // declare the loop iterator inside the loop
{
printf("%d ", arr[i]);
}
}
I want to know if there is any real difference; I have written code that as it feel it a passing by copy not reference but it acts as reference.
Here is the code:
#include <stdio.h>
#include <conio.h>
using namespace std;
int pause = 0;
void display(int b[5], int size){
for (int i = 0; i < size; i++){
printf("\n%d",b[i]," at:");
printf(" %d", &b[i]);
}
}
void main(){
int num[] = { 2, 4, 6, 8, 10 };
printf("\nIn main function.");
for (int i = 0; i < 5; i++){
printf("\n%d", num[i], " at:");
printf(" %d", &num[i]);
}
display(num,5);
scanf("%d", pause);
}
You cannot pass an array itself to a function at all, nor can you return one. In particular, despite the appearance of its declaration, your function display() does not receive an array as a parameter. It's declaration is 100% equivalent to this one:
void display(int *b, int size);
and this one:
void display(int b[], int size);
Expressions of array type are automatically converted to pointers in almost every context in which they can appear, so this function call:
display(num,5);
is equivalent to
display(&num[0],5);
Nevertheless, there is a potential difference to call out in this area: the expression &num is not equivalent to &num[0]. They refer to the same address, but the two expressions have different types. Passing the former would be the analog of passing the array by reference, but that expression does not have the correct type for the first argument to your display() function. A function that wants to receive &num needs to be declared differently:
void display2(int (*b)[5]);
or
void display3(int n, int (*b)[n]);
The latter requires C99, or C2011 with VLA support (which is required in C99, but optional in C2011).
I am trying understand how pointers works in C. I am trying a simple case where an array, and a pointer to array are the arguments of a function which will copy the elements of the first one in the second one.
I have written this code
#include <stdio.h>
#define TAM 32
typedef int TablaArray[32];
void copyArray(TablaArray, TablaArray*, int);
void main(){
int t1[] = {1,2,3,4};
int t2[4];
copyArray(t1, t2,4);
for(int i = 0; i <= 3; i ++){
printf("%d - %d\n", t1[i], t2[i]);
}
}
void copyArray(TablaArray t1, TablaArray *t2, int tam){
for(int i = 0; i<tam-1; i++){
printf("%d\n", t1[i]);
*t2[i] = t1[i];
}
}
I am expecting to get something like this with the printf expression:
1 - 1
2 - 2
3 - 3
4 - 4
But definitely I don't know the way... I have been looking in stackoverflow and because I am sure this trivial question is already answered... but I didn't find it...
You need to make sure you are passing two int pointers pointing to both arrays. In your code only one of the arguments is a pointer. The code below should make it more clear:
#include <stdio.h>
void copyArray(int * arr1, int * arr2, int size);
int main(void)
{
int t1[] = {1,2,3,4};
int t2[4];
copyArray(t1, t2,4);
for(int i = 0; i <= 3; i ++)
{
printf("%d - %d\n", t1[i], t2[i]);
}
return 0;
}
void copyArray(int * arr1, int * arr2, int size)
{
for(int i = 0; i < size; i++)
{
printf("%d\n", arr1[i]);
arr2[i] = arr1[i];
}
return;
}
Edit: in what you have written, a TablaArray * is a pointer to an array of 32 ints, while you need an int *
typedef int TablaArray[32];
is bad practice
The problem is connected with array to pointer decay and then with pointer arithmetics:
Pointer decay means that if you pass an array-object of type int x[32] as argument to a function, then it "decays" to a pointer like int *, which points to the first element of the integer array. So be aware that if you pass an int x[32]-object, it's actually passed by reference (the array is not copied) and you may alter the contents of the array in the function.
Now pointer arithmetics:
Incrementing a pointer (or accessing an array through array subscripting) implicitly does pointer arithmetics, and the number of bytes added to the initial value depends on the type of the object to which the pointer points:
typedef int Array10[10];
Array10 arr = { 1,2,3,4,5,6,7,8,9,0 };
int *x = arr; // arrayOfInts decays to a pointer; x points to the &arr[0]
x++; // in terms of bytes, x is incremented by sizeof(int) bytes
int i = x[3]; // gets the int-value on the address of x + 3*sizeof(int)
Array10 *arr10ptr = arr;
arr10ptr++; // in terms of bytes, x is incremented by sizeof(Array10) bytes, which is 10*sizeof(int)
arr10ptr[3]; // 3*sizeof(Array10), i.e. 3*10*sizeof(int)
Now it should be clear why a function parameter being declared as a pointer to an array of int[32] behaves different from a function parameter being declared as an int[32].
So you could correct your program as follows, now knowing that TablaArray t2 will be a reference to the underlying array anyway:
void copyArray(TablaArray t1, TablaArray t2, int tam){
for(int i = 0; i<tam; i++){
printf("%d\n", t1[i]);
t2[i] = t1[i];
}
}
Hope it helps.
Compile with warnings enabled. If you used gcc -Wall -Werror, you would get the following errors:
luis.c:10:6: error: return type of ‘main’ is not ‘int’ [-Werror=main]
void main(){
^~~~
luis.c: In function ‘main’:
luis.c:15:19: error: passing argument 2 of ‘copyArray’ from incompatible pointer type [-Werror=incompatible-pointer-types]
copyArray(t1, t2,4);
^~
luis.c:8:6: note: expected ‘int (*)[32]’ but argument is of type ‘int *’
void copyArray(TablaArray, TablaArray*, int);
^~~~~~~~~
cc1: all warnings being treated as errors
The first one is simple, it should be int main.
The second one is a bit harder to see exactly because you used a typedef. So your prototype is now
void copyArray(int *, int (*)[32], int);
With the second value being a pointer-to-array that by itself is a construct that is not used often.
Instead, you'd just need two pointers to int here, and the size of an array should perhaps use size_t instead:
void copyArray(int *, int *, size_t);
void copyArray(int *t1, int *t2, size_t n){
for (int i = 0; i < tam; i++) {
t2[i] = t1[i];
}
}
Finally, if you use a C99, C11 compiler, it could be nice to use the variable-length arrays arrays to tell that one of the parameters tell the sizes of the arrays; for that we need to reorder the parameters:
void copyArray(size_t, int[*], int[*]);
void copyArray(size_t n, int t1[n], int t2[n]) {
...
}
void copyArray(TablaArray, TablaArray, int); // prototype
void copyArray(TablaArray t1, TablaArray t2, int tam){
for(int i = 0; i<tam; i++){
printf("%d\n", t1[i]);
t2[i] = t1[i];
}
}
this will help
// much faster
#include <string.h>
void copyArray(TablaArray t1, TablaArray t2, int tam){
memcpy(t2, t1, sizeof(t1[0]) * tam);
}
In Your Copy function you were copying the same value of T1 to T2 on the Address Of T2. you can do it with out pointers but pointers helps you to refer the Address
I have a function I would like to have a function to receive a 2D array (H), to read a specified column (col) and to pass it to another array (b).
It appears that the code below is not OK has I was expecting to get a 1 printed.
Any guidance is very much appreciated.
#define nline 5
#define ncol 4
#include <string.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
void count0(int **M,int col, int *a);
void main(){
int i;
int **H;
H=(int**)malloc(nline*sizeof(int*));
for(i=0;i<nline;i++){
H[i]=(int*)malloc(ncol*sizeof(int));
}
H[0][0]=8;
H[0][1]=5;
H[0][2]=6;
H[0][3]=0;
H[1][0]=7;
H[1][1]=5;
H[1][2]=4;
H[1][3]=0;
H[2][0]=5;
H[2][1]=1;
H[2][2]=1;
H[2][3]=7;
H[3][0]=0;
H[3][1]=0;
H[3][2]=0;
H[3][3]=2;
H[4][0]=1;
H[4][1]=0;
H[4][2]=1;
H[4][3]=4;
int *b;
int col=1;
count0(H,col,&b);
printf("num 0=%d\n",b[2]); getchar();
}
/////////////////////////////////////////////////////////////////////////////////
void count0(int **M,int col, int *a){
int i;
a=(int*)malloc(1*sizeof(int));
for(i=0;i<nline;i++){
a[i]=M[i][col];
a=realloc(a,(i+2)*sizeof(int));
}
}
Your argument for the output b is wrong. It needs to be a pointer to a pointer (like how you pass it). Right now you should get a compiler warning about it. The function prototype should be
void count0(int **M,int col, int **a);
Then in the function you need to use the dereference operator to access a:
*a = malloc(1*sizeof(int));
Note that I don't cast the return value of malloc, there no need to and neither should you.
As you already knows the number of rows = nline in your matrix in count0 function. So you should simply allocate all memory for array a in count function one time, you don't need to re-call realloc() function.
void count0(int **M, int col, int** a){
(*a) = malloc(nline * sizeof(int));
for(i = 0; i < nline; i++){
(*a)[i] = M[i][col];
}
}
Note: precedence of [] is higher then * so you need () around *a
just call this function as: count0(H, col, &b);
and free(b); in main() after printf statement to deallocate memory explicitly.
You are trying to have this variable:
int * b;
Point to an newly allocated array after this call:
count0(H,col,&b);
To do this, you must change the signature of count 0 to the following:
void count0(int **M,int col, int **a);
Note that int *a is now int **a. Then in the body of count0, you must use the following lines to allocate/reallocate a:
*a=(int*)malloc(1*sizeof(int));
*a=realloc(a,(i+2)*sizeof(int));
Right now, a is a pointer variable that only exists in the scope of count0. Initially its value is &b (which right now doesn't make sense since &b is an int**, and a is an int*). You have a point to newly allocated memory, which is lost after the function. The changes I suggest will have *a, and therefore b, to point to memory that can be retrieved after the function call.
Consider this code:
#include <stdio.h>
#define N 5
void printMatrix(int (*matrix)[N],int n)
{
int i,j;
for(i=0;i<n;i++){
for(j=0;j<n;j++)
printf("%d",matrix[i][j]);
printf("\n");
}
}
int main()
{
int R[N][N]={{1,2,3},{4,5,6},{7,8,9}};
printMatrix(R,3);
}
This works fine as expected.
Now, I thought to write the functions handling 2D-matrices in a separate source file and link them wherever required.
But then I ran into a problem as in the function printMatrix, the size of array of int to which matrix points (i.e N) is required at compile-time. So, my functions would not work in other cases when the size is different.
So,How can I handle this?
Dynamic Arrays are a solution but i want to know if it can be done with static arrays.
You can't use the built-in 2D array type if both sizes are not known at compile time. A built-in 2D array must have at least one of the two sizes known at compile time.
If both sizes are run-time values, then you have no other choice but to use a "manual" implementation of 2D array, like an array of pointers to arrays, for example. In that case the function declaration might look as follows (two alternative equivalent forms)
void printMatrix(int *const *matrix, int n, int m);
void printMatrix(int *const matrix[], int n, int m);
To access to the array elements you can still use the "traditional" syntax
matrix[i][j]
The array itself would be created as follows (a simple example)
int row0[] = { 1, 2, 3 };
int row1[] = { 4, 5, 6 };
int *matrix[2];
matrix[0] = row0;
matrix[1] = row1;
printMatrix(matrix, 2, 3);
But if you already have a matrix implemented as a built-in 2d array
int matrix[2][3] = { ... };
then just to be able to pass it to the above function you can "convert" it into the above form by using an additional temporary "row pointer" array
int *rows[2];
rows[0] = matrix[0];
rows[1] = matrix[1];
printMatrix(rows, 2, 3);
Write yourself a macro:
#define MAT(i,j) matrix[i*n + j];
and declare "matrix" as a simple pointer to an "int".
Calculate the array index yourself. This will handle an arbitrary two dimensional array, for example:
void printMatrix(int *matrix,int n, int m)
{
int i,j;
for(i=0;i<n;i++){
for(j=0;j<m;j++)
printf("%d",matrix[m * i + j]);
printf("\n");
}
}
Don't try to pass it as a 2-D array; pass a pointer to the first element, then compute offsets manually:
void printMatrix(int *a, size_t m, size_t n)
{
size_t i,j;
for (i = 0; i < m; i++)
{
for (j = 0; j < n; j++)
{
printf("a[%lu][%lu] = %d\n",
(unsigned long) i,
(unsigned long) j,
a[i*n+j]); // treat a as 1-d array, compute offset manually
}
}
}
int main(void)
{
int arr[5][4];
...
printMatrix(&arr[0][0], 5, 4);
...
}
Granted, this will only work for contiguously allocated arrays.
Although the syntax is not exactly the same, but this also happens to work a bit:
#include <stdio.h>
#define N 5
void printMatrix(int* row,int n,int sz)
{
int i,j;
int *currRow;
for(i=0;i<n;i++){
currRow = row+i*sz;
for(j=0;j<n;j++)
printf("%d",currRow[j]);
printf("\n");
}
}
int main()
{
int R[N][N]={{1,2,3},{4,5,6},{7,8,9}};
printMatrix(R[0],3,sizeof(R[0])/sizeof(int));
}