2d array pointer used in function - arrays

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.

Related

Cout prints incorrect values of Bidimensional int array, while code appears to be correct

Following code appears to be correct, yet it will print incorrect numbers, which are random each time! I literally copied it from C++ site and cross checked it to confirm the code is correct! And it still doesn't work!
#include <iostream>
int main()
{
int a[3][4] = {
{0, 1, 2, 3} , /* initializers for row indexed by 0 */
{4, 5, 6, 7} , /* initializers for row indexed by 1 */
{8, 9, 10, 11} /* initializers for row indexed by 2 */
};
std::cout << a[3][4];
}
When you initialize arrays in c++, the number passed into each bracket is the size of the array, however this is the upper bound, which is not actually an index, its the limit. if your index starts at 0, and you have 3 items in the arrray, then your last row would be 2. This is why c++ loops over the array are always
for(int i =0; i < array_size; i++)
With an emphisis on < and not <=.
In your code, your indexing an item out of bounds; since a[3][4] is technically the 4th col 5th row.
C++ will let you index out of bounds, and your actually just indexing random values out in memory, which isn't good.
Try printing a[2][3] and that should be what your expecting.

How to insert an element starting the iteration from the beginning of the array in c?

I have seen insertion of element in array starting iteration from the rear end. But i wonder if it is possible to insert from the front
I finally figured out a way, Here goes the code
#include <stdio.h>
int main()
{
int number = 5; //element to be inserted
int array[10] = {1, 2, 3, 4, 6, 7, 8, 9};
int ele, temp;
int pos = 4; // position to insert
printf("Array before insertion:\n");
for (int i = 0; i < 10; i++)
{
printf("%d ", array[i]);
}
puts("");
for (int i = pos; i < 10; i++)
{
if (i == pos) // first element
{
ele = array[i + 1];
array[i + 1] = array[i];
}
else // rest of the elements
{
temp = array[i + 1];
array[i + 1] = ele;
ele = temp;
}
}
array[pos] = number; // element to be inserted
printf("Array after insertion:\n");
for (int i = 0; i < 10; i++)
{
printf("%d ", array[i]);
}
return 0;
}
The output looks like:
Array before insertion:
1 2 3 4 6 7 8 9 0 0
Array after insertion:
1 2 3 4 5 6 7 8 9 0
In C the arrays have a "native" built-in implementation based upon the address (aka pointer) to the first element and a the [] operator for element addressing.
Once an array has been allocated, its actual size is not automatically handled or checked: the code needs to make sure boundaries are not trespassed.
Moreover, in C there is no default (aka empty) value for any variable, there included arrays and array element.
Still, in C there's no such a thing like insertion, appending or removal of an array element. You can simply refer to the n-th (with n starting at 0) array element by using the [] operator.
So, if you have an array, you cannot insert a new item at its n-th position. You can only read or (over)write any of its items.
Any other operation, like inserting or removing, requires ad-hoc code which basically boils down to shifting the arrays elements forward (for making room for insertion) or backward (for removing one).
This is the C-language nature and should not be seen as a limitation: any other language allowing for those array operations must have a lower-level hidden implementation or a non-trivial data structure to implement the arrays.
This means, in C, that while keeping the memory usage to a bare minimum, those array operations require some time-consuming implementation, like the item-shifting one.
You can then trade-off the memory usage against the time usage and get some gains in overall efficiency by using, for example, single- and double-linked lists. You loose some memory for link pointer(s) in favor of faster insertion ad removal operations. This depends mostly upon the implementation goals.
Finally, to get to the original question, an actual answer requires some extra details about the memory vs time trade off that can be done to achieve the goal.
The solution depicted by #Krishna Acharya is a simple shift-based solution with no boundary check. A very simple and somehow naive implementation.
A final note. The 0s shown by Krishna's code at the end of the arrays should be considered merely random values. As I said earlier, there is no default value.
The code should have been instead:
int array[10] = {1, 2, 3, 4, 6, 7, 8, 9, 0, 0};
in order to make sure that any unused value was 0 for the last two array elements.

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.

Subscripted arrays in C

Is it possible to create a subscripted array in C which uses another array as its indexes. I went through a link: IDL — Using Arrays as Subscripts
Arrays can be used as subscripts to other arrays. Each element in the subscript array selects an element in the subscripted array.
For another example, consider the statements:
A = [6, 5, 1, 8, 4, 3]
B = [0, 2, 4, 1]
C = A[B]
PRINT, C
This produces the following output:
6 1 4 5
Is the above possible in C programming.
Arrays can be used as subscripts to other arrays. Each element in the subscript array selects an element in the subscripted array.
Syntactically this is not directly possible in C. You've to use a loop to achieve this.
int a[] = {6, 5, 1, 8, 4, 3};
int b[] = {0, 2, 4, 1};
for (int i = 0; i < (sizeof(b)/sizeof(b[0])); ++i)
printf("%d\n", a[b[i]]);
If you really want it to look that neat, then wrap it in a function and you should be alright:
// returns the no. of elements printed
// returns -1 when index is out of bounds
int print_array(int *a, int *b, size_t na, size_t nb)
{
int i = 0;
for (i = 0; i < nb; ++i)
{
int const index = b[i];
if (index >= na)
return -1;
print("%d\n", a[index]);
}
return i;
}
The array index operator in C can only take integer arguments. This is because the compiler will expand the operation, like A[0], into a basic addition and dereference. As such, you can't pass an array as the operand to extract several indices from the original array.
Remember that A[0] is the same as *A, and A[1] is the same as *(A + 1), etc.
Yes ofcourse it is:
int a[6] = { 6, 5, 1, 8, 4, 3 };
int b[4] = { 0, 2, 4, 1 };
printf("\na[b[0]]=%d", a[b[0]]);
printf("\na[b[1]]=%d", a[b[1]]);
printf("\na[b[2]]=%d", a[b[2]]);
printf("\na[b[3]]=%d", a[b[3]]);
output:
a[b[0]]=6
a[b[1]]=1
a[b[2]]=4
a[b[3]]=5
No, that's not possible!
In C, the array operator [x] is just a shorthand for a pointer addition.
So a[x] is the same as (a+x)*
This means the only valid arguments for the array operator are Integers.

In c: Can I copy a whole portion of an array at once, by refering to the pointer to the location of a slot in the array I want to copy from?

Hope my question is clear and relavent, new to Pointers... - Can I copy a whole portion of an array at once, by refering to the pointer to the location of the first slot in the array I want to begin copying from?
For example -
Given an array : A [ 1,2,3,4,5,7,8,3,2,5,1,0,9]
- I want to copy only the part of the array from the n'th slot on, into the beginning of the array B [0 0 0 ..... ] (B is of the same length of A).
Can I do it at once, using pointers instead of a loop? Something like - switching the pointer to the 1'st slot in B with the pointer to the n'th slot of A, and the n'th slot in B with the last one in A?
Thanks a lot on advance!
That's what memcpy is for.
memcpy(B, A + n, (N - n) * sizeof(A[0]));
where N is the number of elements in A. If A is really an array (not just a pointer to one), then N can be computed as sizeof(A) / sizeof(A[0]), so the call simplifies to
memcpy(B, A + n, sizeof(A) - n * sizeof(A[0]));
memcpy lives in <string.h>; its first argument is the destination of the copy, its second the source.
(I'm sorry, I don't really follow what kind of pointer trick you have in mind, so I can't comment on that.)
I think I understand what you're asking. You can use pointers to set up your second array, but here is the problem with doing it that way:
int [] primary = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
int * secondary = primary + 5;
At this point, primary is { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }, and secondary is { 6, 7, 8, 9, 0 }, but the problem is they both point to the same array in memory. So instead of having two independent copies, if you edit any of the elements of 'secondary', they are edited in 'primary' also.
secondary[2] = 10;
for(int i = 0; i < 10; ++i)
cout << primary[i] << ' ';
This portion of code would now yield:
1 2 3 4 5 6 7 10 9 0
The correct way to do it would to either be setting up the new array, and looping through copying over the values, or using memcpy().
Edit:
//Rotate an array such that the index value is moved to the front of the array
null rotateArray( &int original[], int size, int index)
{
int * secondary = new int[size]; //dynamically allocated array
for(int i = 0; i < size; ++i)
{
secondary[i] = original[(i+index)%size];
}
original = secondary; //Move the original array's pointer to the new memory location
}
Some notes:
secondary[i] = original[(i+index)%size];
this is how I rotated the array. Say you had an original array of size 5, and you wanted the fourth element to be the new start (remember, elements are numbered 0-(size-1)):
i = 0;
secondary[0] = original[(0 + 3)%5]// = original[3]
i = 1;
secondary[1] = original[(1 + 3)%5]// = original[4]
i = 2;
secondary[2] = original[(2 + 3)%5]// = original[0]
...
The last part of the code:
original = secondary;
is a little bit questionable, as I don't remember whether or not c++ will try and clean up the used memory once the function is exited. A safer and 100% sure way to do it would be to loop through and copy the secondary array's elements into the original array:
for(int i = 0; i < size; ++i)
original[i] = secondary[i];

Resources