Accessing elements in a static array using pointer(arithmetic) in C - c

If I have the following code in a function:
int A[5][5];
int i; int j;
for(i=0;i<5;i++){
for(j=0;j<5;j++){
A[i][j]=i+j;
printf("%d\n", A[i][j]);
}
}
This simply prints out the sum of each index. What I want to know is if it's possible to access each index in the static array in a similar fashion to dynamic array. So for example, if I wanted to access A[2][2], can I say:
*(A+(2*5+2)*sizeof(int))?
I want to perform some matrix operations on statically allocated matrices and I feel like the method used to dereference dynamic matrices would work the best for my purposes. Any ideas? Thank you.

That's the way to do it: A[i][j].
It prints out the sum of the indexes because, well, you set the element A[i][j] to the sum of the indexes: A[i][j] = i+j.

You can use:
*(*(A + 2) + 2)
for A[2][2]. Pointer arithmetics is done in unit of the pointed type not in unit of char.
Of course, the preferred way is to use A[2][2] in your program.

The subscript operation a[i] is defined as *(a + i) - you compute an offset of i elements (not bytes) from a and then dereference the result. For a 2D array, you just apply that definition recursively:
a[i][j] == *(a[i] + j) == *(*(a + i) + j)
If the array is allocated contiguously, you could also just write *(a + i * rows + j).
When doing pointer arithmetic, the size of the base type is taken into account. Given a pointer
T *p;
the expression p + 1 will evaluate to the address of the next object of type T, which is sizeof T bytes after p.
Note that using pointer arithmetic may not be any faster than using the subscript operator (code up both versions and run them through a profiler to be sure). It will definitely be less readable.

Pointer arithmetic can be tricky.
You are on the right track, however there are some differences between pointer and normal arithmetic.
For example consider this code
int I = 0;
float F = 0;
double D = 0;
int* PI = 0;
float* PF = 0;
double* PD = 0;
cout<<I<<" "<<F<<" "<<D<<" "<<PI<<" "<<PF<<" "<<PD<<endl;
I++;F++;D++;PI++;PF++,PD++;
cout<<I<<" "<<F<<" "<<D<<" "<<PI<<" "<<PF<<" "<<PD<<endl;
cout<<I<<" "<<F<<" "<<D<<" "<<(int)PI<<" "<<(int)PF<<" "<<(int)PD<<endl;
If you run it see the output you would see would look something like this (depending on your architecture and compiler)
0 0 0 0 0 0
1 1 1 0x4 0x4 0x8
1 1 1 4 4 8
As you can see the pointer arithmetic is handled depending on the type of the variable it points to.
So keep in mind which type of variable you are accessing when working with pointer arithmetic.
Just for the sake of example consider this code too:
void* V = 0;
int* IV = (int*)V;
float* FV = (float*)V;
double* DV = (double*)V;
IV++;FV++;DV++;
cout<<IV<<" "<<FV<<" "<<DV<<endl;
You will get the output (again depending on your architecture and compiler)
0x4 0x4 0x8
Remember that the code snippets above are just for demonstration purposes. There are a lot of things NOT to use from here.

Related

Proper way to iterate throught list of pointers?

I can't wrap my head about idea of array of pointers. Problem is I'm trying to iterate throught list of pointers (or at least get second value from pointer's array). I understand that integer is 4 bytes long (assuming im on 32-bit). And what I'm trying to do is get first address that points to a[0] and add to this address 4 bytes, which in my opinion will result in a[1]. However, this works as I'm just adding value to index. I.e. f[0] + 4 -> f[5]
And I don't quite understand why.
#include "stdio.h"
int main()
{
int a[6] = {10,2,3,4,20, 42};
int *f[6];
for(int i = 0; i < sizeof(a)/sizeof(int); i++) f[i] = &a[i];
for(int i = 0; i < sizeof(a)/sizeof(int); i++) printf("Current pointer points to %i\n", *(*f+i));
printf("The is %i", *(f[0]+sizeof(int)));
return 1;
}
Pointer arithmetic takes into account the size of the pointer.
f[0] + 4 will multiply 4 by the size of the integer type.
Here's an online disassembler: https://godbolt.org/.
When I type the code f[0] + 4, the disassembly appears as
add QWORD PTR [rbp-8], 16
Meaning it has multiplied the 4 by 4 (32-bit = 4 bytes) to make 16.
An array is a pointer to a chunk of RAM. int a[6] = {10,2,3,4,20, 42}; actually creates a chunk with [0x0000000A, 0x00000002, 0x00000003, 0x00000004, 0x00000014, 0x0000002A], and a points to where the list starts.
Using an index a[n] basically means go to the position of a (start of the array), then advance by n*sizeof(int) bytes.
a[0] means Go to position of a, then don't jump
a[1] means Go to position of a, then jump 1 time the size of an integer
a[2] means Go to position of a, then jump 2 times the size of an integer
supposing a is at the address 0xF00D0000, and you're on a 32bit machine:
a[0] // Pointer to 0xF00D0000
a[1] // Pointer to 0xF00D0004
a[2] // Pointer to 0xF00D0008
a[32] // Pointer to 0xF00D0080
I hope this makes sense.

how to find cell index no. in 2-D array?

in C programming if an 2-D array is given like ( int a[5][3]) and base address and address of particular element (cell ) is also given and have to find index no. of that element(cell) (row and col no.) can we find that? if yes how?
i know the formula of finding address is like this
int a[R][C];
address(a[i][j])=ba+size(C*i+ j);
if ba, R,C,Size and address(a[i][j]) is given... how to find value of i and j?
for finding the value of 2 variable we need 2 equation ..but im not able to find 2nd equation.
The specific address minus the base address gives you the size in bytes, from the base to the specific address.
If you divide that size in bytes with sizeof(ba[0][0]) (or sizeof(int)), you get the number of items.
items / C gives you the first dimension and items % C gives you the second dimension.
Thus:
int ba[R][C];
uintptr_t address = (uintptr_t)&ba[3][2]; // some random item
size_t items = (address - (uintptr_t)ba) / sizeof(ba[0][0]);
size_t i = items / C;
size_t j = items % C;
It is important to carry out the arithmetic with some type that has well-defined behavior, therefore uintptr_t.
If I had done int* address then address - ba would be nonsense, since ba decays into an array pointer of type int(*)[3]. They aren't compatible types.
Use integer division and remainder operators.
If you have the base and a pointer to an element, elt, then there are two things:
In "pure math" terms, you'll have to divide by the size of the elements in the array.
In "C" terms, when you subtract pointers this division is performed for you.
For example:
int a[2];
ptrdiff_t a0 = (ptrdiff_t)&a[0];
ptrdiff_t a1 = (ptrdiff_t)&a[1];
a1 - a0; // likely 4 or 8.
This will likely be 4 or 8 because that's the likely size of int on whatever machine you're using, and because we performed a "pure math" subtraction of two numbers.
But if you let C get involved, it tries to do the math for you:
int a[2];
int * a0 = &a[0];
int * a1 = &a[1];
a1 - a0; // 1
Because C knows the type, and because it's the law, the subtracted numbers get divided by the size of the type automatically, converting the pointer difference into an array-like index or offset.
This is important because it will affect how you do the math.
Now, if you know that the address of elt is base + SIZE * (R * i + j) you can find the answer with integer division (which may be performed automatically for you), subtraction, more integer division, and either modulus or multiply&subtract:
offset or number = elt - base. This will either give you an index (C style) or a numeric (pure math) difference, depending on how you do the computation.
offset = number / SIZE. This will finish the job, if you need it.
i = offset / R. Integer division here - just throw away the remainder.
j = offset - (i*R) OR j = offset % R. Pick what operation you want to use: multiply & subtract, or modulus.

Calculating the address: pointer + non-negative number

Pointers can only move in discrete steps.
int *p;
p = malloc(sizeof(int)*8);
Therefore, formally *(p+2) is calculated as *(p+2*sizeof(int)).
However If I actually code the above two, I get different results, which seems understandable.
*p = 123;
*(p+2) = 456;
printf("%d\n",*(p+2*(sizeof(int)))); \\0
printf("%d\n",*(p+2)); \\456
The question is, is this calculation implicit, done by the compiler at compile time?
The question is, is this calculation implicit, done by the compiler at
compile time?
Yes this is implicit, when you write ptr+n it actually advances forward n times as many bytes as size of pointee type (e.g. in case of int* - this is 4 bytes granted integer takes four bytes on your computer).
e.g.
int *x = malloc(4 * sizeof(int)); // say x points at 0x1000
x++; // x now points at 0x1004 if size of int is 4
You can read more on pointer arithmetic.
Therefore, formally *(p+2) is calculated as *(p+2*sizeof(int)).
No, *(p+2) is calculated as *(int*)((char*)p+2*sizeof(int)).
Even a brief look reveals that the only way for your statement to hold is if sizeof(int) == 1.

Accessing 2d array with pointer arithmetic

I have an array A[n][n] how come i can access it like this: *A+i*blockSize*dimenson? Doesn't that translate to A[i*blockSize*n]?
How can this be if i*blockSize*n is a number bigger than n? I was thinking that it works because 2d arrays in C are really just one contiguous piece of memory. But, that doesn't change the fact that i can't code A[i*blockSize*n][j] = something without getting a run-time error.
So why is *A+i*blockSize*dimenson ok but, not A[i*blockSize*n]
I hope this question makes sense to someone who is an expert in C..
Doesn't that translate to A[i * blockSize * n]
No, it doesn't what you have is1
*A + i * blockSize * dimenson
is actually equivalent to
A[0] + i * blockSize * dimension
You need to read about operator precedence, the correct equivalent expression is
*(A + i * blockSize * dimenson)
but that is not necessary because it makes the code harder to read without giving you any benefit at all.
1Please use surrounding spaces for operators so that it's easy to distinguish between operators and operands.
First:
*(A+i*blockSize*dimenson)
Translates into:
A[i*blockSize*dimenson]
And you simply can't do:
A[i*blockSize*n][j] = something
if i*blockSize*n is bigger than n, because you will get out of the bounds of the array you allocated, which is of size n by n.
But you can do:
A[i][j]
as:
B[i*n+j]
if you declare B as unidimensional array pointing to A, for example:
int A[n][n];
int * B = (int *)A;

for-loop optimization using pointer

I am trying to optimize code to run in under 7 seconds. I had it down to 8, and now I am trying to use pointers to speed up the code. But gcc gives an error when I try to compile:
.c:29: warning: assignment from incompatible pointer type .c:29:
warning: comparison of distinct pointer types lacks a cast
Here is what I had before trying to use pointers:
#include <stdio.h>
#include <stdlib.h>
#define N_TIMES 600000
#define ARRAY_SIZE 10000
int main (void)
{
double *array = calloc(ARRAY_SIZE, sizeof(double));
double sum = 0;
int i;
double sum1 = 0;
for (i = 0; i < N_TIMES; i++) {
int j;
for (j = 0; j < ARRAY_SIZE; j += 20) {
sum += array[j] + array[j+1] + array[j+2] + array[j+3] + array[j+4] + array[j+5] + array[j+6] + array[j+7] + array[j+8] + array[j+9];
sum1 += array[j+10] + array[j+11] + array[j+12] + array[j+13] + array[j+14] + array[j+15] + array[j+16] + array[j+17] + array[j+18] + array[j+19];
}
}
sum += sum1;
return 0;
}
Here is what I have when I use pointers (this code generates the error):
int *j;
for (j = array; j < &array[ARRAY_SIZE]; j += 20) {
sum += *j + *(j+1) + *(j+2) + *(j+3) + *(j+4) + *(j+5) + *(j+6) + *(j+7) + *(j+8) + *(j+9);
sum1 += *(j+10) + *(j+11) + *(j+12) + *(j+13) + *(j+14) + *(j+15) + *(j+16) + *(j+17) + *(j+18) + *(j+19);
}
How do I fix this error? Btw I don't want suggestions on alternative ways to try to optimize the code. This is a homework problem that has constraints about what I'm allowed to do. I think once I get this pointer thing fixed it will run under 7 seconds and i'll be good to go.
comparison of distinct pointer types lacks a cast
This means that you tried to compare a pointer of one type to a pointer of another type, and did so without a cast.
double *array = calloc(ARRAY_SIZE, sizeof(double));
int *j;
Pointers to double and pointers to int are not directly comparable. You aren't allowed to compare j to array for this reason. Perhaps you meant to declare j as a pointer to double ?
C is a statically typed language, and comparisons across pointer types will give you errors. There is some implicit casting in certain cases, like if you compare a double to an int, because comparing numbers is a common operation. Comparing pointers of different types isn't.
Further, when you increment a pointer over an array, it uses the size of it's dereferenced element to know how far in memory to move. Moving with an int over an array of doubles will lead to issues.
A double will move farther then an int, so you will get more interations with an int pointer anyway.
You could explicitly cast things, but really you should be using a double * for an array of doubles.
I'd be greatly surprised if moving from an array representation to a pointer representation would yield much (if any) speedup, as both are memory addresses (and memory offsets) in the final outputted code. Remember, the array representation is actually a pointer representation in different clothing too.
Instead, I'd look towards one of two techniques:
Embedded MMX representations, to do multiple addition operations within the same register, under the same clock cycle. Then, you need one operation near the end to combine the high double with the low double.
Scatter / Gather algorithims to spread the addition operation across multiple cores (nearly every CPU these days has 4 cores available, if not 16 pseudo-cores (a la hyper-threading))
Beyond that, you can do a few attempts at cache analysis, and at storing intermediates in different registers. There seems to be a deep chain of additions in each of your computations. Breaking them up might yield the ability to spread the on-cpu storage across more registers.
Most operations become memory bound. 20 is a really strange boundary for loop unrolling. Doubles probably are 16 bits, so 20 doubles is 320 bits, which is probably not aligned to your memory cache line size. Try making sure that multiples of your unrolled loop align cleanly with your architecture's level 1 cache, and you might avoid a page fault as you read across cache boundaries. Doing so will speed up your program by some (but who knows how much).
" When you increment a pointer over an array, it uses the size of it's dereferenced element to know how far in memory to move. Moving with an int over an array of doubles will lead to issues ".
To avoid your warn: do the below one
for (j= (int *)array; j < (int *)&array[ARRAY_SIZE]; j += 20)

Resources