I'm writing a simple test program to pass multidimensional arrays. I've been struggling to get the signature of the callee function.
The code I have:
void p(int (*s)[100], int n) { ... }
...
{
int s1[10][100], s2[10][1000];
p(s1, 100);
}
This code appears to work, but is not what I intended. I want the function p to be oblivious whether the range of values is either 100 or 1000, but should know there are 10 pointers (by use of function signature).
As a first attempt:
void p(int (*s)[10], int n) // n = # elements in the range of the array
and as a second:
void p(int **s, int n) // n = # of elements in the range of the array
But to no avail can I seem to get these to work correctly. I don't want to hardcode the 100 or 1000 in the signature, but instead pass it in, keeping in mind there will always be 10 arrays.
Obviously, I want to avoid having to declare the function:
void p(int *s1, int *s2, int *s3, ..., int *s10, int n)
FYI, I'm looking at the answers to a similar question but still confused.
You need to transpose your arrays for this to work. Declare
int s1[100][10];
int s2[1000][10];
Now, you can pass these to a function like this:
void foo(int (*s)[10], int n) {
/* various declarations */
for (i = 0; i < n; i++)
for (j = 0; j < 10; j++)
s[i][j] += 1
}
Because of the way the C type system works, an array argument can only be "flexible" in the sense you want in its left-most index.
You could also create a struct for the matrix and pass it to the function p
struct Matrix{
int **array;
int n;
int m;
};
void p(Matrix *k){
length=k->m;
width=k->n;
firstElement=k->array[0][0];
}
Related
I am trying to write a user defined function that takes some matrices and variables as inputs and gives a matrix as output. So something like this:
cofactor(int A[100][100], n, r, c){
int B[100][100]
//B becomes the cofactor matrix of A after some operations//
return B;
}
and in my main function I just want to write :
C=cofactor(D, n, r, c);
to turn C into the cofactor matrix of D.
But for some reason c language does not support taking a whole 2D array as output of a function. How can I work around this?
I don't want to keep all the junk in the main function. I want to write a separate function that gives me the matrix as output, and simply call that function in my main function.
Currently in your code B will go out of scope and will be destroyed when control exits cofactor.
Thus use pointer to pointer as below.
int **cofactor(int A[100][100], int n, int r, int c){
int **B = malloc(sizeof(int *)*r);
for (int i =0;i<r;i++)
B[i] = malloc(sizeof(int)*c);
//B becomes the cofactor matrix of A after some operations//
return B;
}
And from main.
int **C=cofactor(D, n, r, c);
Note:: NULL checks are not added and allocated memory needs to be freed once done with the processing.
You are correct in that C doesn't allow us to return arrays from functions. This is one area where C is simply plain bad and you'll find yourself choosing between various evils.
The most obvious alternatives are to return an array pointer, or a void pointer.
void pointers should be avoided since they have non-existent type safety.
// bad code
void* cofactor (int A[100][100], int n, size_t r, size_t c)
The array pointer option is rather ugly-looking, hard to read and enforces fixed-size dimensions:
// bad code
int ( *cofactor (int A[100][100], int n, size_t r, size_t c) )[100][100];
Alternatively, also ugly and bad practice, is to hide the array type behind a typedef:
// bad code
typedef int arr_t [100][100];
arr_t* cofactor(int A[100][100], int n, size_t r, size_t c)
The array pointer versions also have the limit that you can't use variable dimensions. But r and c here seem to be rows and columns, so you probably do want the array to have variable size.
This is where some start to use int** out of confusion. But int** cannot be used to point at a 2D array, nor to the first element of a 2D array. It can be used to point at the first element of a 1D array of int* pointers, and then emulate something that looks like an array, but doesn't behave like one. That's not what you want here either, because it is both slow and dangerous. See Correctly allocating multi-dimensional arrays.
Sigh. So what to use!
If you drop the requirement of "function return ing array" (with emphasis on using return), it turns easier and more flexible. Parameter passing to/from functions in C is most often done through the parameters, and most sound APIs reserve the return value for an error type describing the outcome of the function.
The big advantage here is that when passing an array as parameter, we can use variable dimensions:
void func (size_t r, size_t c, int A[r][c])
Suddenly you can have a function accepting any array size, and somewhat type safe as long as r and c have correct values.
The cleanest is to leave allocation to the caller. Then you get
void func (size_t r, size_t c, int A[r][c], int B[r][c])
Out of all options discussed, this is the only pretty one. But it won't work if the function must do the allocation. Then we must return an array through the parameter. And to that with this syntax, turns a bit ugly too:
void copy (size_t r, size_t c, int (**B)[r][c], int A[r][c])
But if we can live with this strange-looking "pointer to array pointer to an array of int[r][c]", then it solves all problems. It can return an array of variable size from a function to the caller.
A function making a copy of any array and returning it would look like this:
void copy (size_t r, size_t c, int (**B)[r][c], int A[r][c])
{
*B = malloc( sizeof(int[r][c]) );
int (*b)[c] = **B; // pointer to the first row in an array int[r][c]
for(size_t i=0; i<r; i++)
{
for(size_t j=0; j<c; j++)
{
b[i][j] = A[i][j];
}
}
}
Or if you will:
#include <string.h>
void copy (size_t r, size_t c, int (**B)[r][c], int A[r][c])
{
*B = malloc( sizeof(int[r][c]) );
memcpy( *B, A, sizeof(int[r][c]) );
}
Full example:
#include <stdlib.h>
#include <stdio.h>
void copy (size_t r, size_t c, int (**B)[r][c], int A[r][c])
{
*B = malloc( sizeof(int[r][c]) );
int (*b)[c] = **B; // pointer to the first row in an array int[r][c]
for(size_t i=0; i<r; i++)
{
for(size_t j=0; j<c; j++)
{
b[i][j] = A[i][j];
}
}
}
int main (void)
{
int array1[2][3] = { {1,2,3}, {4,5,6} };
int (*array2)[2][3];
copy(2, 3, &array2, array1);
int (*arr)[3] = *array2;
for(size_t i=0; i<2; i++)
{
for(size_t j=0; j<3; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
free(array2);
}
I'm having a problem dealing with an array in C. You see, this is a portion of my code which basically reads a file and organizes coordinates of the vertices of parcels of the 3rd-levels administrive divisions in Portugal - which we call Freguesias. In this part of the exercise, I need to write the name of all 2rd-levels administrive divisions - Concelhos (which is already well defined in my code in the array Cartography cartography, that isn't the problem) that appear in the file.
I want to do a function that shows what Concelhos appear in the file and I want to write with this exact subfunctions and functions so I can change some things later, but for some reason it doesn't printf the strings in "command_list_concelhos", it just prints NULL strings. I don't know why this happens, specially since it does rightly so if I do a printf inside and outside the for in "read_string_concelhos".
Sorry if this question is wrongly explained, too big or just a small detail that I am missing, but I don't have a better way to explain it...
#define MAX_STRING 256
#define MAX_NAMES 50
typedef char String[MAX_STRING];
typedef struct {
String list[MAX_NAMES];
int n_strings;
} StringList;
int read_string_concelhos(StringList s ,Cartography cartography, int n)
{
int i, j=1;
strcpy (s.list[j-1], cartography[0].identification.concelho);
for ( i = 0 ; i < n ; i++){
if ( strcmp(cartography[i].identification.concelho, s.list[j-1]) != 0){
strcpy(s.list[j] , cartography[i].identification.concelho);
j++;
}
}
return j; // n_strings
}
void command_list_concelhos(Cartography cartography, int n)
{
StringList s;
s.n_strings = read_string_concelhos(s, cartography, n);
int i;
for(i = 0; i < s.n_strings; i++ )
{
printf("\n", s.list[i]);
}
}
Fail
How it should look like
int read_string_concelhos(StringList s ,Cartography cartography, int n)
should be changed to
int read_string_concelhos(StringList* s ,Cartography cartography, int n)
And inside the function int read_string_concelhos(StringList* s ,Cartography cartography, int n) { ... }, all s.list[...] should be changed to s->list[...]. In this way, parameter s is a pointer therefore strcmp would paste to s declared in command_list_concelhos which is the desired behaviour.
I have successfully fscanf a text file and saved in to an array E2N1. I am trying to pass this into a function as a pointer but it is not working. Whenever I try to call E2N1[0][0], it says that E2N is neither an array or a pointer. I've been looking all over for a solution on this.
(Sorry E2N was meant to be E2N1)
I use fscanf as:
int E2N1[noz.rowE2N][Q.N];
FILE* f = fopen("E2N.txt", "r");
for(i=0; i<noz.rowE2N; i++){
for (j=0; j<Q.N; j++){
fscanf(f,"%d",&E2N1[i][j]);
}
fscanf(f,"\n");
}
fclose(f);
and again I can't pass E2N1 into function.
Your help will be greatly appreciated.
The function is:
double *dudtF = stiffness(&U, &massM, &noz, &newV, &E2N1, &I2E, &B2E, &PP, &QQ);
and I write the function header as:
double *stiffness(double *U, double *massM, MESH *meshN, double *V1, int *E2N1, int *I2E, int *B2E, ordApprox *pp, ordApprox *qq)
V1, I2E, B2E are three arrays and I'm trying to do the same with them as I am trying to do with E2N1.
The funny thing about arrays is that they actually act as pointers.
if you have array char a[3] the variable is equivalent to char* p the same way if you have array char b[3][4] the variable b is equivalent to char** q. In other words, you should consider changing the handling in the method to take reference to reference (and possibly once more to reference) to integer.
Try google... here are some results I've got.
http://www.dailyfreecode.com/code/illustrate-2d-array-int-pointers-929.aspx
http://www.cs.cmu.edu/~ab/15-123S09/lectures/Lecture%2006%20-%20%20Pointer%20to%20a%20pointer.pdf
You don't need to pass as &E2N1, just pass as E2N1 no & as array name itself translates to pointer.
double *dudtF = stiffness(&U, &massM, &noz, &newV, E2N1, &I2E, &B2E, &PP, &QQ);
Also, you need to take it as int ** as its 2-dimensional array.
double *stiffness(double *U, double *massM, MESH *meshN, double *V1, int **E2N1, int *I2E, int *B2E, ordApprox *pp, ordApprox *qq)
Here is the example how to transfer matrix from one function to another ...
void foo (int **a_matrix)
{
int value = a_matrix[9][8];
a_matrix[9][8] = 15;
}
void main ()
{
#define ROWS 10
#define COLUMNS 10
int **matrix = 0;
matrix = new int *[ROWS] ;
for( int i = 0 ; i < ROWS ; i++ )
matrix[i] = new int[COLUMNS];
matrix[9][8] = 5;
int z = matrix[9][8] ;
foo (matrix);
z = matrix[9][8] ;
}
You cannot reference a multi-dimensional array passed to a function by point referencing as in the following:
int iVals[10][10];
foo(iVals);
void foo(int** pvals)
{
// accessing the array as follows will cause an access violation
cout << pvals[0][1]; // access violation or unpredictable results
}
You will need to specify the second dimension to the array in the function prototype
for example:
foo(int ivals[][10])
{
cout << ivals[0][1]; // works fine
}
If do not know the dimensions, then I would suggest you follow the principles outlined here:
void foo(int *p, int r, int c)
{
for(int i=0; i<r; i++)
{
for(int j=0; j<c; j++)
{
printf("%d\n", p[i*c+j]);
}
}
}
int c[6][6];
// pointer to the first element
foo(&c[0][0], 6, 6);
// cast
foo((int*)c, 6, 6);
// dereferencing
foo(c[0], 6, 6);
// dereferencing
foo(*c, 6, 6);
I hope this helps.
Alternatively you could use SAFEARRAY - see:
http://limbioliong.wordpress.com/2011/06/22/passing-multi-dimensional-managed-array-to-c-part-2/
I am learning how to use dynamic arrays in C. What I want to do is to create a dynamic array data, and put "1" into the first entry using the function test().
void test(void)
{
data[0] = 1;
}
int main(void)
{
int *data = malloc(4 * sizeof *data);
test();
return 0;
}
This compiles in Visual Studio 2010 but the program crashes when run. Instead of using test(), using data[0] = 1 works.
My (newbie) guess is that I need to pass a pointer to data to function test(). How should I write this?
Attempt
void test(int *data)
{
data[0] = 1;
}
Then, in main use test(data) instead of just test().
Edit
The attempt works. However, is this a "proper" way of doing it?
When you use a local variable in C, (dynamic or static, array or not), you need to pass it to the function that will be using it. That's what's wrong with your initial code, test() doesn't know anything about data.
When you declare an array, (dynamic or static) you can pass it to the function in the same ways. The following code is pretty pointless, but it illustrates that using a dynamic array is really no different than a static array.
void assign_function(int arr[], int len_of_arr, int *arr2, int len_of_arr2);
void print_function(int *arr, int len_of_arr, int arr2[], int len_of_arr2);
int main()
{
int data[2] = {0}; // static array of 2 ints
int *data2 = malloc(3 * sizeof(int)); // dynamic array of 3 ints
assign_function(data, 2, data2, 3);
print_function(data2, 3, data, 2);
free(data2); // One difference is you have to free the memory when you're done
return 0;
}
So we can pass the arrays, be they dynamic or static, via array[] or as a pointer, but we need to pass an int along as well so we know how big the array is.
void assign_function(int arr[], int len_of_arr, int *arr2, int len_of_arr2)
{
int count;
for(count = 0; count < len_of_arr; count++) //This is the static array
arr[count] = count;
for(count = 0; count < len_of_arr2; count++) //This is the dynamic array
arr2[count] = count;
}
Then just for fun I reverse which array is pass in arr and arr2 here, and also how they're accessed:
void print_function(int *arr, int len_of_arr, int arr2[], int len_of_arr2)
{
int count;
for(count = 0; count < len_of_arr; count++) //This is the dynamic array now
printf("arr[%d] = %d\n", count, *(arr+count));
for(count = 0; count < len_of_arr2; count++) //And this is the static array
printf("arr2[%d] = %d\n", count, *(arr2+count));
}
Point being, passing via [] or as a pointer, and accessing via [] or a deferenced pointer is up to you, both are fine, both work. I try to avoid pointers when I can as they tend to be hard to read and more error prone when writing.
You can pass arrays dynamically in two ways :
Using a simple pointer and then using pointer arithmetic to manipulate
void test (int * data, int i)
{
*(data + i) = 1; //This sets data[i] = 1
}
Or this way :
void test(int data[], int i)
{
data[i] = 1; //This is the more familiar notation
}
Either of these ways is the 'proper' way to go about this.
The variable 'data' in test is locally scoped. It's not the same 'data' that is in main. You should pass a pointer to 'data' through the parameters of test().
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));
}