I was asked to write a program that gets a two dimensional array (a matrix), number of columns,and number of rows, and the program will return the transpose matrix (without using a [][], meaning only using pointer arithmetics)
The program I wrote, does indeed transpose the matrix, it is no problem. My problem is understanding how to return. here's my code:
int** transpose_matrix(matrix mat1,int number_of_rows,int number_of_columns)
{
matrix mat2;
int row_index,column_index;
for(row_index=0;row_index<number_of_rows;row_index++)
{
for(column_index=0;column_index<number_of_columns;column_index++)
**(mat2+(column_index*number_of_rows)+row_index)=**(mat1+(row_index*number_of_columns)+column_index);
}
// at this point, mat2 is exactly the transpose of mat1
return mat2;
}
now here's my problem: I can't return a matrix, closest thing I can do is return the address of the first value of the matrix, but even if i do that, all the rest of the matrix will be unusable as soon as i exit transpose_matrix function back into void main...How can I return mat2?
One, a two-dimensional array is not a double pointer.
Two, dynamic allocation. If matrix is a two-dimensional array type, then write something like this:
typedef int matrix[ROWS][COLUMNS];
typedef int (*matrix_ptr)[COLUMNS];
matrix_ptr transpose_matrix(matrix m, int rows, int cols)
{
matrix_ptr transposed = malloc(sizeof(*transposed) * rows);
// transpose, then
return transposed;
}
OK: Here you have 3 thing:
You cannot return a pointer to a local variable (it will be garbage
after return and the stack (memory) where it was is reused).
Array decay to pointer to the first element when passed.
Pointer arithmetic: p+1 increment the adress in p by sizeof(*p), so
p point to the next element, not to the next byte.
The simple fix for your code (this works for any matrix size) :
int* transpose_matrix(int *mat1,int number_of_rows,int number_of_columns)
{
int *mat2=malloc(number_of_rows*number_of_columns*sizeof(int));
int row_index,column_index;
for(row_index=0;row_index<number_of_rows;row_index++)
{
for(column_index=0;column_index<number_of_columns;column_index++)
mat2[column_index*number_of_rows+row_index]=mat1[row_index*number_of_columns+column_index];
}
// at this point, mat2 is exactly the transpose of mat1
return mat2;
}
...
print(m,r,c); // I hope you have a print()
int *t=transpose_matrix(m,r,c);
print (t,c,r);
...
// use t[max: c-1][max: r-1]
free(t);
If we have only fixed size matrix (well with C99 we can use varable length array too!).
typedef int Matrix[ROWS][COLUMNS];
typedef int TMatrix[COLUMNS][ROWS];
typedef int (*pMatrix)[COLUMNS];
typedef int (*pTMatrix)[ROWS];
pTMatrix transpose_matrix(Matrix m , int rows, int cols)
{
pTMatrix t = malloc(sizeof(*t)*cols);
for (int r=0; r<rows ; ++r)
for (int c=0; r<cols ; ++r)
t[c][r]=m[r][c];
return t;
}
Well, if rows and cols are fixed you dont need to pass it.... hmmm...
Related
I will go straight to what I'm asking for, I also see some similar question but is not what I'm looking for...so it seems I have to ask with a new forum.
I'm preparing myself for a future examination, where is not required the pointer, but I would like to get some extra information and abilities.
Here's the code followed by the question...
I'm using Fedora 33, I know is different from some IDE on Windows (ex: Visual Studio or Dev C++)
/* It's just a simple test, if this work I will get myself into a more complicated one, as you could read in the
* forum, I'm getting ready ( just a recheck of my abilities ) for an universitary examinaton. */
#include <stdio.h>
#include <stdlib.h>
#define N 5
void casual_generation(int** mat);
void prompt_print(int** mat);
int main()
{
int **mat[N][N];
casual_generation(**mat);
prompt_print(**mat);
}
void casual_generation(int** mat)
{
int i=0,j=0;
for(i=0;i<N;i++)
for(j=0;j<N;j++)
mat[i][j] = rand() % 50;
}
void prompt_print(int** mat)
{
int i=0,j=0;
for(i=0;i<N;i++)
{
for(j=0;j<N;j++)
printf("%d ", mat[i][j]);
printf("\n");
}
}
Somebody else on the forum used malloc, struct or other stuff, as you can see in this picture, when I try to execute him it says "Segmentation fault (core dumped)"
screen error
Where is my error?
And if you want, can you also send me the version with the passed value pointer?
Thanks for whoever will give me an answer, and time dedicated.
This declaration
int **mat[N][N];
does not make a sense. It means that you have a matrix elements of which are pointers of the type int **. But you need a matrix elements of which are integer numbers of the type int. That is you need a declaration like this
int mat[N][N];
So now you have a two-dimensional array (or matrix) of integers.
As you are going to pass this two-dimensional array to functions then used as an argument expression it is converted to pointer to its first element of the type int ( * )[N].
Correspondingly the functions that accepts such an array should be declared like
void casual_generation( int mat[][N], size_t n );
void prompt_print( int mat[][N], size_t n );
or (that is fully equivalent) like
void casual_generation( int ( * mat )[N], size_t n );
void prompt_print( int ( *mat )[N], size_t n );
because the compiler adjusts function parameters having array types to pointers to array element types.
Now for example the first function can be defined the following way
void casual_generation( int ( * mat )[N], size_t n )
{
for ( size_t i = 0; i < n; i++ )
{
for ( size_t j = 0; j < N; j++ )
{
mat[i][j] = rand() % 50;
}
}
}
And the function can be called like
casual_generation( mat, N );
A similar way can be defined the function prompt_print.
Using the second parameter makes the function more general. For example it can be called for two-dimensional arrays with different numbers of rows.
Now I will explain why you are getting a segmentation fault in your original code.
You have this declaration
int **mat[N][N];
a two dimensional array of pointers of the type int **.
Then you are using the expression **mat as an argument of function calls like this
casual_generation(**mat);
Then you are applying the dereference operator like *mat the array designator is converted to pointer to its first element (row) having the type int ** ( * )[N]. So dereferencing this pointer you get the first row of your array int **[N]. Applying the second time the dereferenced operator to this expression that has an array type the used expression is again is converted to pointer to its first element of the type int **( * ). That is it points to the first element of the first row of the original two-dimensional array. Dereferencing this pointer you get the first element of the type int **. This uninitialized pointer with indeterminate value the function accepts as its argument.
Thus dereferencing this first uninitialized element of the original matrix within the function
mat[i][j] = rand() % 50;
^^^
you get a segmentation fault. The reason of the fault is the incorrect matrix and the corresponding function parameter as it was shown above in tbe beginning of the answer.
Where is my error?
The "Segmentation fault" error happens because you define the variable mat as a pointer, but don't allocate any memory for it to point to.
int **mat[N][N];
You meant to do
Int mat[N][N];
and
casual_generation(mat);
prompt_print(mat);
By passing **mat you are passing mat[0][0] that is an int, but you want to pass the whole matrix which is a pointer to pointers to int (i.e. int **)
And you may want to introduce srand() in your code.
Just to make things clear:
mat is of type int ** and it's the whole matrix (or if you want it's a pointer to the first row)
*mat is of type int * and it's the first row of the matrix (or if you want it's a pointer to the first element of the first row)
**mat is of type int and it's the first element of the first row of the matrix
int **mat[N][N];
Here, you defined a double pointer to a 2D array. You only need to use one of those - a double pointer or a 2D array, like so:
int mat[N][N];
However, the bigger problem comes from trying to interchange 2D arrays and double pointers. This isn't possible in C since the 2D array is laid out flat in memory.
You need to create an array mat_ptr of pointers yourself and then pass that to casual_generation and prompt_print.
Finally, these casual_generation and prompt_print functions expect to be given a pointer, so you shouldn't dereference the pointer with ** before calling the function.
The final working code is:
int main()
{
int mat[N][N];
int *mat_ptr[N];
for (int i = 0; i < N; i++)
mat_ptr[i] = mat[i];
casual_generation(mat_ptr);
prompt_print(mat_ptr);
}
As you can find a detailed explanation why the code crashed in the other answer I will only propose a quite elegant solution that uses a neat though little known feature from C99 called Variable Length Arrays (aka VLA).
#include <stdio.h>
#include <stdlib.h>
void casual_generation(int n, int mat[n][n]);
void prompt_print(int n, int mat[n][n]);
int main()
{
const int N = 5;
int mat[N][N];
casual_generation(N, mat);
prompt_print(N, mat);
}
void casual_generation(int n, int mat[n][n])
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
mat[i][j] = rand() % 50;
}
void prompt_print(int n, int mat[n][n])
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
printf("%d ", mat[i][j]);
printf("\n");
}
}
It compiles in pedantic mode with no warnings and it works like a charm.
VLA were introduced to C to simplify numerical computation over multidimensional arrays.
I am trying to compute the power of the matrix A using multiplications.
I am having problems with the ArrayPower function. It does not function as i think it should.The MultiArray function however seems to work fine. Can anyone help me ?
#include <stdio.h>
int** MultiArray(int a[2][2],int b[2][2]);
int** ArrayPower(int a[2][2],int e);
int main(void)
{
int fa[2][2];
fa[0][0]=0;
fa[0][1]=1;
fa[1][0]=1;
fa[1][1]=1;
int **multifa=malloc(sizeof(int)*2);
for (int i=0;i<2;i++) {
multifa[i]=malloc(sizeof(int)*2);
}
multifa=ArrayPower(fa,2);
printf("%d %d\n",multifa[0][0],multifa[0][1]);
printf("%d %d\n",multifa[1][0],multifa[1][1]);
return 0;
}
int** MultiArray(int a[2][2], int b[2][2]) {
//multi a *b
//memory allocation
int i,rows=2,cols=2;
int **c=malloc(rows*sizeof(int));
for (i=0;i<rows;i++) {
c[i]=malloc(cols*sizeof(int));
}
c[0][0]=a[0][0]*b[0][0]+a[0][1]*b[1][0];
c[0][1]=a[0][0]*b[0][1]+a[0][1]*b[1][1];
c[1][0]=a[1][0]*b[0][0]+a[1][1]*b[1][0];
c[1][1]=a[1][0]*b[0][1]+a[1][1]*b[1][1];
return c;
}
int** ArrayPower(int a[2][2],int e) {
//memory allocation
int i,rows=2,cols=2;
int **c=malloc(rows*sizeof(int));
for (i=0;i<rows;i++) {
c[i]=malloc(cols*sizeof(int));
}
c[0][0]=a[0][0];
c[0][1]=a[0][1];
c[1][0]=a[1][0];
c[1][1]=a[1][1];
for (i=1;i<e;i++) {
c=MultiArray(a,c);
}
return c;
}
MultiArray is declared as taking a second parameter of type int [2][2], but it is called with an argument of c, which as type int **. These are not compatible types.
In a parameter, the type int [2][2] is automatically converted to a pointer to an array of two int, the type int (*)[2]. This is a pointer to a place where there are two int objects (and, because we know it is the first element of an array of two arrays of two int objects, we know there are two more int objects beyond the first two).
The definition of c with int **c means that c is a pointer to a pointer to an int. A pointer to a pointer and a pointer to an array are different and are not compatible.
One way to fix this is to define c with int (*c)[2] = malloc(2 * sizeof *c);. It is then unnecessary to have the loop after the definition that allocates more space; the single allocation allocates the entire array.
The return type of MultiArray should be changed similarly, as well as the code within it and elsewhere in the program. Alternatively, the second parameter of MultiArray can be changed from int b[2][2] to int **b. (This latter is an easier edit but produces an inferior program, since it uses more pointers and allocations than necessary.)
You should always compile your code with warnings enabled. That would have alerted you to the incorrect call.
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.
I am trying to pass a double-dimensional array to a function, but it throws this error all the time. My code is below:
void initialize_centroids(int *,int,int);(Initialization)
initialize_centroids(centroid[0],noofcentroids,newnoofvar);(inside my main)
void initialize_centroids(int *carray,int p,int q)
{
int i,j;
for(i=0;i<p;i++)
{
for(j=0;j<q;j++)
{
carray[i][j]=i;
}
}
return;
}
You're passing a pointer to an int (int*), but you're trying to use two subscripts. Is it a 2D array? Then the parameter needs to be a pointer to a pointer to an int: int**
void initialize_centroids(int**, int, int);
int centroid[][] = .... // wherever this comes from
initialize_centroids(centroid, noofcentroids, newnoofvar);(inside my main)
void initialize_centroids(int** carray, int p, int q)
{
int i,j;
for(i=0;i<p;i++)
{
for(j=0;j<q;j++)
{
carray[i][j]=i;
}
}
return;
}
Don't de-reference centroid when passing in. Doing that will only pass your first row. Do this:
initialize_centroids( centroid, noofcentroids, newnoofvar );
Then you need to use the correct type here:
void initialize_centroids( int **carray, int p, int q )
Your array is presumably an int**. That means it's a pointer to a location in memory that contains an array of int* pointers. Each of those pointers (I assume) references memory that has been allocated one row of your array.
Now, once you obtain one of these pointers by doing carray[i] you have selected row i. You now have an int* which means it points to an array of int.
Finally, carray[i][j] selects a specific integer from column j on row i.
[edit]
Theory about what might be going wrong... You may not be allocating a 2D array in a dynamic sense, or indeed it might be a 1D array and you are supposed to use stride-lengths etc. Here is a solution that you can use for allocating a 2D array dynamically, and indexing it as carray[i][j].
Note: Some people have gotten upset at me for this method in the past due to alignment concerns, but I have never had issues. I think they were just having a grumpy day. For those who are worried about alignment, it's easy to adjust for that, but is too complicated for this example.
int** allocate_array2d( int rows, int cols )
{
int i, **arr, *data;
arr = (int**)malloc( rows * sizeof(int*) + rows*cols*sizeof(int) );
data = (int*)(arr + rows);
for( i = 0; i < rows; i++ ) {
rows[i] = data;
data += cols;
}
return arr;
}
void free_array2d( int** arr ) {
free((void*)arr);
}
Now, in your main:
int** centroid = allocate_array2d( noofcentroids, newnoofvar );
initialize_centroids( centroid, noofcentroids, newnoofvar );
[more...]
Okay.Yes I allocated memory like this centroid[100][100] – Bobby 11
mins ago
In that case, you should declare:
void initialize_centroids( int carray[100][100], int p, int q )
{
//...
}
No need to use my dynamic array example
Suppose I have a function, int function(int N, int c[N]){...}, taking as parameters an integer and an array. Suppose now I have a double array **c of size 'N times 2' and suppose, I want to apply the function function to one column of the double arrow, c[i][0], i varying from to N-1. How am I supposed to use this function. Does it looks like something like function(N,*c[0]) ?
Does anyone can help ?
An array in C always decays to a pointer to its first element when passed into a function. This is good to know in some situations.
As an example, you could write
int list[10];
func (int *x) {
int i;
for (i = 0; i < 10; i++) {
printf("%d", x[i]);
}
}
x[i] is really just syntactic sugar. In C, when you use bracket notation to access an element of an array, it gets converted to *(x + i), where x is the name of the array.
This works because of pointer arithmetic. If x is the name for an array of 10 integers, then the value of x in an expression is the address of the first integer of the array.
x + i will always point to the i-th element after x (C takes into account the size of the element type stored in the array, and increments the pointer accordingly).
Thus, when passing 2d arrays, the array decays to a pointer to its first element - which is an array.
A function signature taking a 2d array can be written as
func(int x[][columns] {
...
}
// but could also be written as
func(int (*x)[columns]) {
...
}
which indicates that x is a pointer to an array of integers.
Sometimes you need to write a function to accept a 2 dimensional array where the width is not known until run time. In this case, you can pass a pointer to the [0][0] element and also pass the two dimensions, and then use pointer arithmetic to get the right element. For example,
print_2d_array (int *x, height, width) {
int i, j;
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
printf("%d", x[i * width + j]);
}
}
}
int list[10][10];
print_2d_array (&list[0][0], 10, 10);
would work for a dynamically allocated 2d array.
In c langauge, for single dimentional array you no need to mention the size of the array in the function arguments while passing an array to that function.
If it is a single dimentional array
...
int a[10];
func(10, a);
...
void func(int size, int x[]) //no need to mention like int x[10]
{
//here x is not an array. Its equivalent to int *
printf("%d", sizeof(x)); // this will print 4 or 8 not 40
}
If it is 2D array
...
int a[10][5];
func (10, a);
...
void (int rows, int x[][5]) //here int x[][] is invalid
{
}