Pointer arithmetic with 2D arrays in C - c

I need help understanding how to use point arithmetic for 2D arrays in C. I'm using this website (http://www.geeksforgeeks.org/dynamically-allocate-2d-array-c/) as a reference (using example 1, a single pointer).
int numRows = 2;
int numColumns = 3;
double * arrayMatrix = malloc(numRows * numColumns * sizeof(double));
int row = 0;
int column = 0;
printf("\nPlease enter the elements of your augmented matrix:\n");
for(row = 0; row < numRows; row++)
{
for(column = 0; column < numColumns; column++)
{
printf("A[%d][%d]:", row + 1, column + 1);
scanf("%lf", &arrayElement);
printf("\n");
*(arrayMatrix + row * numColumns + column) = arrayElement;
//arrayMatrix[row + numColumns + column] = arrayElement;
}
}
// TEST PRINT
for(row = 0; row < numRows; row++)
{
for(column = 0; column < numColumns; column++)
{
printf("%5.2lf", *(arrayMatrix + row * numColumns + column));
//printf("%5.2lf", arrayMatrix[row + numColumns + column]);
}
printf("\n");
}
I need help understanding if this is a correct way to input data into a 2D array and if it is also a correct way to print data from a 2D array. I'm using the example data of for row 1 as {1, 2, 3} and row 2 as {1, 2, 3}; however when printing out the information all I get are 0 for all 6 elements.
I also used this answer as reference (How to use pointer expressions to access elements of a two-dimensional array in C?). Specifically following this line:
int x = *((int *)y + 2 * NUMBER_OF_COLUMNS + 2); // Right!
But I'm using a double pointer instead of an integer, but I don't know if that is causing my issues or if it is something else.
Edit - Updated the code a little but it is still not working at all.
Edit 2: This is the most recent update with the code that I've been trying to get to work. All 3 ways of inputting and printing data from the array result in the same result (0's for all values in the array).
int numRows = 2;
int numColumns = 3;
//double * arrayMatrix = malloc(numRows * numColumns * sizeof(double));
double (*arrayMatrix)[numColumns] = malloc(sizeof(double[numRows][numColumns]));
int row = 0;
int column = 0;
printf("\nPlease enter the elements of your augmented matrix:\n");
for(row = 0; row < numRows; row++)
{
for(column = 0; column < numColumns; column++)
{
printf("A[%d][%d]:", row + 1, column + 1);
scanf("%lf", &arrayElement);
printf("\n");
//*(arrayMatrix + row * numColumns + column) = arrayElement;
//arrayMatrix[row + numColumns + column] = arrayElement;
arrayMatrix[row][column] = arrayElement;
}
}
// TEST PRINT
for(row = 0; row < numRows; row++)
{
for(column = 0; column < numColumns; column++)
{
//printf("%5.2lf", *(arrayMatrix + row * numColumns + column));
//printf("%5.2lf", arrayMatrix[row + numColumns + column]);
printf("%5.2lf", arrayMatrix[row][column]);
}
printf("\n");
}

I think I understand what you are wanting to do. Before we talk code, let's back up and bit and learn a little about the different ways a 2D array can be simulated in C. You have 2 basic approaches. You can statically or dynamically declared an array array[row][col] = {{r0c0, r0c1, r0c2, ...}, {r1c0, r1c1, r1c2, ...} ... }; which will create a single block of memory, with the values stored sequentially r0c0, r0c1, r0c2, ..., r1c0, r1c1, r1c2, ...., or you can create row number of pointers with each pointing to an individual array of col elements. The second method (the row number of pointers each pointing to arrays of col elements) need not be sequential in memory. It can be, but there is no requirement that it is.
The array index notation array[i][j] will take care of handling the offset within a sequential block of memory to provide access to any individual element. The same holds true for access to any element of within the individual col sizes array pointed to by array[i]. But what is actually happening?
Let's look at the notation of a simple 4-element array, say array[4]. To access any element, you could request any element array[0] to array[3] to access all 4 elements. What is array[2] really? You know array is also a pointer. You know that to access the value at the address held by the pointer you need to dereference the pointer. To access array[0], you could simply write *array, but how would you access the 2nd element with pointer notation?
As we discussed earlier, all the elements in an array declared as we have declared this example are stored sequentially in memory. So, to access any element in the array, all you need is the offset from the beginning of the array. Since you know the beginning address of the array is just array, if you wanted the 2nd element, you would need to access the element offset 1 from the beginning, or at *(array + 1) -- try it. In fact you can access all elements at offsets 0-3 from the beginning with *(array + i) where i is a number in 0-3.
Looking back a bit, that also explains why you can access the 1st element in an array by simply using *array. If you wrote the full syntax for the first element you would have *(array + 0) -- and you know the + 0 is doing nothing so that is why you can access the 1st element with *array because *(array + 0) = *array.
OK, what about the 2D case? If array[x] is *(array + x), what is array[x][y]? Break it down. You know you can write array[x] as *(array + x), so array[x][y] can be written *(array + x)[y] (and if we substitute stuff for *(array + x) for the moment, we can write stuff[y]. We know how to write that in pointer notation: *(stuff + y), right? Now just substitute *(array + x) for stuff and you get *(*(array + x) + y). That is your full pointer notation for accessing any element within a sequential block of memory in a simulated 2D array manner and that is what is happening behind the scene when you write array[x][y].
Now let's talk pointer arithmetic. When you declare a pointer, you are declaring a pointer to a specific type (except in the case of void). That type tells the compiler how to handle the arithmetic with that pointer. For example, if you declare:
char array[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
char *p = array;
The compiler knows that each char occupies 1-byte of memory, so when you write *(p + 1), you are asking for the char value 1-byte from the beginning of array. The same holds true if you write p++; then *p. But what happens with:
int array[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
int *p = array;
By virtue of knowing the type is int and that an int is 4-bytes (platform dependent), when you write *(p + 1) or p++; *p;, you will get the 2nd element in the array, but the value is 4-bytes from the beginning of the array. The type tells the compiler how to handle pointer arithmetic (i.e. the offset) for any given value.
You can cement that for yourself with a minimal example:
#include <stdio.h>
#define ROWS 2
#define COLS 2
int main (void) {
int a[ROWS][COLS] = {{ 1, 2 }, { 3, 4 }};
int *p = *a;
int i, j;
for (i = 0; i < ROWS; i++) {
for (j = 0; j < COLS; j++)
printf (" %2d", a[i][j]);
putchar ('\n');
}
/* using a pointer to access the values */
for (i = 0; i < ROWS * COLS; p++, i++)
printf (" %2d", *p);
putchar ('\n');
return 0;
}
Output
$ ./bin/array_min
1 2
3 4
1 2 3 4
Now on to what you actually asked about. Given all we have discussed, what are you declaring when you declare:
double (*arrayMatrix)[NCOLS] = calloc (NROWS, NCOLS * sizeof **arrayMatrix);
You are declaring and allocating space for a pointer to what? A pointer to an array of doubles with NCOLS elements. How many of those do you need to hold the complete array? You will need NROWS number of pointers to arrays holding NCOLS elements each. Note above the use of calloc instead of malloc. There is an important, but subtle difference, in both the syntax and what they do. malloc will allocate memory for you, but that memory is uninitialized and can contain all manner of stuff. calloc also allocates, but then initializes the memory to zero. Which when dealing with numeric arrays is useful to prevent the accidental access of an uninitialized element (resulting in undefined behavior). There is a marginal speed difference between malloc and calloc as the result, but you will be hard pressed to find a measurable difference in anything less than a few million allocations.
With that background, consider again what you are trying to do. With very few tweaks, you would have it make more sense if you did something like:
#include <stdio.h>
#include <stdlib.h>
#define NROWS 2
#define NCOLS 3
int main (void) {
size_t row = 0;
size_t col = 0;
/* allocate NROWS (array of pointers to NCOLS doubles). using
* calloc will allocate and initialize all elements to zero.
*/
double (*arrayMatrix)[NCOLS] = calloc (NROWS, NCOLS * sizeof **arrayMatrix);
/* prompt user for input, validate a proper value is entered */
printf("\nPlease enter the elements of your augmented matrix:\n");
for(row = 0; row < NROWS; row++)
{
for(col = 0; col < NCOLS; col++)
{
while (printf(" A[%zu][%zu]: ", row + 1, col + 1) &&
scanf("%lf", &arrayMatrix[row][col]) != 1)
printf("\n");
}
}
/* printf the array of pointers */
printf ("\n The matrix entered was:\n\n");
for(row = 0; row < NROWS; row++)
{
for(col = 0; col < NCOLS; col++)
{
printf(" %5.2lf", arrayMatrix[row][col]);
}
printf("\n");
}
free (arrayMatrix);
return 0;
}
Output
$ ./bin/arraymatrix
Please enter the elements of your augmented matrix:
A[1][1]: 1
A[1][2]: 2
A[1][3]: 3
A[2][1]: 4
A[2][2]: 5
A[2][3]: 6
The matrix entered was:
1.00 2.00 3.00
4.00 5.00 6.00
Memory Error/Leak Check
In any code your write that dynamically allocates memory, you have 2 responsibilites regarding any block of memory allocated: (1) always preserves a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed. It is imperative that you use a memory error checking program to insure you haven't written beyond/outside your allocated block of memory and to confirm that you have freed all the memory you have allocated. For Linux valgrind is the normal choice. There are so many subtle ways to misuse a block of memory that can cause real problems, there is no excuse not to do it. There are similar memory checkers for every platform. They are all simple to use. Just run your program through it.
$ valgrind ./bin/arraymatrix
==17256== Memcheck, a memory error detector
==17256== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==17256== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==17256== Command: ./bin/arraymatrix
==17256==
Please enter the elements of your augmented matrix:
A[1][1]: 1
A[1][2]: 2
A[1][3]: 3
A[2][1]: 4
A[2][2]: 5
A[2][3]: 6
The matrix entered was:
1.00 2.00 3.00
4.00 5.00 6.00
==17256==
==17256== HEAP SUMMARY:
==17256== in use at exit: 0 bytes in 0 blocks
==17256== total heap usage: 1 allocs, 1 frees, 48 bytes allocated
==17256==
==17256== All heap blocks were freed -- no leaks are possible
==17256==
==17256== For counts of detected and suppressed errors, rerun with: -v
==17256== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
Let me know if you have further questions. My fingers are tired. This ended up much longer than I anticipated...

Here is a function that will allocate a contiguous 2d array of doubles:
double* alloc_array_2d(int Width, int Height){
return (double*)malloc(Width * Height * sizeof(double));
}
Here is a function that will get a pointer to an element of the array based on an x and y coordinate:
double* get_element_2d(double* Array, int Width, int X, int Y){
int index = (Width * Y) + X;
return Array[index];
}
With this method a 5 x 3 array could be imagined to look like this:
0 1 2 3 4
5 6 7 8 9
10 11 12 13 14
In computer memory it actually looks like this:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
The basic idea is that the beginning of one row of values sits beside the end of the previous row of values, so by multiplying the width of the array by the vertical coordinate you offset the index into the correct row. For example to access the third object in the second row (7) we call
get_element_2d(myArray, 5, 2, 1); // 1 * 5 + 2 = 7
Note that each of the coordinates starts at zero just like with all pointer arithmetic, so to access an element in the first row you would use get_element_2d(Array, Width, X, 0)

Your first code sample looks correct, if you had double arrayElement; earlier.
However, if perhaps you had it as int arrayElement; or some other data type instead, it would explain what you are seeing, because %lf can only be used with double.
Modern compilers are able to give a warning for this problem, so you could investigate which compiler switches you are using to make sure you are getting the maximum possible warning level.
To avoid this error you could scan directly into the array:
scanf("%lf", &arrayMatrix[row * numColumns + column]);
NB. You seem to have got alternative variations of each line that accesses the array, where you change from pointer notation to index notation. Generally speaking, index notation is considered easier to read and therefore preferable.

Related

Why is the Index NOT out of bounds although it intuitively should?

I'm relatively new to C programming and I stumbled upon a for me unexplainable behaviour while running the following code and debugging it using gdb and lldb.
In short: When swapping the indices i and j (max i != max j) when accessing a value in a two-dimensional Array inside a double nested for-loop it does not seem to matter if I access the value using array[i][j] or array[j][i].
The two loops and arrays are mostly identical.
unsigned matrix[3][1] =
{
{3},
{4},
{5}
};
//Loop1
for (size_t i = 0; i < sizeof(matrix) / sizeof(*matrix); i++)
{
for (size_t j = 0; j < sizeof(matrix[i]) / sizeof(*matrix[i]); j++)
{
matrix[i][j] <<= 1;
printf("matrix[%zu][%zu] has the value: %d\n", i, j, matrix[i][j]);
}
}
//same two dimensional array as matrix
unsigned matrix2[3][1] =
{
{3},
{4},
{5}
};
//Loop2, basically the same loop as Loop1
for (size_t i = 0; i < sizeof(matrix2) / sizeof(*matrix2); i++)
{
for (size_t j = 0; j < sizeof(matrix2[i]) / sizeof(*matrix2[i]); j++)
{
//swapped i and j here
matrix2[j][i] <<= 1;
printf("matrix2[%zu][%zu] has the value: %d\n", j, i, matrix2[j][i]);
}
}
Am I missing here something?
In both cases i is passed the value 2 at the end of the outer loop and j the value 0 at the end of the inner loop.
Intuitively, matrix[0][2] should throw an exception as each row only has one element.
I will take a slightly different approach than the other respondents.
You are technically not reading outside of the array's boundary as far as the memory layout is concerned. Looking at it from a human perspective you are (the index [0][2] doesn't exist!), but the memory layout of the array is contiguous. Each of the "rows" of the matrix are stored next to each other.
In memory, your array is stored as: | ? | 3 | 4 | 5 | ? |
So when you index to matrix[1][0] or matrix [0][1] you are accessing the same position in memory. This would not be the case if your array was larger than 1 dimension wide.
For example, replace your array with the following one and experiment. You can access integer '4' either by indexing matrix[0][2], or matrix [1][0]. The position [0][2] shouldn't exist, but it does because the memory is contiguous.
unsigned matrix[3][2] =
{
{3, 6},
{4, 8},
{5, 10}
};
Oops, matrix[0][2] should throw an exception as each row only has one element...
Some languages do warn the programmer by an exception if they try an out of bound access, but C does not. It just invokes Undefined Behaviour. On a technical point of view, it means that the compiler does not have to test the out of bound condition. On an operational point of view, it means that anything can happen, including expected behaviour... or an immediate crash... or a modification of an unrelated variable... or...
If my C skills aren't mega-rusty you're reading "unsafe memory".
Essentially your matrix is declared as a block of bytes. After that block of bytes there are more bytes. What are they? Usually more variables that are declared as your program's data. Once you reach the end of the program's data block you reach the user code memory block (encoded ASM instructions).
Most languages perform checks and throw an exception when you run out of bounds by somehow keeping track of the last index that is valid to access. C does not do that and doing such thing is your very own responsibility. If you aren't careful you might be overwriting important parts of your program's code.
There are attacks that one can perform on C programs that don't sanitize user input, like a buffer overrun; which exploits what it's been described.
Essentially if you declare a char[] of length N and store a string that comes from outside and this string happens to be of length N+X you'll be overwriting program memory (instructions).
With the right sequence of characters you can inject your very own assembly code into a running program which doesn't sanitize user input
As your array is int and all elements are of the same size, i don't see any problem as your array is stored in contiguous space in RAM and you use a special case of matrix where inverting indexes has no side effect.
In the first loop your indexes are [0][0], [1][0], [2][0]
In the second loop your indexes are [0][0], [0][1], [0][2]
now try to linear the access, as your array is saved as linear array into the RAM.
address of element = row * NCOL + col
row: is row number
NCOL: number of columns into your matrix
col : the column number
so the linear index for :
[0][2] ==> 0 * 1 + 2 = 2 /* the third element*/
[2][0] ==> 2 * 1 + 0 = 2 /* always the third element */
But if you use a matrix of n x m , n >= 1 and m > 1 and n != m.
if you inverse the indexes, the result will not be the same.
so if you take a 4 x 2 matrix
linear index of [3][1] = 3 * 2 + 1 = 7
linear index of [1][3] = 1 * 2 + 3 = 5 /* even [1][3] is out of the range of your matrix index */
[1][3] you will manipulate the element [2][1]
So be worry when manipulating matrix indexes.

Malloc not needed to create inner array [duplicate]

This question already has answers here:
using unallocated memory without error?
(5 answers)
Closed 6 years ago.
I am trying to fully wrap my mind around malloc and memory allocation. I recently came across a situation that made me raise a brow.
When fiddling with arrays I was creating an array of arrays. Which in my mind would look something like this:
[[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], ...]
When doing this I figured since I needed malloc to create the outer array. I also needed to call malloc for each inner array that I was creating. I quickly realized I get the same output when I skip this step which makes no sense to me.
Consider the following script.
int main(int argv, char* argc[]){
// initialize outer array
int* outer = malloc(5 * sizeof(int));
int i, j;
// for each slot in outer array
// create a new array and assign it
// to that slot.
// NOT NEEDED.
for(i = 0; i < 5; i++){
int* inner = malloc(5 * sizeof(int));
*(outer + i) = *inner;
}
// If I comment out the above four lines
// the output remains the same.
// assign to each slot in each inner array
for(i = 0; i < 5; i++)
for(j = 0; j < 5; j++)
*(outer + i * 5 + j) = j;
// print each element in each inner array
for(i = 0; i < 5; i++){
for(j = 0; j < 5; j++){
printf(
"%d ",
*(outer + i * 5 + j)
);
}
puts("");
}
}
The output from this script is as follows:
0 1 2 3 4
0 1 2 3 4
0 1 2 3 4
0 1 2 3 4
0 1 2 3 4
Which is what I expected. But when I comment out the first for loop in the script I get the same output. Why is this? Do I not need to allocate memory for the inner arrays? Clearly the answer is no but I'm trying to understand why that is.
Short answer: Undefined behavior.
When you fail to allocate memory for the inner arrays, the pointers are uninitialized, so they point to some unspecified memory location.
With undefined behavior, your program may crash, it may behave in some unexpected manner or it may (as in your case) appear to work properly. A seemingly unrelated change such as adding unused variables can cause the programs behavior to change.

Copying matrix from .txt into array

I have a task to read matrix from .txt file and then make an 2D array in C. I read numbers well but I have a problem with writing these numbers into array because I need to allocate memory because im not sure how big the matrix will be.
int read()
{
FILE *f;
int number, i, j, size;
f = fopen("matrix.txt","r");
if (f == NULL)
{
printf("Error reading matrix.txt\n");
return 1;
}
printf("Sucess! \n");
fscanf(f, "%d",&size);
printf("Size of matrix: %d\n", size,size);
int* matrix;
matrix = malloc(size * sizeof(int));
for(; feof(f) == 0;)
{
for(i = 0; i < size; i++)
{
for(j = 0; j < size; j++)
{
fscanf(f,"%i",&number);
// *(*(matrix+j)+i) = number;
printf("%i\t",number);
}
printf("\n");
}
}
fclose(f);
To my understanding, matrix is of type int* and you intend to store size*size elements read from the file into it. First of all, you should allocate memory for size*size times the size of int, which can be done as follows.
matrix = malloc(size * size * sizeof(int));
Next, as you iterate via i and j over the matrix entries which are read from the file, you need to do a proper address calculation. As matrix is of type int*, this can be done as follows.
matrix[ i * ( size - 1 ) + j ] = number;
That being said, perhaps it would be better to have matrix of type int** and allocate space for the rows manually. By doing so, you could do the access to the elements by
matrix[ i ][ j ] = number;
which is perhaps more intuitive.
You can do :
matrix[(size-1)*i+j]=number
To fill the array, that is the usual way to simulate 2D arrays in C, to understand from where did (size-1)*i+j come from notice this example :
1 2 3
4 5 6
7 8 9
the result array is : 1 2 3 4 5 6 7 8 9.
So when we begin in the first row and first column, in the result array 1 is the first element so its index is zero.
When we advance one row(from 1 to 4) we advance three positions in the result array so the index is 3.
Now if we begin with column 1(second column) and the first row we have 2 which has index 1 in the result array, if we advance one row(from 2 to 5) we also advance 3 positions and the index is 4.
Notice that 3 is actually the size of matrix and I think you can verify that i*(size-1)+j is working, the size-1 is like this because C arrays are zero-based.
Note
If your file only has one matrix, I recommend you to get rid of the outermost loop , a simple mistake(like a new line after the matrix or space) will cause a call to fscanf(f,"%i",&number) without finding a number(I'm not sure what will happen then).
Also you should allocate size*size of ints.

2-D matrices using malloc failing to assign correct values

sorry, I'm relatively new to c and am trying to create two 2-D arrays using malloc. I was told that this method is computationally more efficient than creating a pointer array of arrays through a for loop (for large arrays).
int i, j;
double **PNow, **PNext, *Array2D1, *Array2D2;
//Allocate memory
PNow = (double**)malloc(3 * sizeof(double*));
PNext = (double**)malloc(3 * sizeof(double*));
Array2D1 = (double*)malloc(5 * sizeof(double));
Array2D2 = (double*)malloc(5 * sizeof(double));
//Create 2-Dimensionality
for(i = 0; i < 3; i++)
{
PNow[i] = Array2D1 + i * 5;
PNext[i] = Array2D2 + i * 5;
};
//Define Element Values
for(i = 0; i < 3; i++)
{
for(j = 0; j < 5; j++)
{
PNow[i][j] = 10.*(i + j);
PNext[i][j] = 1000.*(i + j);
};
};
//Output two matrices side-by-side.
for(i = 0; i < 3; i++)
{
for(j = 0; j < 5; j++)
{
printf("%6lg", PNow[i][j]);
if(j == 4)
{
printf("|");
};
};
for(j = 0; j < 5; j++)
{
printf("%6lg", PNext[i][j]);
if(j == 4)
{
printf("\n");
};
};
};
My problem is that the first matrix (PNow) turns out as I would expect, but for some reason half of the values in PNext are those of PNow, and I can't for the life of me figure out why it is doing this? I'm obviously missing something.. Also I am not overly clear on what "Array2D1 + i*5" is doing and how this makes PNow a 2-D array?
Any help would be really appreciated.
Thank you.
P.S. This is the output that I am getting, so you can see what I mean:
0 10 20 30 40| 20 30 40 50 20
10 20 30 40 50| 30 40 50 60 5000
20 30 40 50 60| 2000 3000 4000 5000 6000
In C you don't cast the result of mallocs, so your malloc lines should read
PNow = malloc(3*sizeof(double*));
Your problem is you're not actually allocating enough memory in Array2D1 and Array2D2. When you move past the first "row" in your array you're getting beyond your allocated memory! So you're in undefined behavior territory. In your case, it looks like your two matrices step all over each other (though my test just throws an error). You can solve this in two ways:
Specify the full size of your matrix in the malloc and do as you did:
Array2D1 = malloc(15*sizeof(double));
Array2D2 = malloc(15*sizeof(double));
Or malloc each line in your for loop:
for(i=0; i<3; i++){
PNow[i] = malloc(5*sizeof(double));
PNext[i] = malloc(5*sizeof(double));
}
Edit: On the topic of freeing in each example
For the first example, the freeing is straight forward
free(PNow);
free(PNext);
free(Array2D1);
free(Array2D2);
For the second, you must iterate through each line and free individually
for (i = 0; i < 3; i++) {
free(PNow[i]);
free(PNext[i]);
}
Edit2: Realistically, if you're going to hardcode your rows and columns in with a pre-processor macro, there's no reason to malloc at all. You can simply do this:
#define ROW 3
#define COL 5
double PNow[ROW][COL], PNext[ROW][COL];
Edit3: As for what Array2D1 + i * 5 is doing, PNow is an array of pointers, and Array2D1 is a pointer. By adding i * 5 you're incrementing the pointer by i * 5 (i.e., saying "give me a pointer to the memory that is i * 5 doubles away from Array2D1). So, you're filling PNow with pointers to the starts of appropriately sized memory chunks for your rows.
You code does not have 2D arrays, aka matrices. And your pointers cannot point to such an object either.
A proper pointer which can point to a 2D array would be declared like:
#define ROWS 4
#define COLS 5
double (*arr)[COLS];
Allocation is straight-forward:
arr = malloc(sizeof(*arr) * ROWS);
And deleting similar:
free(arr);
Indexing is like:
arr[row][col]
Notice the identical syntax only. The semantics are different.
Nothing more necessary and no need for hand-crafted pointer arrays.
The code above shows another important rule: Don't use magic values. Use constant-like macros instead. These should be #defined at the beginning or in a configuration-section of the code (typically somewhere near the top of the file or a distinct header file). So if you lateron change e.g. the length of a dimension, you don't have to edit all places you explicitly wrote it, but only change the macro once.
While the code above uses constants, you can as well use variables for the dimensions. This is standard C and called variable length array (VLA). If you pass the arrays to other functions, you have to pass them as additional arguments:
void f(size_t rows, size_t cols, double a[rows][cols]);
Remember array-arguments decay to pointers to the first element, so a is actually the same as arr above. The outermost dimension can be omitted, but as you need it anyway it is good for documentation to specify it, too.

How to free the final element of a malloc'd array in C?

Say I initialize an array of 5 integer elements like this:
int *Q = malloc(sizeof(int) * 5);
for (int i = 0; i < 5; i++) {
Q[i] = i;
}
The array looks like: {0, 1, 2, 3, 4}.
Now if I shift everything along by 1 position:
Q++;
The array looks like: {1, 2, 3, 4, #}, where # is some garbage value.
Is there a way to free the final element so it's not stored in the array?
I tried this:
free(Q[4]);
But I know this won't work because free() can only operate of the whole chunk of memory allocated for Q.
Is there a better way to shift everything along? The resulting array should look like: {1, 2, 3, 4}.
Would it be a good idea to realloc() Q after every shift?
realloc() can change the size of an allocated chunk of memory, which will do the job for you. Note that this cannot be used to "free" arbitrary elements of an array, but only one(s) on the end.
How good an idea it is to do this depends on a number of factors, none of which you have provided.
When you do Q++ the array has not changed, it still contains the five values 0,1,2,3,4 it is just that Q is pointing to the second element in the array.
If you want to change the size of allocated memory then do as Scott said and realloc the block - but it is a costly way of handling heap memory.
If you just want to keep track of the number of elements in the array let Q remain pointing on the first element and have a size variable indicating how many integers there are.
Alternatively use another data structure to hold your integers e.g. a linked list of integers, then you can add and remove integers easier.
Taliking about last elements of array you can surely use realloc
BTW take note that when you say
The array looks like: {1, 2, 3, 4, #}, where # is some garbage value.
You are wrong and you are invoking undefined behavior as well explained by this SO answer.
So the loop that left shift value have not to do Q[4] = Q[5];
To shift around elements inside an array one can use memmove().
#include <stdio.h>
#include <string.h>
int main(void)
{
int d_init[] = {0, 1, 2, 3, 4};
size_t s = sizeof d_init/sizeof *d_init;
int d[s];
/* Fill d */
memcpy(d, d_init, s * sizeof *d);
for (size_t i = 0; i < s; ++i)
printf("%d ", d[i]);
puts("\n");
/* shift one to the left */
memmove(d, d + 1, (s - 1) * sizeof *d);
for (size_t i = 0; i < s; ++i)
printf("%d ", d[i]);
puts("\n");
/* shift two to the right */
memmove(d + 2, d, (s - 2) * sizeof *d);
for (size_t i = 0; i < s; ++i)
printf("%d ", d[i]);
puts("\n");
}
The snippet above would print:
0 1 2 3 4
1 2 3 4 4
1 2 1 2 3
If you're doing a Q++ you've not shifted the elements of the array, your array is simply pointing to the second element (index 1). Thus, Q[4] is reading something that doesn't belong to the array: C is permissive enough to let you do that (in most cases), but it is a mistake.
To shift elements you should either do
for (int i=0; i<4; i++)
Q[i] = Q[i+1];
or (smarter)
memmove(Q, Q+1, 4*sizeof(int));
but indeed, to have an array of size 4 you'll have to realloc.
BUT if you need to do that, maybe an array is not the data structure you should use: a linked list seems to be a better choice.

Resources