Why can't access multidementianal arrays like single dimentional - c

In C
we have
int B[2][3] = { {1, 2, 3}, {4, 5, 6} };
It is stored in memory as
1 2 3 4 5 6
int A[6]={1,2,3,4,5,6};
It is also stored in memory as
1 2 3 4 5 6
we can access A[6] by A[i] where i=0,2,3..
but we cannot access B[2][3] by B[i ] where i=0,1,2..
I know there are other techniques by which we can access elements of multidimentional arrays
but we cannot access multidimentional arrays like single dimentional arrays why?

You can interpret them:
int B[2][3] = { {1, 2, 3}, {4, 5, 6} };
int* b = ( void* )B ;
for( int i = 0 ; i < 6 ; i++ )
printf("%d " , b[i] ) ;
The same goes for single arrays:
int A[6]={1,2,3,4,5,6};
int (*a)[3] ;
a = ( void* )A ;
for( int i = 0 ; i < 2 ; i++ )
for( int j = 0 ; j < 3 ; j++ )
printf("%d " , a[i][j] ) ;

You can access using another pointer to the array as below,
#include <stdio.h>
int main()
{
int i;
int a[2][3] = {{1,2,3}, {4,5,6}};
int *b = (int *)a;
for (i = 0; i < 6; i++)
printf("%d\n", b[i]);
return 0;
}

It has, amongst others, to do with the types of what you access.
B is a int[2][3]. That means, it has 6× the size of an int and consists of 2 successive int[3].
If you do [i], i being an integer, you get away the first level of indexing. That will give you an expression of type int[3], i. e. an array of 3 ints. That is not the same as an int and needs further indexing.
But there is another solution: dereferencing B with [0] gives you the first array. While this is limited in length, you can use it to access the whole array. So you can achieve your goal with B[0][5].
As said, B is a int[2][3], meaning that it is an array of 2 arrays of 3 ints. In memory, that looks like
offs 0 offs 1 offs 2 offs 3 offs 4 offs 5
B[0][0] B[0][1] B[0][2] B[1][0] B[1][1] B[1][2]
======================= =======================
B[0] B[1]
===============================================
B
B[0] is a 1D-array and as such degrades into a pointer as well. It points to the first element as well, but has a different type. So B[0] is of type int[2] and cannot be used as an int at the same time.
If I consider B[1], it even has a different address. See above how B[1] means the 2nd half of all data. B[0] and B[1] both have 3 times the size of an integer, meaning that the address of B[1] is 3*sizeof int positions away from B[0].
B[0] is, as said, the first array shown above. It degrades into a pointer to its first element (to B[0][0]) under most circumstances. A pointer, OTOH, can be accessed like an array: B[0][0] points to the first element, B[0][1] to the 2nd, and so on.
You are allowed to access the whole big array using this pointer, so you can go up to B[0][5]. Accessing B[0][6] is undefined behaviour in this case, meaning that you access something completely different - or even an area you aren't even allowed to read.
That is how arrays work. Making them work the way you intend to at the same time wouldn't work (how should it?).
If you want to learn more about pointers, have a look at a good C tutorial or book.

Related

2d array pointer used in function

im writting a program in which i want to use this piece of code to transfer a 2d array in a function, but i dont understand fully how it works exactly. Can someone explain it, specifically line 7?
#include <stdio.h>
void print(int *arr, int m, int n)
{
int i, j;
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
printf("%d ", *((arr+i*n) + j));
}
int main()
{
int arr[][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
int m = 3, n = 3;
// We can also use "print(&arr[0][0], m, n);"
print((int *)arr, m, n);
return 0;
}
i also tried using
*( *(p + i) + j)
instead, but it didnt really work and i dont know why so if someone can explain why this didnt work as well i would really appreciate it.
In modern C, you should use Variable Length Array types introduced in C99.
void print(int m, int n, int arr[m][n])
{
int i, j;
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
printf("%d ", arr[i][j]);
}
The function should be called with a simple:
int main()
{
int arr[][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
int m = 3, n = 3;
print(m, n, arr);
return 0;
}
The VLA types are optional feature in C11 but they will be mandatory again in C23.
You pass a 2-dimesional Array to your print function, with the amount of items in the individual arrays and the amount of arrays in the 2D-Array.
Now let us come to the loop:
First of all if i and j are both zero you get the first Item of the first Arrays. In the next Iteration of the inner loop j is 1, thus (arr+i*n) + 1 points to 2 Element of the first Arrays, because i is still zero and j will be 1 ((arr + 0 * 3) + 1). In the next iteration it is the same but i is 2, thus pointing to the second element.
When the inner loop has finished i is increased to 1 and the expression is now (arr + 1 * 3) + 0. So now i * 3 will point to the first element of the second Array.
And in the third iteration of the outer loop i will point to the first element of the third array. So i * 3 is always the pointer to the first element of an array, in this 2D-Array and the + j always points to an individual element in the Array. By combining this the 2D-Array gets printed.
*( *(p + i) + j) Does not work because, assuming p is an pointer to the array arr, because you are dereferencing it, so it in the first iteration it would evaluate to *(1 + 0) which results in a segmentation fault because you are not allowed to read this Memory Adress. This is, because by dereferencing it you are *(p + 0) referring to the first Element of the first Array, which is 1.
In int arr[][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};, 1, 2, and 3 initialize an array of 3 int. An array is a contiguously allocated set of objects, so 1, 2, and 3 are contiguous in memory. 4, 5, and 6 initialize another array of 3 int, and so do 7, 8, and 9. These three arrays of 3 int are themselves another array, an array of 3 arrays of 3 int. Since an array is a contiguously allocated set of objects, the 3 arrays are contiguous in memory. So the 4, 5, and 6 follow the 1, 2, and 3, and the 7, 8, and 9 followed the 4, 5, and 6.
So the overall effect is that 1, 2, 3, 4, 5, 6, 7, 8, and 9 are contiguous and consecutive in memory.
*((arr+i*n) + j) uses this fact to calculate the location of the element in row i and column j. The starting address of the array is arr. i*n is the number of elements from the start to row i. That is, each row has n elements, so i rows have i*n elements. Then j is the number of elements from the start of the row to the element in column j of that row. So arr + i*n + j is where the element in row i, column j is, and *(arr + i*n + j) is that element. The extra parentheses in *((arr+i*n) + j) are unnecessary.
This code abuses the C type model. In main, arr is an array of 3 arrays of 3 int. When main calls print, it passes (int *)arr. This passes a pointer to an int instead of a pointer to an array of 3 int, and then print bypasses the normal application of array types to accessing the memory. Technically, the behavior of this code is not defined by the C standard, but it works in many C implementations.
C is an extremely simple language, it became popular mainly because the simple parts were designed to be combined in ways that replaced complex parts of previous languages (see for as an example). One side effect is that it leaves out parts you expect in other languages.
Specifically for arrays, an array has no information on its size or format, it's assumed that the programmer will keep track of that, or that the size of every dimension but the first is constant (and normally the first one as well). So however many dimensions it's declared as, an array is just a single block of memory large enough to hold all elements, and the location is calculated internally using the [] operator.
Fun fact, C allows you to specify a[1] as 1[a], because it all translates to addition and multiplication. But don't do that.
In the event that you have an array that has variable sizes for more than one dimension, C doesn't support that so you have to do the math yourself, which is what that print() function is doing, where m and n are the sizes of the dimensions. The first row starts at arr (or arr + 0), and goes to arr + (n - 1) (0 to n-1 is n elements), and would look like arr[0][0] to arr[0][n-1] in a language that supported it. The next row starts at arr + n (would be arr[1][0]) to arr + (2 * n) - 1, and so on (up to what would be arr[m-1][n-1]).
In the function here, i and j go from 0 to m-1 and n-1 respectively, so you don't see - 1 in the code.
One more thing, C is at least helpful enough to know when you use + on a pointer, you mean to increment by the size of the thing you're pointing to, so you don't have to figure out how many bytes in a int.

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.

I am not sure how the array of the code is being traced?

I don't understand how the array is being traced. I feel like I know it but then I mess it up again. I get how the values are being swapped but I am still getting confused. I wrote my questions as comments besides my code. Can someone help me trace that part?
#include <stdio.h>
int main()
{
int a[5]={1,2,3,4,5};
int i,j,temp;
for (j=1; j<5; j++)
for (i=0; i<5-j; i=i+2)
{
printf("%d %d\n",i,i+j); //I got this part right
temp = a[i]; //from here I get confused
a[i] = a[i+j]; //how is the addition inside working??
a[i+j] = temp; //temp = the index's value
}
for (i=0; i<5; i++)
printf("a[%d] = %d\n",i,a[i]);//what is i supposed to be here??
}
Output:
0 1
2 3
0 2
2 4
0 3
0 4
a[0] = 2 //from here on I get lost
a[1] = 1
a[2] = 5
a[3] = 4
a[4] = 3
Why don't you print your whole array in every loop, that way you can see how values are moving, for example in step in you swap 0,1 element so array is {2,1,3,4,5}, then 2,3 so {2,1,4,3,5}, then 0,2 so {4,1,2,3,5} , 2,4,=> {4,1,5,3,2}, 0,3 {3,1,5,4,2},0 4 {2,1,5,4,3}
I am guessing you don't know much about C programming. So here is a bit about arrays:
An array (here: int a[5]={1,2,3,4,5}) is contiguously allocated blocks of memory.
An array a[n] is of size 'n'(stores n values of array type, here int) and is index from 0 to n-1. Meaning each of the n values are accessed from a[0] to a[n-1].
There are multi-dimensional arrays (read it up!).
The logic given here:
temp = a[i]; //temp gets a[i]'s value and not the value of i
a[i] = a[i+j];
a[i+j] = temp;
This is the standard swap(a,b) operation using a temporary variable temp. Just that 'a' and 'b' here are elements of an array.
The loops are designed in such a way to access different elements of the array in each iteration. This shuffles the array.
So obviously:
printf("a[%d] = %d\n",i,a[i]); // i here is the index used to access a's ith element
I found out what I was doing wrong. I was simply trying to do the math and change that position's value. I have to open up space and move the old number out to put the new number in. Then the old number will go to empty space that's left. It's actually just simply swapping but it helps to see it this way better.
So in {1,2,3,4,5}, if I try to put a[3]=4 in a[1]=2, the value 4 will go to a[1].
a[1] which had 2 will have to get out and a[3] which had 4 will move in.
The 2 that was out will go in the place where 4 was before in a[3]=2.
So now a[1]=4 and a[3]=2.
So the swapped array will now look like {1,4,3,2,5}

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.

How to set array of pointers to arrays correctly in C?

Let's say I have defined these 3 arrays:
int[][3] arr0 = {
{1,2,3},
{4,5,6}
};
int[][3] arr1 = {
{10,20,30},
{40,50,60},
{70,80,90}
};
int[][3] arr2 = {
{100,200,300},
{400,500,600},
{700,800,900},
{1000,1100,1200}
};
Now I want to make an array of pointers leading to these arrays, something like:
// pseudo code example
arrays[] = {
arr0,
arr1,
arr2
};
Because I then want to get the k-th value from the j-th sub-array of variable "arrayN" this way:
// pseudo code example
int value = arrays[N][j][k];
For example: N is 2, j is 1 and k is 0, the target array is arr2, so the value should be 400.
How can I write this code correctly in C? I tried many ways and none worked.
Pointers to array won't work as you want.
To archive what you want, I think using array of pointer to int[3] is good.
#include <stdio.h>
int main(void) {
int N = 2, j = 1, k = 0;
int arr0[][3] = { {1,2,3}, {4,5,6} };
int arr1[][3] = { {10,20,30}, {40,50,60}, {70,80,90} };
int arr2[][3] = { {100,200,300}, {400,500,600}, {700,800,900}, {1000,1100,1200} };
int (*arrays[])[3]={arr0,arr1,arr2};
int value = arrays[N][j][k];
printf("%d\n",value);
return 0;
}
You can do it like this:
int (*arr[])[3] = {arr0, arr1, arr2};
for (int i = 0 ; i != 3 ; i++) {
for (int j = 0 ; j != i+2 ; j++) {
printf("%d %d %d\n", arr[i][j][0], arr[i][j][1], arr[i][j][2]);
}
}
which prints
1 2 3
4 5 6
10 20 30
40 50 60
70 80 90
100 200 300
400 500 600
700 800 900
1000 1100 1200
The key to the solution is this declaration:
int (*arr[])[3]
It means "declare arr to be an array of pointers to arrays of three integers".
Demo.
There's some problems with this approach. The empty dimension [] means "allocate an array as large as there are items in the initializer list". And the only thing the compiler cares about in the initializer list is the number of {} pairs, because each such brace pair will be an array initializer.
Since you specified the inner most dimension to [3], it will try to create as many arrays of length [3] as there are brace pairs. In the first example there are 2 brace pairs, so 2 arrays will be needed. The type of arr0 will therefore be int [2][3].
Same applies to the other arrays, which will get different types: int [3][3] and int [4][3] respectively.
So you have 3 different types. You cannot make an array of these 3 different types no more than you can make an array out of lets say 1 char, 1 int and 1 float.
There are a couple of solutions. Either you don't care about memory allocated nor variable array lengths. Then you can set both dimensions to fixed size. With all arrays of type int [4][3] you can then declare an array of such arrays.
Or alternatively you can make an array of pointers, each pointing at the first item in each array:
int* arr_list = {arr0, arr1, arr2};
With either of these solutions, you'll be able to access the items as [x][y][z].

Resources