How do I make a 2D array initialization function with pointers? - c

I'm trying to make a function that takes in the pointer of the 2d array and the integers y and x based on the size of the array. I keep getting errors here and was hoping someone could help me out. the function randNum just returns a random integer from 0 to 9.
void initialize(int t[], int y, int x){
for(p = &t[0][0]; p <= &t[y-1][x-1]; p++){
*(t + ((y*x) + x)) = randomNum(0,9);
}
}

void initialize(int t[], int y, int x){
for(int *i = t, i < t + x * y; i++)
*i = randomNum(0,9);
}
Explanation:
Your array contains x times y integers, so it is a memory segment containing those. Thus, we can see it as an one dimensional array of size x*y.
Your code does not work because for instance the compiler would have no way to determine what
&t[y-1][x-1]
even is. For an integer array a the compiler would know that for
*(a + k) == a[k]
it would need to take the address of a and add k times the size of an integer (usually 4 bytes). For
a[k][l]
we would need to take
*(a + innerdimension * k + l)
but as the compiler does not know what the inner dimension is it cannot work.
Alternatively you could also go for something like
void intitialize(int *t, int y, int x){
for(int i = 0; i < y; i++)
for (int j = 0; j < x; j++)
*(t + i * x + j) = randomNum(0,9);
}
While this is a bit longer it would exactly describe how you would iterate over an 2D array while replacing the not working t[i][j] by its equivalent (t + ix + j) given a known inner dimension x.

Related

How many pointers are in an array of pointers

I dynamically allocated memory for 3D array of pointers. My question is how many pointers do I have? I mean, do I have X·Y number of pointers pointing to an array of double or X·Y·Z pointers pointing to a double element or is there another variant?
double*** arr;
arr = (double***)calloc(X, sizeof(double));
for (int i = 0; i < X; ++i) {
*(arr + i) = (double**)calloc(Y, sizeof(double));
for (int k = 0; k < Y; ++k) {
*(*(arr+i) + k) = (double*)calloc(Z, sizeof(double));
}
}
The code you apparently intended to write would start:
double ***arr = calloc(X, sizeof *arr);
Notes:
Here we define one pointer, arr, and set it to point to memory provided by calloc.
Using sizeof (double) with this is wrong; arr is going to point to things of type double **, so we want the size of that. The sizeof operator accepts either types in parentheses or objects. So we can write sizeof *arr to mean “the size of a thing that arr will point to”. This always gets the right size for whatever arr points to; we never have to figure out the type.
There is no need to use calloc if we are going to assign values to all of the elements. We can use just double ***arr = malloc(X * sizeof *arr);.
In C, there is no need to cast the return value of calloc or malloc. Its type is void *, and the compiler will automatically convert that to whatever pointer type we assign it to. If the compiler complains, you are probably using a C++ compiler, not a C compiler, and the rules are different.
You should check the return value from calloc or malloc in case not enough memory was available. For brevity, I omit showing the code for that.
Then the code would continue:
for (ptrdiff_t i = 0; i < X; ++i)
{
arr[i] = calloc(Y, sizeof *arr[i]);
…
}
Notes:
Here we assign values to the X pointers that arr points to.
ptrdiff_t is defined in stddef.h. You should generally use it for array indices, unless there is a reason to use another type.
arr[i] is equivalent to *(arr + i) but is generally easier for humans to read and think about.
As before sizeof *arr[i] automatically gives us the right size for the pointer we are setting, arr[i].
Finally, the … in there is:
for (ptrdiff_t k = 0; k < Y; ++k)
arr[i][k] = calloc(Z, sizeof *arr[i][k]);
Notes:
Here we assign values to the Y pointers that arr[i] points to, and this loop is inside the loop on i that executes X times, so this code assigns XY pointers in total.
So the answer to your question is we have 1 + X + XY pointers.
Nobody producing good commercial code uses this. Using pointers-to-pointers-to-pointers is bad for the hardware (meaning inefficient in performance) because the processor generally cannot predict where a pointer points to until it fetches it. Accessing some member of your array, arr[i][j][k], requires loading three pointers from memory.
In most C implementations, you can simply allocate a three-dimensional array:
double (*arr)[Y][Z] = calloc(X, sizeof *arr);
With this, when you access arr[i][j][k], the compiler will calculate the address (as, in effect, arr + (i*Y + j)*Z + k). Although that involves several multiplications and additions, they are fairly simple for modern processors and are likely as fast or faster than fetching pointers from memory and they leave the processor’s load-store unit free to fetch the actual array data. Also, when you are using the same i and/or j repeatedly, the compiler likely generates code that keeps i*Y and/or (i*Y + j)*Z around for multiple uses without recalculating them.
Well, short answer is: it is not known.
As a classic example, keep in mind the main() prototype
int main( int argc, char** argv);
argc keeps the number of pointers. Without it we do not know how many they are. The system builds the array argv, gently updates argc with the value and then launches the program.
Back to your array
double*** arr;
All you know is that
arr is a pointer.
*arr is double**, also a pointer
**arr is double*, also a pointer
***arr is a double.
What you will get in code depends on how you build this. A common way if you need an array of arrays and things like that is to mimic the system and use a few unsigned and wrap them all with the pointers into a struct like
typedef struct
{
int n_planes;
int n_rows;
int n_columns;
double*** array;
} Cube;
A CSV file for example is char ** **, a sheet workbook is char ** ** ** and it is a bit scary, but works. For each ** a counter is needed, as said above about main()
A C example
The code below uses arr, declared as double***, to
store a pointer to a pointer to a pointer to a double
prints the value using the 3 pointers
then uses arr again to build a cube of X*Y*Z doubles, using a bit of math to set values to 9XY9.Z9
the program uses 2, 3 and 4 for a total of 24 values
lists the full array
list the first and the very last element, arr[0][0][0] and arr[X-1][Y-1][Z-1]
frees the whole thing in reverse order
The code
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
int n_planes;
int n_rows;
int n_columns;
double*** array;
} Cube;
int print_array(double***, int, int, int);
int main(void)
{
double sample = 20.21;
double* pDouble = &sample;
double** ppDouble = &pDouble;
double*** arr = &ppDouble;
printf("***arr is %.2ff\n", ***arr);
printf("original double is %.2ff\n", sample);
printf("*pDouble is %.2ff\n", *pDouble);
printf("**ppDouble is %.2ff\n", **ppDouble);
// but we can build a cube of XxYxZ doubles for arr
int X = 2;
int Y = 3;
int Z = 4; // 24 elements
arr = (double***)malloc(X * sizeof(double**));
// now each arr[i] must point to an array of double**
for (int i = 0; i < X; i += 1)
{
arr[i] = (double**)malloc(Y * sizeof(double*));
for (int j = 0; j < Y; j += 1)
{
arr[i][j] = (double*)malloc(Z * sizeof(double));
for (int k = 0; k < Z; k += 1)
{
arr[i][j][k] = (100. * i) + (10. * j) + (.1 * k) + 9009.09;
}
}
}
print_array(arr, X, Y, Z);
printf("\n\
Test: first element is arr[%d][%d[%d] = %6.2f (9XY9.Z9)\n\
last element is arr[%d][%d[%d] = %6.2f (9XY9.Z9)\n",
0, 0, 0, arr[0][0][0],
(X-1), (Y-1), (Z-1), arr[X-1][Y-1][Z-1]
);
// now to free this monster
for (int x = 0; x < X; x += 1)
{
for (int y = 0; y < Y; y += 1)
{
free(arr[x][y]); // the Z rows
}
free(arr[x]); // the plane Y
}
free(arr); // the initial pointer;
return 0;
}; // main()
int print_array(double*** block, int I, int J, int K)
{
for (int a = 0; a < I; a += 1)
{
printf("\nPlane %d\n\n", a);
for (int b = 0; b < J; b += 1)
{
for (int c = 0; c < K; c += 1)
{
printf("%6.2f ", block[a][b][c]);
}
printf("\n");
}
}
return 0;
}; // print_array()
The output
***arr is 20.21f
original double is 20.21f
*pDouble is 20.21f
**ppDouble is 20.21f
Plane 0
9009.09 9009.19 9009.29 9009.39
9019.09 9019.19 9019.29 9019.39
9029.09 9029.19 9029.29 9029.39
Plane 1
9109.09 9109.19 9109.29 9109.39
9119.09 9119.19 9119.29 9119.39
9129.09 9129.19 9129.29 9129.39
Test: first element is arr[0][0[0] = 9009.09 (9XY9.Z9)
last element is arr[1][2[3] = 9129.39 (9XY9.Z9)

Creating and looping a two-dimensional array from dynamic values in C

I am trying to create a two dimensional array based on two pre-calculated values (here len1 and len2 are const, but they come from another function). When I run this I get segmentation fault. I am very new to C, this is my first task. Can not figure it out from Guides nor SO, anybody around to help me out?
I suppose the dynamic creation of the two dimensional arrays is wrong. But can't find a good example that would work ..
int main() {
int y, x;
int my_val = 10; // dynamnic value calculated by another func
int len1 = 3; // dynamnic value calculated by another func
int len2 = 3; // dynamnic value calculated by another func
int cols = len1 + 1;
int rows = len2 + 1;
int **twodarr = (int **)malloc(rows * cols * sizeof(int));
for (x = 1; x < cols; x++) {
for (y = 1; y < rows; y++) {
twodarr[y][x] = my_val;
}
}
return 0;
}
Arrays have never been first class elements in C, and multi-dimensional ones have even more poor support. Originally, only C used constant sized arrays, because pointer arithmetics was enough for dynamic 1D arrays, and pointers were an essential element of the language.
C99 introduced the concept of Variable Length Arrays which are what #Lundin's answer uses. Unfortunately, C11 defined them as an optional feature, and Microsoft choosed not to support them for compatibility with C++.
If you use a Microsoft compiler or want compability with environments that do not support the optional VLA feature, you will have to use the old linear idiom: you only use 1D arrays and use compound indices computation: the index of element (i, j) is j + i * cols where cols is the size of the second dimension.
Your code could become:
...
int *twodarr = malloc(rows * cols * sizeof(int)); // BEWARE: actualy 1D array!
for (x = 1; x < cols; x++) {
for (y = 1; y < rows; y++) {
twodarr[x + y*cols] = my_val;
}
}
...
You have to allocate each rows
// allocation of cols
int **twodarr = (int **)malloc(cols * sizeof(int*));// note it is sizeof(int*)
// allocation each rows (in each cols)
for (x = 0; x < cols; x++) {
twodarr[x] = (int *)malloc(rows * sizeof(int));
}
The problem is that int **twodarr cannot be used for 2D arrays, it has no relation what-so-ever to them. You need to swap it for a pointer to a 2D array. Or more conveniently, a pointer to a 1D array - a pointer to a row in this case, assuming [rows][cols].
Also, arrays in C start at index 0.
Code with bug fixes & a simple print example:
#include <stdio.h>
#include <stdlib.h>
int main() {
int my_val = 10; // dynamnic value calculated by another func
int len1 = 3; // dynamnic value calculated by another func
int len2 = 3; // dynamnic value calculated by another func
int rows = len2 + 1;
int cols = len1 + 1;
int (*twodarr)[cols] = malloc( sizeof(int[rows][cols]) );
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
twodarr[r][c] = my_val;
printf("%d ", twodarr[r][c]);
}
puts("");
}
free(twodarr);
return 0;
}
#kcabus had it right...and admittedly the much more readable way for sanity sake.
The other way to go about it would be to declare it as a memory block, but its much more confusing.
such as
int *twodarr = (int*)calloc((rows *
cols), sizeof(int));
// accessed as follows
*(twodarr + rows*r + c) = value;
// rows * position + position 2
// much more confusing.
A third alternative would be to create a struct like POINT (or just use point) and use two values by just creating an array of POINT just as an example. But I assume you don't want to deal with that in a loop...and I don't blame you heh.

Copying data from 1st to 2nd array using Pointer arithemtic

I am learning C, and I came across this problem I can't figure it out. Write a function that computes the element of an integer array a plus 6 modulus 10 and store the result in array b. For example, if 5 is the second element of array a, then the second element of array b should be (5+6)%10, which is 1. The function has the following prototype, n is the length of the arrays, a and b are the integer arrays.
I did:
void arithmetic (int *a, int n, int *b)
{
int *arr1; arr1=a; int *arr2; arr2=b;
int i;
for(i = 0; i < n; i++) {
*arr1 = *(((a + i) + 6) % 10);
*arr2 = *arr1;
}
}//don't know if the function is correct.
A couple things:
No need to update the actual content of the first array (which fixes the error pointed out about your code always storing the result in the first element of a)
Use some parens to make sure you get the right order of operations.
void newArr(int *a, int n, int *b) {
int *arr1; arr1 = a; int *arr2; arr2 = b;
for (int i = 0; i < n; i++) {
*(arr2 + i) = (*(arr1 + i) + 6) % 10;
}
}
Think about your title "...using Pointer arithemtic". You need to add the loop counter to the array pointer for both arr1 and arr2 so that it steps through each element of each array: *(arr2 + i) and *(arr1 + i).
This is also a good place to reinforce the fact that the pointers are passed by value and that the function receives copy of each pointer which it is free to iterate with to affect the copy without effecting the pointers in the caller. So it would also be perfectly valid to do:
void arithmetic (int *a, int *b, size_t n)
{
if (!a || !b)
return;
for(size_t i = 0; i < n; i++, a++, b++)
*b = (*a + 6) % 10;
}
(good job Pablo with the use of size_t for the length (or number of elements) parameter)
No, your function is not correct.
*arr1 = *((a+i)+6)%10);
You are only writing the values in the first element of the array.
arr1 points to a which already has the values. You want to do the
calculation with a value stored in a and then save it to b, so don't modify
a.
*((a+i+6)%10) is completely wrong. a+i+6 is the same as &a[i+6]. The %10
applies to the value &a[i+6] (which is the address of the i+6th element), and returns a value between 0 and 9 (let's call
it x). When do *(x) you are interpreting the x as a pointer and it
dereferences (=access the value through the pointer) it, but this is not a valid
address at all. You will also eventually access a out of bounds.
*arr2 = *arr1; here you also only storing the values in the first element of arr2.
You function has no name.
int *arr1; arr1=a; this is unnecessary, you can access a directly, no
need to create a copy of the pointer.
The +6 % 10 rule applies to the values stored in the array, not the indices.
The correct function should look like this:
void compute(int *a, int *b, size_t len)
{
if(a == NULL || b == NULL)
return;
for(size_t i = 0; i < len; ++i)
b[i] = (a[i] + 6) % 10;
}
And if your assignment says you should do it with pointer arithmetic instead of
using array indexing:
void compute(int *a, int *b, size_t len)
{
if(a == NULL || b == NULL)
return;
for(size_t i = 0; i < len; ++i)
*(b+i) = (*(a + i) + 6) % 10;
}

Can't sort array without temp variable using pointer

The algorithm to swap the values of two integers x and y without using a tmp variable is
x = x + y;
y = x - y;
x = x - y;
I've written a code to sort an array by passing it to a method. The method accepts the array in a pointer *ptr. Thus, the elements of the array, arr[0], arr[1],... would be accessed with the pointer variable as *(ptr + 0), *(ptr + 1),.... However, the problem I'm facing is that when I try to swap the values of the array while sorting by referencing the memory location with a pointer, without the use of a temporary variable, the array is not getting sorted the way I expect and, instead, I see some random elements getting inserted into the array.
This is my array sorting code (selection sort - the sort algorithm is correct):
void sort(int *arr, int n){
int i,j,m;
for(i=0; i<n-1; i++){
m = i;
for(j=i+1; j<n; j++){
if(arr[j] < arr[m])
m = j;
}
//swapping arr[i] and arr[m]
*(arr + i) = *(arr + i) + *(arr + m);
*(arr + m) = *(arr + i) - *(arr + m);
*(arr + i) = *(arr + i) - *(arr + m);
}
//print the array...
}
void main(){
int arr[] = {2,4,3,5,8,7};
sort(arr, 6);
}
INPUT:
2 4 3 5 8 7
EXPECTED OUTPUT:
2 3 4 5 7 8
OBTAINED OUTPUT:
0 3 0 0 7 8
Why is this happening? What am I doing wrong?
The algorithm to swap the values of two integers x and y without using a tmp variable is
x = x + y;
y = x - y;
x = x - y;
One of several problems with this approach is that it does not work when x and y expressions refer to the same memory location. This is exactly what happens when an item is in its place after completion of the nested loop, i.e. when i is the same as m.
Adding if (i == m) continue before going into the swap will fix this problem.
Demo.

Transferring Fortran multiD arrays to C

I am having issues transferring 3D arrays from Fortran to C. I have variables which represent the size of the array (idim, jdim, kdim) but I am having a tough time writing a C code to receive arrays that have size of these values. I will attach the Fortran & C code I have right now.
FORTRAN:
! Transfer u,v,w to CPU
idim = imax_ - imin_
jdim = jmax_ - jmin_
kdim = kmax_ - kmin_
CALL CUDA(idim,jdim,kdim,u,v,w)
and C:
extern "C" void cuda_(int *idim, int *jdim, int *kdim, float U[*kdim][*jdim][*idim], float V[*kdim][*jdim][*idim], float W[*kdim][*jdim][*idim])
{
I am working on accelerating an already existing code with GPU programming, but am still relatively new to programming, so please take that into consideration.
Thanks in advance!
Why is the function name in the FORTRAN program not the same? I would use the same name in both programs but perhaps this is FORTRAN-related. I will use the C function name you wrote for this answer and yes, I agree that this is quite a task for a beginner. This will not be a complete solution but should steer you in the right direction (hopefully). First... arrays in C have fixed dimensions determined at compile time. So your function declaration will not compile. If your intention is to dereference the dimension pointers in the array dimention parameters, this will not work because it's not executable code; those are parameter declarations used only for compilation.
Second, it seems like you want to pass arrays that can have different dimensions from one call to another or that you don't know in advance how many elements will be in your arrays. Assuming this, you need only pass the address of your arrays (assuming your dimensions are always the right ones). Your function prototype could then be:
void cuda_(int *idim, int *jdim, int *kdim, float *U, float* V, float* W);
Your function could be implemented as follow (so to show you the pointer arithmetic):
void cuda_(int *idim, int *jdim, int *kdim, float* U, float* V, float* W)
{
int i, j, k;
// Assuming you want to process each individual array
// items one after the other; this to show pointer arithmetic
for (i=0; i<*idim; i++) {
for (j=0; j<*jdim; j++) {
for (k=0; k<*kdim; k++) {
// Do whatever with the i,j,kth element;
// We assign unique values so you can check
// that this example accesses the right array elements
*(U + i * sizeof(float) + j * sizeof(float) + k) = i + j + k;
*(V + i * sizeof(float) + j * sizeof(float) + k) = 2*i + 2*j + 2*k;
*(W + i * sizeof(float) + j * sizeof(float) + k) = 3*i + 3*j + 3*k;
}
}
}
return;
}
Of course, you need to test this example thoroughly to make sure that this is what you really intend on doing and that I did map the 3D array properly (I mapped it over a one-dimentional array assuming that this is how it is implemented in your FORTRAN program; otherwise, you will have to come up with the proper pointer arithmitic but the principle will be the same as in the examples). I did very superficial testing of this code and be warned that pointer manipulation is tricky and error prone! Good luck.
Now, and this is of secondary importance but I feel the point should be made. I don't see why you want to pass the array dimensions as pointers; perhaps it's a requirement for FORTRAN (that is maybe you cannot pass parameters by value/copy). If you can pass parameters by copy (as opposed to by reference), then I suggest the following change:
// Prototype:
void cuda_(int idim, int jdim, int kdim, float* U, float* V, float* W);
// Implementation:
void cuda_(int idim, int jdim, int kdim, float* U, float* V, float* W)
{
int i, j, k;
for (i=0; i<idim; i++) {
for (j=0; j<jdim; j++) {
for (k=0; k<kdim; k++) {
*(U + i * sizeof(float) + j * sizeof(float) + k) = i + j + k;
*(V + i * sizeof(float) + j * sizeof(float) + k) = 2*i + 2*j + 2*k;
*(W + i * sizeof(float) + j * sizeof(float) + k) = 3*i + 3*j + 3*k;
}
}
}
}
The easiest way I could figure out to do this was to pass the array as a 1D array. Then in the c function to create new 3D arrays with the proper dimensions and the then fill them using the 1 D arrays that were passed. I set the modified arrays to be referenced in the same way as the FORTRAN array to hopefully make accessing the array easier. I will attach my C solution below:
extern "C" void cuda_(double *ptr_u, double *ptr_v, double *ptr_w, int *nx, int *ny, int *nz)
{
//Creating new arrays for U,V,W
int i,j,k,imax,jmax,kmax,ct=0;
imax = *nx;
jmax = *ny;
kmax = *nz;
double V[imax][jmax][kmax], W[imax][jmax][kmax], U[imax][jmax][kmax];
for (k = 0; k < kmax; k++)
{
for (j = 0; j < jmax; j++)
{
for (i = 0; i < imax; i++)
{
U[i][j][k] = ptr_u[ct];
V[i][j][k] = ptr_v[ct];
W[i][j][k] = ptr_w[ct];
ct++;
}
}
}
If anyone has any comments on this solution, feel free to comment. I'm sure there is a better way of doing this somewhere out there!

Resources