Using pointer of pointer to reference a matrix [duplicate] - c

This question already has answers here:
Why can't we use double pointer to represent two dimensional arrays?
(6 answers)
Closed 3 years ago.
I am very new to C, and I am trying to get a int **data to represent a matrix of integers.
I first created an array of arrays, then I tried referencing the pointer of pointer to that array like so:
int **pointer;
int data[num_rows][num_cols];
pointer = (int**) data[0];
However I get a warning: cast to pointer from integer of a different size.
Can someone please help me understand what is going on, and how can I assign an array to int **pointer? (I have to use the double pointer)

The line int data[num_rows][num_cols]; does not actually declare an "array of arrays!" Rather, it declares a single array with two dimensions - in memory, this will be a single block of data, of size num_rows x num_cols x sizeof(int).
To get an "array of arrays" that you can access using a 'double pointer', you generally have to use the malloc function. Something like the following:
int **pointer = malloc(num_rows * sizeof(int*)); // allocate an array of pointers
for (int i = 0; i < num_rows; ++i) {
pointer[i] = malloc(num_cols * sizeof(int)); // allocate each row array
}
You can then access any [row][column] element via the double pointer:
pointer[row][column] = 1234;
When you've finished with the array(s), be sure to free the memory, like this:
for (int i = 0; i < num_cols; ++i) {
free(pointer[i]); // free each row array
}
free(pointer); // free the array of arrays
Alternatively, given your int data[num_rows][num_cols]; you could avoid the malloc calls inside the for loop, as follows:
int **pointer = malloc(num_rows * sizeof(int*)); // allocate an array of pointers
for (int i = 0; i < num_rows; ++i) {
pointer[i] = &data[i][0]; // Assign a pointer to the beginning of each row
}
Feel free to ask for further clarification and/or explanation.

Related

how to return the 2D array to the main() [duplicate]

This question already has answers here:
Return a 2d array from a function
(10 answers)
Return a 2d array from a function
(3 answers)
Closed 5 years ago.
I am learning c language and always confused with the array return using pointers.My question is:
I want to read and declare the 2D array inside
int ** readMatrix(int rows,int cols); function
and return it to the main()
plz give me the solution in simple language because I was already go through many books but couldn't understand.
thank you
To initialize memory for an 2D array within in another function with the intent to use the very same memory outside this function you must use malloc to ask for the required memory from the OS.
Malloc returns an void pointer to the start adress of the block of memory you requested or NULL if the request could not be served from the OS, which nowadays with home PC's is very unlikely to happen because it means you have run out of memory. malloc doc
If you want to create array of pointer of type Int you have to do the following
see
int ** readMatrix(int rows,int cols){
int** var = (int**) malloc(sizeof(int)*rows); //Here you allocate the memory for the pointer which will later point the the columns
for (int i=0; i<r; i++)
arr[i] = (int *)malloc(cols * sizeof(int)); //Here you allocate the columns
return var;
}
another way would be to map an 2D array onto an 1D array. What do I mean with mapping? Let me show it with an example:
If you want to map all Elements from an 2D array onto 1D array the 1D array must have the same number of Elements as the 2D array otherwise you would miss elements.
Then you need some kind of formula to calc the index from 2D array to an 1D array. The formula is: y*width+x
Width represent the maximum amount of elements one row of the 2D array can contain. X represent your position on the current row and Y represent the row you are currently at.
in C it would look like this:
int* var = malloc(sizeof(int)*rows*cols);
for(int i = 0; i < row; i++)
for(int j = 0; j < cols; j++)
var[i*cols+j] = 0;

multi-dimension array allocation with calloc

I have the following 2-dimension array N*2 (I can't modify its declaration):
bool* myArray[2];
int N;
I want to allocate it with calloc but no success:
myArray = calloc(N, 2*sizeof(bool));
for (int i=0; i!=N; i++)
{
myArray[i] = calloc(2, sizeof(bool));
}
The compiler raises me (on the first calloc):
error: incompatible types in assignment of 'void*' to 'bool* [2]'
what am I doing wrong?
This code:
bool* myArray[2];
int N;
doesn't declare a 2-dimensional array but an array of pointers. This is an important difference because 2-dimensional arrays are not arrays of pointers to arrays -- they are just stored contiguously, like 1-dimensional arrays are (one "row" after the other).
So, as you state you cannot change the declaration, let's instead explain what you need for an array of pointers. With your declaration, you declare exactly 2 pointers, so N can only mean the "second dimension" as in the number of elements in the arrays those pointers point to. With this declaration, you can have 2 times an array of N bools. Allocating them would look like this:
myArray[0] = calloc(N, sizeof(bool));
myArray[1] = calloc(N, sizeof(bool));
There's no need to allocate space for myArray itself, with your declaration, it already has automatic storage.
Do this instead:
bool (*myArray)[2] = calloc(N, sizeof(*myArray));
Or, if you do not wish to modify your declaration, just get rid of the first calloc here and modify your for loop:
myArray = calloc(N, 2*sizeof(bool)); // you do not need that
for (int i=0; i < 2; i++)
{
myArray[i] = calloc(N, sizeof(bool));
}
PS: In C we don't cast malloc, we do that when we wish to compile C++.
The reason you can't reallocate myArray is that myArray is not a pointer. It is an array of two pointers to bool. It is also, contrary to your description, not a "2-dimension array".
All you need to do is
for (int i=0; i < 2; ++i)
{
myArray[i] = calloc(N, sizeof(bool));
}
and you can then use as a '2*N' array, for example to set all elements to true;
for (int i = 0; i < 2; ++i)
{
for (j = 0; j < N; ++j)
myArray[i][j] = true;
}
If you swap the order of indices (e.g. use myArray[j][i] in the inner loop above) and use myArray as a 'N*2' array rather than as a '2*N' array, the result will be undefined behaviour. There is no solution to change that, without changing the declaration of myArray - which you have said you do not want to do.

C , regarding pointers (or pointers to pointers?), **, and malloc

As said in title, I have a question regarding using * twice, like in the main function of the following code. it DOES run, but I don't understand why using ** is right here. What i want is an array of SPPoints , sized n, where parr is the base adress. Why is ** right and * wrong in this case? thanks.
SPPoint code:
struct sp_point_t
{
double* data;
int dim;
int index;
};
SPPoint* spPointCreate(double* data, int dim, int index)
{
if (data == NULL || dim <= 0 || index < 0)
{
return NULL;
}
SPPoint* point = malloc(sizeof(*point));
if (point == NULL)
{
return NULL;
}
point->data = (double*)malloc(dim * sizeof(*data));
for (int i = 0; i < dim; i++)
{
point->data[i] = data[i];
}
point->dim = dim;
point->index = index;
return point;
}
And this is the main function:
int main()
{
int n, d, k;
scanf("%d %d %d", &n, &d, &k);
double* darr = malloc(d * sizeof(double));
if (darr == NULL)
{
return 0;
}
SPPoint** parr = malloc(n * sizeof(SPPoint*));
if (parr == NULL)
{
return 0;
}
for (int i = 0; i < n; i++)
{
for (int j = 0; j < d; j++)
{
scanf(" %lf", &darr[j]);
}
parr[i] = spPointCreate(darr, d, i);
}
}
When using a dynamically-allocated array, it's usually "handled" by having a pointer to the first element of the array, and also having some method of knowing the length, such as explicitly storing the length, or having an end sentinel.
So for a dynamically allocated array of SPPoint * as you have in your code, a pointer to the first one of those has type SPPoint * *
Your existing code creates an array of SPPoint *, i.e. an array of pointers. Each of those pointers points to one dynamically-allocated instance of SPPoint, i.e. you have separate allocations for each entry.
This is viable but you indicate that you instead wanted an array of SPPoint, in which case a pointer to the first element has type SPPoint *.
In order to have such an array, it is a single memory allocation. So you will need to redesign your spPointCreate function. Currently that allocates memory for and initializes only a single SPPoint. Instead you want to separate the allocation from the initialization, since you only need one allocation but you need multiple initializations. Your program logic will read something like:
Allocate one block of memory big enough for n SPPoints
Initialize each SPPoint inside the allocated space
If you have tried this but got stuck then post a new question showing your code and explaining where you got stuck.
An array can behave similarly to a pointer. For instance, int a [] is very similar to int* a. Each function in SPPoint returns a pointer to a SPPoint struct. An array of pointers to SPPoint can be written as a pointer to a pointer to SPPoint. With the malloc command, you are designating a certain amount of memory (enough to hold n pointers to SPPoint) for storage of pointers to SPPoint structs.
Not all pointers are arrays, however. SPPoint** parr is acting as an array holding pointers to single structs of type SPPoint.
Arrays can behave differently from pointers, especially when used for strings.
The reason why it is advantageous to use pointers to SPPoint (as you are now) is that you can view or modify a single element without having to copy the entire struct.

Malloc a 2D array in C [duplicate]

This question already has answers here:
A different way to malloc a 2D array?
(3 answers)
Freaky way of allocating two-dimensional array?
(3 answers)
Closed 6 years ago.
Every time I allocate the memory for a 2D array first I create an array of int** and then with a for I allocate the memory for each element.
For example:
int ** arr = malloc(N*sizeof(int *));
for(i=0; i< N; i++) arr[i] = malloc(M*sizeof(int));
Wouldn't be possible allocate the memory like:
int ** arr = malloc(N*sizeof(int[M]));
or
int ** arr = malloc(sizeof(int[N][M]));
in order to avoid the for?
like this : int (*arr)[M] = malloc(sizeof(int[N][M]));
arr is pointer to int[M].
use like arr[0][M-1];
and free(arr);
int ** arr = malloc(N*sizeof(int[M]));
is incorrect C code, if you simulate it by allocating once
int *arr = malloc(N*M*sizeof(int));
and access it by
arr[i*M + j],
this is an analog to arr[I][j] in your first case.
You have a "pointer to pointer". That cannot represent a 2D array.
The correct declaration of a pointer to a 2D array is
// number of elements in one row
#define COLS 10
// number of rows
#define ROWS 20
int (*array)[COLS]; // mind the parenthesis!
That makes array a pointer to array of COLS ints. The type is `int (*)[COLS], btw. but you don't need the type, see below.
To allocate the array you should then use the standard allocation for a 1D array:
array = malloc(sizeof(*array) * ROWS); // COLS is in the `sizeof`
array = malloc(sizeof(int[ROWS][COLS])); // explicit 2D array notation
Which variant to use is personal style. While the first contains no redundancy (consider you change the declaration of array to use INNER instead of COLS or the element-type to float). The second is more clear at a fist glance, but more prone to errors when modifying the declaration of array.
To free:
free(array);

Am I correctly allocating memory for my pointer arrays in C?

I am trying to track down a bug a big program. I think it is due to how I am passing arrays to my functions. Am I doing this correctly?
main(){
int *x = declarArray(x, 100);
int *y = declarArray(x, 100);
// lines of code....
x = arrayManip(x, 100);
// more code...
int i;
for(i=0; i<100; i++)
y[i] = x[i];
//more code...
free(x);
free(y);
}
This is how I manipulate arrays:
int *arrayManip(int *myarray, int length){
int i;
for(i=0; i<length; i++)
myarray[i] = i;
return array;
}
This is how I initialize the arrays:
int* declareArray(int *myarray, int length){
myarray = (int*) malloc(length*sizeof(int*));
if (myarray==NULL)
printf("Error allocating memory!\n");
int i;
for(i=0; i<length; i++)
myarray[i] = -888;
return myarray;
}
This code seems to work fine on a small scale, but maybe there is a problem once I have many more arrays of larger size that are often getting passed back and forth and copied in my program?
declarArray :
Name is not gramatically correct
The name of the function is not what it does
malloc with sizeof(int*), not sizeof(int). Guarantuee to be a bug in 64 bit machine
malloc fails, you print, but still write to null
passing myarray as argument is a noop as is
-888 is a magic number
There is no error check whatsoever
My advice. Throw it away and start fresh
No, as per my understanding.
You allocating one dim array => elements in that array should be integers and not pointers to integers so instead of this :
myarray = (int*) malloc(length*sizeof(int*));
it should be :
myarray = (int*) malloc(length*sizeof(int));
In function arrayManip you pass param named array, and than you trying to access it as myarray
This:
myarray = (int*) malloc(length*sizeof(int*));
allocates an array of length pointers to an integer, but then puts it into a pointer to an integer (i.e. an array of integers, not pointers to integers). If you want an array of integers, you want:
myarray = (int*) malloc(length*sizeof(int));
or (if you want to zero it):
myarray = (int*) calloc(length, sizeof(int));
which does the size x length calculation itself.
To allocate a list of pointers to integers, you want:
myarray = (int**) malloc(length*sizeof(int*));
or
myarray = (int**) calloc(length, sizeof(int*));
Unless you are fantastically concerned about speed, I find using calloc() results in fewer bugs from uninitialized arrays, and makes the reason for the allocated size more obvious.
The pointer is of word size [2 or 4 ,... depending on machine architecture]. whatever it may point to int,double,float,...
for integer pointer it works if it takes 4 bytes for int in machine. when u go for other data type it 'll lead you to error.
you should allot memory as
pointer = (DataType*) malloc (length * sizeof(DataType));
use malloc and to make your code clear.
void* malloc (size_t size);
malloc reference
use memset to allot default value [-888] for your array.
void *memset(void *str, int c, size_t n)

Resources