How to Calculate the Element Addresses of an N-Dimensional Array - c

From what I understand, blocks of allocated memory is continuous, so addresses in an array are sequential in multiples of the size of the array data (int = 4 on some systems, etc.)
I've also seen that for an array A and index i, A[i] == *(A+i) in C.
A 2D array is like an array of arrays, so I wanted to know how to determine the expression for an N-dimensional array if I was crazy enough not to use the [] operator.
If the array was created with pointers, wouldn't it be necessary to know the length of the level?

For
int array2d[X][Y];
the two expressions are equivalent:
array[1][2];
*((int *)array + 1*Y + 2);
For
int array3d[X][Y][Z]
the two expressions are equivalent:
array[1][2][3];
*((int *)arr + 1*Y*Z + 2*Z + 3);
So, for
int arraynd[X][Y][Z]..[N]
the two expression are equivalent:
arraynd[1][2][3]...[n];
((int *)array + 1*X*Y*Z*...*N + 2*Y*Z*...*N + 3*Z*...*N + ... + n);

Suppose you declare int a[m][n]; If you reference a[i][j], it is equivalent to (a[i])[j] which, as you noted, is equivalent to (*(a+i))[j], which is equivalent to *((*(a+i))+j). In terms of bytes, the integer is scaled by the size of the object pointed to, so i is scaled by the size of a[0], or *a, which is the size of the sub-array, which is sizeof(int) * n. The dereference of the result, via the * operator, is essentially a type cast, converting it from a pointer to the sub-array, type int (*)[n], to a pointer to an element of the sub-array, type int *. Then, when adding j, it is scaled by sizeof(int). The outer dereference, via the * operator, actually dereferences the pointer, either reading the value or modifying it, depending on the context.
Edit: Here's a simple demonstration program you can try. It illustrates what I explained:
#include <stdio.h>
int main()
{
int a[5][10];
printf("%d %d %d\n", sizeof(int[5][10]), sizeof(int[10]), sizeof(int));
printf("%d %d %d\n", sizeof(a), sizeof(a[0]), sizeof(a[0][0]));
printf("%d %d %d\n", sizeof(a), sizeof(*a), sizeof(**a));
void *p1 = a;
void *p2 = a + 1;
void *p3 = *(a + 1) + 3;
printf("%d %d\n", (int) (p2 - p1), (int) (p3 - p2));
printf("%d %d\n", 1 * (sizeof(int) * 10), 3 * sizeof(int));
return 0;
}

Related

Pointers to an Array In C

So my book is explaining me pointers to an array using ts example
#include <stdio.h>
int main()
{
int s[4][2] = {
{1234,56},{1212,33},{1434,80},{1312,78}
};
int(*p)[2];
int i, j, * pint;
for (i = 0; i <= 3; i++)
{
p = &s[i];
pint = (int*)p;
printf("\n");
for (j = 0; j<= 1; j++)
{
printf("%d ", *(pint + j));
}
}
return 0;
}
The output is Given as
1234 56
1212 33
1434 80
1312 78
No issue I am getting the same output.
My question is what was the need of using another pointer pint ?
Why can't we directly use P?
So When I tried to do it using P directly it didn't work
printf("%d ", *(p + j));
I got garbage values in output, Why is this happening?
I also tried printing p and pint they are the same.
Although p and pint have the same value, p + 1 and pint + 1 do not. p + 1 is the same as (char *)p + sizeof *p, and pint + 1 is the same as (char *)pint + sizeof *pint. Since the size of the object pointed to is different, the arithmetic gives different results.
The pointer p is declared like
int(*p)[2];
So dereferencing the pointer expression with the pointer in this call of printf
printf("%d ", *(p + j));
you will get the j-th "row" of the type int[2] of the two dimensional array that in turn will be implicitly converted to a pointer of the type int * that will point to the first element of the j-th "row".
So instead of outputting elements of each row you will output first elements of each row that moreover results in undefined behavior when i will be greater than 2.

Understanding double pointer to an array in C

I have been learning C for couple of months and I came across a question which is given below.
#include <stdio.h>
int main() {
int a[2][2] = {{1,2}, {3,4}};
int (**p)[2] = &a;
for (int i=0; i<2; ++i) {
for (int j=0; j<2; ++j) {
printf("%d %u\n", a[i][j], (*(a+i) + j));
}
}
for (int i=0; i<4; ++i) {
printf("%d %u\n", *(*p + i), (*p + i));
}
printf("%u\n", p);
printf("%u\n", p+1);
printf("%u\n", p+2);
printf("%u\n", p+3);
printf("%u\n", *p);
printf("%u\n", *p+1);
printf("%u\n", *p+2);
printf("%u\n", *p+3);
puts("");
}
The output that I am getting on my machine is as follows:
1 3751802992
2 3751802996
3 3751803000
4 3751803004
1 1
9 9
17 17
25 25
3751802992
3751803000
3751803008
3751803016
1
9
17
25
I understand the first four lines of the output where the elements of the 2D array and their respective addresses is getting printed but I have absolutely no clue how the other outputs are happening.
I checked in an online IDE and there also I am getting the same output except the addresses which obviously will differ.
I know that int (**p)[2] is incomparable pointer type to a[2][2] which is a (int *)[2] data type.
But still I want to understand how the p pointer is working.
Can someone please help me understand how this is happening?
I have been eagerly waiting to get the logic behind the code outputs.
I am extremely sorry for the long code snippet and the long output sequence.
Thanks in advance.
N.B - I know that the code is producing a lot of warnings but I want to get the core idea about p.
The problem with this code starts right here:
int main() {
int a[2][2] = {{1,2}, {3,4}};
int (**p)[2] = &a; // <-- Invalid conversion, undefined behaviour
// warning: incompatible pointer types initializing 'int (**)[2]' with an expression of type 'int (*)[2][2]' [-Wincompatible-pointer-types]
// ... Everything past here is undefined behaviour
}
There's a huge difference between int** and what you're attempting to cast, one big enough that this conversion isn't possible.
int** means, specifically, a structure where it's an array of int*, or pointers. Treating int[2] as a pointer is going to be a mess. That any of this code even semi-works is hard to explain. It's the compiler trying to make the best of a bad situation.
I introduced a macro LEN to calculate your array sizes instead of hard-coping the magic numbers, fixed the declaration of p, changed the unsigned format %u to signed %d as you were printed signed values, the last loop, I am sure what the 2nd thing you were trying to print so left it out, and the last section of print statements were pointers so used %p for those in a loop instead of duplicating the code:
#include <stdio.h>
#define LEN(a) sizeof(a) / sizeof(*a)
int main() {
int a[2][2] = {{1,2}, {3,4}};
int (*p)[2] = a;
for (int i=0; i < LEN(a); i++) {
for (int j = 0; j < LEN(*a); j++) {
printf("%d %d\n", a[i][j], *(*(a + i) + j));
}
}
for (int i=0; i < LEN(a) * LEN(*a); i++) {
printf("%d\n", *(*p + i));
}
for(int i = 0; i < LEN(a) * LEN(*a); i++) {
printf("%p\n", p + i);
}
for(int i = 0; i < LEN(a) * LEN(*a); i++) {
printf("%p\n", (void *) *(p + i));
}
puts("");
}
This is a problem:
int (**p)[2] = &a; // int (**)[2] = int (*)[2][2]
The type of &a is int (*)[2][2], not int (**)[2]. Your pointer declaration should be
int (*p)[2][2] = &a;
Unless it is the operand of the sizeof or unary & operators or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T will be converted, or "decay", to an expression of type "pointer to T" and the value of the expression will be the address of the first element of the array.
The expression a "decays" from type "2-element array of 2-element array of int" (int [2][2]) to "pointer to 2-element array of int" (int (*)[2]). However, since a is the operand of the unary & operator that conversion doesn’t take place, so &a has type "pointer to 2-element array of 2-element array of int" (int (*)[2][2]). Thus,
p == &a
(*p) == a
(*p) + i == a + i == &(*p)[i] == &a[i]
*((*p) + i) == *(a + i) == (*p)[i] == a[i]
*((*p) + i) + j == *(a + i) + j == &(*p)[i][j] == &a[i][j]
*(*((*p) + i) + j) == *(*(a + i) + j) == (*p)[i][j] == a[i][j]
A pointer is used to store the address of variables. So, when we define a pointer to pointer, the first pointer is used to store the address of the second pointer. Thus it is known as double pointers.
EXAMPLE:
int main() {
int integerValue = 84;
int *pointer1;
int **pointer2;
pointer1 = &integerValue;
pointer2= &pointer1;
printf("Value of integer = %d\n", integerValue);
printf("Value of integer using single pointer = %d\n", *pointer1);
printf("Value of integer using double pointer = %d\n", **pointer2);
return 0;
}
OUTPUT:
Value of integer = 84
Value of integer using single pointer = 84
Value of integer using double pointer = 84

How to access elements of 2D array created with malloc, using pointers?

I have code like this:
#include <stdio.h>
#include <stdlib.h>
int main() {
int x=10;
int y=10;
int **data = (int**) malloc(x * sizeof(int));
if(!**data){
printf("Error");
return 1;
}
for(int i=0;i<x;i++){
*(data+i) = (int*) malloc(y * sizeof(int));
if(!*(data+i)){
printf("Error");
return 1;
}
}
for(int i=0;i<x;i++){
for(int j=0;j<y;j++){
data[i][j]=(i+1)*(j+1);
}
}
for(int i=0;i<x;i++){
for(int j=0;j<y;j++){
printf("%3i ",data[i][j]);
}
printf("\n");
}
return 0;
}
How can i access points of that array using pointers instead of data[i][j]?
I tried searching for answer but in every example I see people use data[x][y] option, i have to use pointers for accessing each element.
Also is error handling correct in that code?
if(!**data){
printf("Error");
return 1;
}
Here's a major problem, especially on 64-bit systems where sizeof(int) != sizeof(int *):
int **data = (int**) malloc(x * sizeof(int));
You allocate x times the size of int, not the size of pointer to int.
There is a good "trick" to always get the correct size, use sizeof *variable_youre_allocating_for. In your case it would be
int **data = malloc(x * sizeof *data);
This works because sizeof *data is done at compile-time, and the compiler knows that *data is of type int * and will use the correct size.
Also notice that I removed the cast, it's not needed in C.
Besides that, your use of the data is correct. Using data[i][j] is perfectly fine, if i and j are valid indexes, and data and data[i] have been properly initialized.
The important part is to remember that for any pointer or array a and index i, the expression a[i] is exactly equal to *(a + i). In fact, the compiler will translate a[i] to *(a + i). So for your pointer data, the expression *(data + i) is exactly equal to data[i]. And the latter is usually easier to read and understand, as well as less to write.

Printing value of a pointer to a pointer

I am trying to wrap my head around "pointer to a pointer". And I tried some experiments and I got stuck here for a while:
int array[5] = {4 , 5 ,6 ,7 ,8};
int *p = array;
int **pp = &p;
for ( int i = 0; i < 4; i ++)
{
printf("\nprinting\n");
printf("Source: %d\n", array[i]);
printf("Output by pointer: %d, %d\n", p[i], *(p + i));
printf("Output by pointer to a pointer: %d, %d\n", *pp[i], **(pp + i) );
}
And I got this as output:
printing
Source: 4
Output by pointer: 4, 4
Output by pointer to a pointer: 4, 4
printing
Source: 5
Output by pointer: 5, 5
I don't understand why after 1 loop, the program stop at the 2nd loop- line 9. Did I misunderstand anything basic knowledge or something else.
Thank you for reading.
Change the last printf to:
printf("Output by pointer to a pointer: %d, %d\n", (*pp)[i], *(*pp + i) );
You're basically using *pp in place of p, but the * operator doesn't group as tightly as [] so you need to use parentheses in the first form. In the second form, you need to dereference pp before adding i, after which the result is dereferenced.
For starters it is unclear why there is used the magic number 4 in the loop instead of the number 5 that is the number of elements in the array
for ( int i = 0; i < 4; i ++)
^^^^^
The pointer pp does not point to first element of an array. It points to a single object
int **pp = &p;
So these expressions
*pp[i] (that is equivalent to *(pp[i] )
and
**(pp + i)
does not make sense.
An expression using the pointer p can be written using the pointer pp like *pp.
So these correct expressions
p[i]
and
*(p + i)
can be written using the pointer pp the following way (just substitute p for *pp taking into account operation precedences)
( *pp )[i]
and
*( *pp + i )
You acesses to pointer thru pointer-to-pointers are wrong:
you must access the pointee as the array:
int array[5] = {4 , 5 ,6 ,7 ,8};
int *p = array;
int **pp = &p;
for ( int i = 0; i < 4; i ++)
{
printf("\nprinting\n");
printf("Source: %d\n", array[i]);
printf("Output by pointer: %d, %d\n", p[i], *(p + i));
printf("Output by pointer to a pointer: %d, %d\n", (*pp)[i], *(*pp + i) );
}
This line is wrong
printf("Output by pointer to a pointer: %d, %d\n", *pp[i], **(pp + i) );
You need to change it to
printf("Output by pointer to a pointer: %d, %d\n", (*pp)[i], *(*pp + i) );
so that you dereference the double pointer before using it as a normal pointer.
You can think of it like this:
p is the same as (*pp)
In other words - in a valid expression that uses p you are allowed to substitute p with (*pp). That is
p[i] --> (*p)[i]
*(p + i) --> *((*pp) + i) --> *(*pp + i)
Notice that the parenthesis is important. The parenthesis can be removed in the second example but not in the first as [] has higher precedence than *.
Doing pp + i generates a pointer that doesn't point to any valid object. So when you dereference it using **(pp + i) you do an illegal access an your program crashes.

Transferring values from void pointer

Can someone tell me whats wrong with this code?
base is a void pointer to a bunch of floats
i is a value >1
size is the size of the type (in this case float - 4 )
char *a = (char *)base;
char *temp = (char *)a + size * (i/2);
printf("%d: %d = ", i, temp);
memcpy(a + size * i , temp , size);
printf("%d\n", a + size * i);
This is the output:
2: 136724 = 136728
3: 136724 = 136732
4: 136728 = 136736
6: 136732 = 136744
7: 136732 = 136748
8: 136736 = 136752
If a was a void*, the compiler wouldn't allow you to write a + size*i (you can't do pointer arithmetic with incomplete types). Probably the type isn't what you think it is.
But why do you think there's a problem? The left-hand column advances half as fast as the right-hand column, and this is expected because you are dividing by 2.
You do realize that you're printing addresses, and not the values being copied, right?
char *a = (char *)base;
char *temp = (char *)a + size * (i/2);
printf("%d: %f = ", i, *(float *)temp);
memcpy(a + size * i , temp , size);
printf("%f\n", *(float *)(a + size * i));
The changes I have made are to dereference the pointers correctly (and casting them to the correct type) and to change %d to %f as you specified that base is an array of floats. %d is for ints and %f is for floats.
The reason your code did not work is that you were printing out the addresses and not the values.
Would you please tell us what you're trying to accomplish? Seems like a
homework problem, right?
The C language allows you to cast any pointer to a void*, and then cast it
back to the original pointer type, without losing any information. Anything
else you do with a void pointer is a bad idea, although some library functions
(such as memcpy) still have void* for historical reasons. That's also why
you don't need an explicit cast to go from any pointer type to a void*.
You cannot look at what the void* points to, until you cast it back to the
correct pointer type. And be careful when you do!
#include <stdio.h>
#include <memory.h>
/* It's a bad idea to pass Base as a void pointer,
but that's what you said you have. */
void silly_function(void*base, int i, int size) {
/* Using a char* that points to float, is an even worse idea!
char *a = (char *)base;
char *temp = (char *)a + size * (i/2);
printf("%d: %d = ", i, temp);
memcpy(a + size * i , temp , size);
printf("%d\n", a + size * i);
**/
/** Probably ought to have a big SWITCH statement here, based
on the data type. sizeof() isn't a good way to do this...
On many computers, sizeof(float)==sizeof(long), but that
doesn't mean that a float* is the same as a long* !!!
For now, I'm going to assume (as you did) that base points
to an array of float. */
/* I think you're trying to copy the first half of the array
into the second half of the array! But that's easy. */
float*firsthalf = (float*)base;
float*secondhalf = firsthalf + (i/2);
/* Show some starting values. */
printf("Before: %x --> %f, %x --> %f\n",
firsthalf, *firsthalf, secondhalf, *secondhalf);
/* Now do the copy */
memcpy(secondhalf, firsthalf, (i/2)*(sizeof(float)));
/* Now prove that it's been copied? */
printf("After: %x --> %f, %x --> %f\n",
firsthalf, *firsthalf, secondhalf, *secondhalf);
}
int main() {
/* This drives the test */
float ary[10] = {
1.1f, 2.2f, 3.3f, 4.4f, 5.5f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
silly_function(ary, 10, sizeof(ary[0]));
return 0;
}
On my system, the output is
Before: 12ff38 --> 1.100000, 12ff4c --> 0.000000
After: 12ff38 --> 1.100000, 12ff4c --> 1.100000
I hope this helps.

Resources