The purpose of a triple pointer in C [duplicate] - c

This question already has answers here:
Triple pointers in C: is it a matter of style?
(5 answers)
Closed 4 years ago.
While I have seen some threads on this, I fail to understand the meaning behind triple pointers, since it seems that it's possible to do the same without them.
void Reading(int *N, int ***M) {
printf("Input an integer N: \n");
scanf("%d", N);
*M = malloc(N * sizeof(int*));
int i;
for (i = 0; i < N; i++)
*(*M+i) = malloc(N * sizeof(int));
printf("Input N*N integers that will form a matrix \n");
int i, j;
for (i = 0; i < *N; i++)
for (j = 0; j < *N; j++)
scanf("%d", &((*M)[i][j]));
}
This code makes **M a 2D array. If I take the malloc procedures and put them into main, the triple pointer isn't needed anymore. Could someone please explain why this is the case ?

If I take the malloc procedures and put them into main, the triple pointer isn't needed anymore.
There are two ways to pass a variable to a function: either by value or by reference. When you pass the reference of a variable, that allows you to modify it.
Example:
void fun(int a) {
a = 42; // Does nothing
}
int b = 9;
fun(b);
// b is unchanged.
void fun(int *a) {
*a = 42;
}
int b = 9;
fun(&b);
// b equals 42.
Your variable happens to be a of type int **, when you pass the address (reference) of this variable, this makes it a int ***.

Related

Why did the array lose the last element when passed into another function? [duplicate]

This question already has answers here:
Why isn't the size of an array parameter the same as within main?
(13 answers)
Closed 1 year ago.
I made an static int arr[3] and set to 1, 2, 3.
I can print 1, 2, 3 in the same function.
But when I pass the array it only prints 1, 2.
Why? What happened? How do I fix this?
#include <stdio.h>
void printArray(int* arr){
size_t n = sizeof(arr)/sizeof(arr[0]);
for(int i=0; i<n; i++){
printf("%d\n",arr[i]);
}
}
int* makearray()
{
static int arr[3];
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
printf("The Array before passing onto stack\n");
size_t n = sizeof(arr)/sizeof(arr[0]);
for(int i=0; i<n; i++){ printf("%d\n",arr[i]);}
printf("\nThe Array when attempting to pass to another function\n");
printArray(arr);
return arr;
}
int main(void) {
int* m = makearray();
return 0;
}
By converting your array to a pointer, you removed the information that sizeof needs to know its total length.
Instead, it just gives you the size of a single int *, which is twice the size of a single int on your machine.
Hence, you only see the first two elements.
In C, you're basically forced to pass around the length alongside the pointer. You can wrap the two in a struct to make it easier to use, but don't expect the niceties of other languages you may be used to.

Segmentation fault using scanf for float ** type

I'm trying to code a function that would ask the user to enter matrix. It prompts the number of lines, the number of columns and then prompts the value for each element of the matrix:
#include <stdio.h>
#include <stdlib.h>
void enterMatrix(float ** matrix, int nbLines, int nbColumns){
for (int i = 0; i < nbLines * nbColumns; i++){
printf("i = %d? ", i);
scanf("%f", matrix[i]);
}
}
int main(void){
int nbLines, nbColumns;
printf("nbLines? "); scanf("%d", &nbLines);
printf("nbColumns? "); scanf("%d", &nbColumns);
float *matrix[nbL * nbCol];
enterMatrix(matrix, nbLines, nbColumns);
}
Everything works fine until I enter a value for i = 0 and then press enter, which leads to a segmentation fault.
Any idea as to what could be wrong?
Your problem is because
float *matrice[nbL * nbCol];
defines an array of uninitialised pointers (i.e. an array of float *), not an array of float. This is then passed to enterMatrix() as a pointer to pointer to float (i.e. a float **). The scanf() calls then read to matrix[i] which is an uninitialised pointer. The result is undefined behaviour.
One fix would be to change the definition of matrice in main() to
float matrice[nbL * nbCol];
and change the function to (I've used comment to highlight changes)
void enterMatrix(float *matrix, int nbLines, int nbColumns) /* note type of matrix */
{
for (int i = 0; i < nbLines * nbColumns; i++)
{
printf("i = %d? ", i);
scanf("%f", &matrix[i]); /* note what the second argument is */
}
}
You need to allocate memory dinamically since you do not know at compile time which values the variables nbLines and nbColumns will hold.
So you need to first declare the pointer to the matrix:
float **matrix;
Then start allocate memory according to user input:
matrix = (float **)malloc(nbLines * sizeof(float *));
for (int i = 0; i < nbLines; i++)
{
matrix[i] = (float *)malloc(nbColums * sizeof(float ));
}
The segmentation fault error happens becouse you are not allocating memory for your matrix, but just a [nbL * nbCol] pointers to float
You don't allocate enough memory for your array, thus you invoke Undefined Behavior, since you go out of bounds, causing a Segmentation fault.
You could declare it like a 2D array, like this:
/* TODO: Check if allocation succeeded. (check for NULL pointer) */
float** matrix;
matrix = malloc(nbLines * sizeof(float*));
for(int i = 0 ; i < N ; i++)
matrix[i] = malloc(nbColumns * sizeof(float));
I have other approaches for allocating a 2D array dynamically here.
Please note: Do I cast the result of malloc? No!
Also do not forget to free().
You could emulate a 2D array with an 1D array, like this:
void enterMatrix(float* matrix, int nbLines, int nbColumns){
for (int i = 0; i < nbLines ; i++) {
for (int j = 0; j < nbColumns; j++) {
scanf("%f", matrix[i + nbColumns * j]);
}
}
float matrix[nbLines * nbColumns];
You're creating a variable length array, and, of pointers.
While other answers are perfectly valid, if you really want a 2D array, you just need to change the declaration:
float matrix[nbLines][nbColumns];
to declare a 2D variable length array of floats.
Now the hard point is to pass this VLA to a function and preserve dimensions.
For that you could use C99 way of passing VLAs (note that dimensions must be located before the VLA itself). Reference: Passing a multidimensional variable length array to a function:
void enterMatrix(int nbLines, int nbColumns, float matrix[][nbColumns] ){
for (int i = 0; i < nbLines; i++){
for (int j = 0; j < nbColumns; j++)
{
scanf("%f", &matrix[i][j]);
}
}
}
call as follows:
enterMatrix(nbLines, nbColumns, matrix);

Passing a 2d array as a pointer C [duplicate]

This question already has answers here:
C, passing 2 dimensional array
(2 answers)
Closed 9 years ago.
So I have a recursive function that requires it to be of type void, without turning to global variables how can I pass a 2d array as a pointer and dereference once I edit values in the recursive function? I already tried int * m[10][10], I can't show all of the code since it is an assignment, pointers aren't required in the assignment but global variables are not permitted
Void h(int * m[10][10]){
int x = 5;
int y = 5;
*m[x][y]=7;
}
That's the general idea
Simply try this
Void h(int m[][10]) {
...
m[x][y]=7;
}
Call your function either as
h(&m[0]); // Passing the address of first row of 2D array m.
or
h(m); // As array names decays to pointer to first element of the array. Note that
// m will decays to pointer to m[0], not m[0][0].
It all depends on how you declared the array supposed to be passed to your function.
If you declared it like this
int my_array[10][10]; // array declaration
then
void fun (int m[10][10]); // prototype of a function accepting my_array
fun (my_array); // calling the function
is what you are looking for.
In that case, m is a constant pointer to 100 contiguous ints that are accessed as a 10x10 2D array.
Other possible variant:
int * my_array[10];
for (i = 0 ; i != 10 ; i++) my_array[i] = malloc (10*sizeof(int));
void fun (int m[10][]); // these syntaxes are equivalent
void fun (int * m[10]);
or this one:
int ** my_array;
my_array = malloc (10 * sizeof (int*));
for (i = 0 ; i != 10 ; i++) my_array[i] = malloc (10*sizeof(int));
void fun (int m[][]); // these syntaxes are equivalent
void fun (int * m[]);
void fun (int ** m);
or this pathological one:
int (* my_array)[10];
int a0[10];
int a1[10];
/* ... */
int a9[10];
my_array = malloc (10 * sizeof (int *));
my_array[0] = a0;
my_array[1] = a1;
/* ... */
my_array[9] = a9;
void fun (int m[][10]); // these syntaxes are equivalent
void fun (int (* m)[10]);
If your variable declaration and function prototype are not consistent, you will not access the array properly from within your function, read incoherent values, and mess up your memory and possibly crash if you attempt to modify an element.
If you have nothing better to do, you can read this little essay of mine on the subject for further details.
void h(int** m) {
int x = 5;
int y = 7;
m[x][y] = 7;
}
int main(int argc, char* argv[])
{
int** a = (int **)malloc(10*sizeof(int *));
for (int i=0; i<10; i++) {
a[i] = (int *)malloc(10*sizeof(int));
}
h(a);
return 0;
}

Write a function to malloc double pointer

I need to write a function that creates a double pointer using malloc.
This is how I declared my double pointer as I normally would:
double **G; //Create double pointer to hold 2d matrix
*G = malloc(numNodes * sizeof(double*));
for(i = 0; i < numNodes; i++)
{
G[i] = malloc(numNodes*sizeof(double));
for (j = 0; j < numNodes; j++)
{
G[i][j] = 0;
}
}
Now I tried replacing it with:
double **G;
mallocDoubleArr(G, numNodes);
With the function being:
void mallocDoubleArr(double **arr, int size)
{
int i, j;
*arr = malloc(size * sizeof(double*));
for(i = 0; i < size; i++)
{
arr[i]= malloc(size*sizeof(double));
for (j = 0; j < size; j++)
{
arr[i][j] = 0;
}
}
}
Why doesn't this work?
You need one more "indirection", in other words pass G by reference like a pointer to a pointer to a pointer to float:
void mallocDoubleArr(double ***arr, int size);
And then call it as
mallocDoubleArr(&G, numNodes);
Modify mallocDoubleArr accordingly, like for example
(*arr)[i] = malloc(size*sizeof(double));
For starters, you need to change the line
*G = malloc(numNodes * sizeof(double*));
to
G = malloc(numNodes * sizeof(double*));
(you can't dereference a pointer safely until you've assigned something to it.)
Secondly, your function modifies the pointer passed in, so you need a pointer to it. Your signature should instead by
void mallocDoubleArr(double ***arr, int size)
and you will need to add the relevant indirections in your code to access the pointer that the pointer is pointing to.
A lot of confusion for beginners working with pointers comes from, in my opinion, thinking that they are something different than regular old variables. Pointers, like ints, floats, etc. are just variables that live on the stack: they have addresses, and they are passed to functions the same way. If you want to change a variable (int, float, pointer, etc) in a function, you need to pass a pointer to it. There is no difference in this regard.
C is call-by-value. In
double **G;
mallocDoubleArr(G, numNodes);
you are passing an uninitialized variable to mallocDoubleArr. It may be zero, it may be something else, but it almost certainly isn't something that mallocDoubleArr can assign to.
We can change the code, and the function's definition, to pass in G's address, but then you're dealing with yet another level of pointer. That might make it harder to understand the code. If that really isn't a requirement, I'd propose instead to have mallocDoubleArr return a double**.
double **G;
G = mallocDoubleArr(numNodes);
double **mallocDoubleArr(int size)
{
int i, j;
double **arr;
arr = (double **) malloc(size * sizeof(double *));
/* continue with old code */
return arr;
}
[edit: bstamour's post was made while I was writing mine. Sorry for any overlap.]
I use for matrix operations code like following for allocating and freeing.
int **inputMatrix, i, j;
Grid myGrid = *grid;
inputMatrix = (int *) calloc (myGrid.num_nodes, sizeof(int*));
for(i=0; i < myGrid.num_nodes; i++){
inputMatrix[i] = calloc(myGrid.num_nodes, sizeof(int));
for(j=0;j<myGrid.num_nodes;j++){
inputMatrix[i][j] = 0;
}
};
for(i=0; i < myGrid.num_nodes; i++){
free(inputMatrix[i]);
}
free (inputMatrix);

C error "variable-sized object may not be initialized" [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C compile error: “Variable-sized object may not be initialized”
I've got a problem cause my compiler still gives me an error: Variable-sized object may not be initialized. What's wrong with my code?
int x, y, n, i;
printf ("give me the width of the table \n");
scanf ("%d", &x);
printf ("give me the height of the table\n");
scanf ("%d", &y);
int plansza [x][y] = 0;
int plansza2 [x][y] = 0;
Of course I want to fill the table with 'zeroes'.
Unfortunately the program still doesn't work. The tables are displayed with numbers like '416082' on all of their cells. My code looks like this now.:
int plansza [x][y];
memset(plansza, 0, sizeof plansza);
int plansza2 [x][y];
memset(plansza2, 0, sizeof plansza2);
printf("plansza: \n");
for(j=0;j<x;j++) {
for(l=0;l<y;l++) {
printf("%d",plansza[x][y]);
printf(" ");
}
printf("\n");
}
printf("plansza2: \n");
for(m=0;m<x;m++) {
for(o=0;o<y;o++) {
printf("%d",plansza2[x][y]);
printf(" ");
}
printf("\n");
}
Your two arrays are variable lenght arrays. You cannot initialize a variable length array in C.
To set all the int elements of your arrays to 0 you can use the memset function:
memset(plansza, 0, sizeof plansza);
By the way to initialize an array which is not a variable length array, the valid form to initialize all the elements to 0 is:
int array[31][14] = {{0}}; // you need the {}
If both dimensions are unknown, you'll have to use a one-dimensional array, and do the indexing yourself:
int *ary = (int *) malloc(x * y * sizeof(int));
memset(ary, 0, x * y * sizeof(int));
int elem1_2 = ary[1 * x + 2];
int elem3_4 = ary[3 * x + 4];
and so on. You better define some macros or access functions. And free the memory after use.
Alternative to the suggestion of #Chris:
You can create 2d array as an array of one-dimensional arrays. This will allow you to do array element indexing as you used to. Be aware that in this case array is allocated in heap, not in stack. Therefore, when you don't need the array anymore, you must clean the allocated memory.
Example:
#include <malloc.h>
#include <string.h>
/* Create dynamic 2-d array of size x*y. */
int** create_array (int x, int y)
{
int i;
int** arr = (int**) malloc(sizeof (int*) * x);
for (i = 0; i < x; i++)
{
arr[i] = (int*) malloc (sizeof (int) * y);
memset (arr[i], 0, sizeof (arr[i]));
}
return arr;
}
/* Deallocate memory. */
void remove_array (int** arr, int x)
{
int i;
for (i = 0; i < x; i++)
free (arr[i]);
free (arr);
}
int main()
{
int x = 5, y = 10;
int i, j;
int** plansza = create_array (x, y); /* Array creation. */
plansza[1][1] = 42; /* Array usage. */
remove_array (plansza, x); /* Array deallocation. */
return 0;
}

Resources