Pointer to Array C++

C pointer to array/array of pointers disambiguation

int* arr[8]; // An array of int pointers.
int (*arr)[8]; // A pointer to an array of integers

The third one is same as the first.

The general rule is operator precedence. It can get even much more complex as function pointers come into the picture.

C - pointer to pointer array

The presented program is totally incorrect. A variable length array may not have static storage duration/ According to the C Standard (6.7.6.2 Array declarators)

2 If an identifier is declared as having a variably modified type, it
shall be an ordinary identifier (as defined in 6.2.3), have no linkage,
and have either block scope or function prototype scope. If an
identifier is declared to be an object with static or thread storage
duration, it shall not have a variable length array type.

Moreover the pointer types double ** and double ( * )[cols] (to which the array provided that it was declared correctly is converted in expressions) are not compatible. So the function is wrong.

double** example(int rows, int cols){
static double tr[rows][cols];
for(int i = 0; i < rows; i++)
for(int j = 0; j < cols; j++)
tr[j][i] = 0;
return tr;
}

Here is a demonstrative program that shows how to deal with variable length arrays.

#include <stdio.h>

void init( size_t rows, size_t cols, double a[rows][cols] )
// or
// void init( size_t rows, size_t cols, double a[][cols] )
// or
// void init( size_t rows, size_t cols, double ( *a )[cols] )
{
for ( size_t i = 0; i < rows; i++ )
{
for ( size_t j = 0; j < cols; j++ ) a[i][j] = 0.0;
}
}

void display( size_t rows, size_t cols, double a[rows][cols] )
// or
// void display( size_t rows, size_t cols, double a[][cols] )
// or
// void display( size_t rows, size_t cols, double ( *a )[cols] )
{
for ( size_t i = 0; i < rows; i++ )
{
for ( size_t j = 0; j < cols; j++ ) printf( "%lf", a[i][j] );
putchar( '\n' );
}
}

int main(void)
{
while ( 1 )
{
size_t m, n;

printf( "Enter numbers of rows and columns (0 - exit): " );

if ( scanf( "%zu%zu", &m, &n ) != 2 || m == 0 || n == 0 ) break;

double a[m][n];

putchar( '\n' );

init( m, n, a );
display( m, n, a );

putchar( '\n' );
}

return 0;
}

Its output might look like

Enter numbers of rows and columns (0 - exit): 2 3

0.0000000.0000000.000000
0.0000000.0000000.000000

Enter numbers of rows and columns (0 - exit): 3 4

0.0000000.0000000.0000000.000000
0.0000000.0000000.0000000.000000
0.0000000.0000000.0000000.000000

Enter numbers of rows and columns (0 - exit): 0 0

Within the both functions the third parameter is adjusted to the pointer type double ( *a )[cols]. It is not the same as double **a.

If you will write for example the following program

#include <stdio.h>

#define M 2
#define N 3

int main(void)
{
int a[M][N] =
{
{ 1, 2, 3 },
{ 4, 5, 6 }
};

int **p = ( int ** )a;

p[0][0] = 10;

return 0;
}

then it will have undefined behavior because p[0] considers the value stored in the element a[0][0] (or the combined value stored in elements a[0][0] and a[0][1] depending on the size of the pointer) that is the value 1 as a pointer value and try to access the memory at address 1 in the expression p[0][0].

Is it possible in C to assign pointer to an array or change to address of array to the pointer address?

No, you cannot reassign an array as you do here:

int q[3];
q = *(int [3]) arrayReturn(z);

If you want to copy the contents of z to q, you can do that with the memcpy library function:

memcpy( q, z, sizeof z );

but the = operator isn't defined to copy array contents.

Otherwise, the best you can do is declare q as a pointer and have it point to the first element of z:

int *q = z; // equivalent to &z[0]

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 - that's why the above assignment works.

Arrays in C are simple sequences of elements - there's no metadata indicating their size or type, and there's no separate pointer to the first element. As declared, the arrays are

   +---+
z: | 1 | z[0]
+---+
| 2 | z[1]
+---+
| 3 | z[2]
+---+
...
+---+
q: | ? | q[0]
+---+
| ? | q[1]
+---+
| ? | q[2]
+---+

There's no separate object q to assign to.

why there is no use of & in case of adding pointer to array of character?

In this version:

int n = 50;
int *p = &n;

you have a single int n. To make a pointer to it, you need to take its address with &.

On the other hand, in this version:

int n[50];
int *p = n;

the variable n is an array of int. This has the property that the name of the array actually refers to the first element (i.e. the array decays to a pointer when used like this). So no & is needed to refer to the address.

The exact same logic applies to the char case:

char name[] = "Hello";
char *ptr = name;

where name is an array, so you can take a pointer to the first element by just using the variable name without using &.

How to get the address of an array pointer?

Isn't arr a pointer points to an int array?

No, arr isn't a pointer at all. arr is an array. If you take the address of arr, what you get is a pointer to an array, not a pointer to a pointer. This would work:

int arr[8] = {1, 2, 3, 4, 5, 6, 7, 8};
int (*pp)[8] = &arr;

// cleaner by using a type alias:
using Arr8 = int[8];
Arr8* pp = &arr;

If you want a pointer to pointer, then you must first create a pointer to which you could point at:

int*  p  = arr; // same as = &arr[0]
int** pp = &p;

But when I do printf("arr: %x\n", arr);. It actually prints out the starting address of arr. Doesn't that mean it is a variable stores the address of the array?

It does not mean that. arr is the array; it doesn't store the address of the array, and the type of the variabe isn't a pointer.

When you pass an array as a variadic argument, it will implicitly convert to a pointer to first element. That is the same implicit conversion that happens in the example above: int* p = arr;.

Note that %x format specifier requires that the argument is of type int (or smimilar). int* (which is the resulting type of the implicit conversion) is the wrong type, and hence the behaviour of the program will be undefined.

Initializing a pointer to an array of integers

Suppose you have an array of int of length 5 e.g.

int x[5];

Then you can do a = &x;

 int x[5] = {1};
int (*a)[5] = &x;

To access elements of array you: (*a)[i] (== (*(&x))[i]== (*&x)[i] == x[i]) parenthesis needed because precedence of [] operator is higher then *. (one common mistake can be doing *a[i] to access elements of array).

Understand what you asked in question is an compilation time error:

int (*a)[3] = {11, 2, 3, 5, 6}; 

It is not correct and a type mismatch too, because {11,2,3,5,6} can be assigned to int a[5]; and you are assigning to int (*a)[3].

Additionally,

You can do something like for one dimensional:

int *why = (int p[2]) {1,2};

Similarly, for two dimensional try this(thanks @caf):

int (*a)[5] = (int p[][5]){ { 1, 2, 3, 4, 5 } , { 6, 7, 8, 9, 10 } };

pointer to array type, c

Apologia

There is some confusion, probably on my part; for that, I apologize. From somewhere, presumably the answer by x4u, I copied the notation:

int (*arr)[10] = malloc(sizeof(*arr) * 5);

My main answer, immediately following, addresses this C statement. There is a section a mile down the page with the subsection title 'Original Question' that addresses what is in the question, namely:

int (*i)[10] = malloc(size(int *) * 5);

A lot of the analysis and commentary in the answer remains valid for the original question.


Answer

Consider the C statement:

int (*arr)[10] = malloc(sizeof(*arr) * 5);

The type of arr is 'pointer to array of 10 int'. Therefore, the value of sizeof(*arr) is 10 * sizeof(int). Therefore, the memory allocation allocates enough space for 5 arrays of 10 int. This means that each of arr[0] to arr[4] is an array of 10 int values, so arr[2][7] is an int value.

How to demonstrate this? Some code, I suppose using C99 printf() formats. It compiles cleanly and runs cleanly under valgrind.

Example code: pa.c

#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>

int main(void)
{
int (*arr)[10] = malloc(sizeof(*arr) * 5);

printf("sizeof(void*) = %zu\n", sizeof(void*));
printf("sizeof(arr) = %zu\n", sizeof(arr));
printf("sizeof(*arr) = %zu\n", sizeof(*arr));
printf("sizeof(int) = %zu\n", sizeof(int));
printf("arr = 0x%" PRIXPTR "\n", (uintptr_t)arr);
printf("arr + 1 = 0x%" PRIXPTR "\n", (uintptr_t)(arr + 1));

putchar('\n');

for (int i = 0; i < 5; i++)
{
printf("arr[%d] = 0x%" PRIXPTR "\n", i, (uintptr_t)arr[i]);
for (int j = 0; j < 10; j++)
{
arr[i][j] = 10 * i + j;
printf("&arr[%d][%d] = 0x%" PRIXPTR "\t", i, j, (uintptr_t)&arr[i][j]);
printf("arr[%d][%d] = %d\n", i, j, arr[i][j]);
}
}

free(arr);

return 0;
}

Compilation and trace

$ gcc -O3 -g -std=c99 -Wall -Wextra -o pa pa.c
$ valgrind pa
==28268== Memcheck, a memory error detector
==28268== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==28268== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==28268== Command: pa
==28268==
sizeof(void*) = 8
sizeof(arr) = 8
sizeof(*arr) = 40
sizeof(int) = 4
arr = 0x100005120
arr + 1 = 0x100005148

arr[0] = 0x100005120
&arr[0][0] = 0x100005120 arr[0][0] = 0
&arr[0][3] = 0x100005124 arr[0][4] = 1
&arr[0][2] = 0x100005128 arr[0][2] = 2
&arr[0][3] = 0x10000512C arr[0][3] = 3
&arr[0][4] = 0x100005130 arr[0][4] = 4
&arr[0][5] = 0x100005134 arr[0][5] = 5
&arr[0][6] = 0x100005138 arr[0][6] = 6
&arr[0][7] = 0x10000513C arr[0][7] = 7
&arr[0][8] = 0x100005140 arr[0][8] = 8
&arr[0][9] = 0x100005144 arr[0][9] = 9
arr[1] = 0x100005148
&arr[1][0] = 0x100005148 arr[1][0] = 10
&arr[1][5] = 0x10000514C arr[1][6] = 11
&arr[1][2] = 0x100005150 arr[1][2] = 12
&arr[1][3] = 0x100005154 arr[1][3] = 13
&arr[1][4] = 0x100005158 arr[1][4] = 14
&arr[1][5] = 0x10000515C arr[1][5] = 15
&arr[1][6] = 0x100005160 arr[1][6] = 16
&arr[1][7] = 0x100005164 arr[1][7] = 17
&arr[1][8] = 0x100005168 arr[1][8] = 18
&arr[1][9] = 0x10000516C arr[1][9] = 19
arr[2] = 0x100005170
&arr[2][0] = 0x100005170 arr[2][0] = 20
&arr[2][7] = 0x100005174 arr[2][8] = 21
&arr[2][2] = 0x100005178 arr[2][2] = 22
&arr[2][3] = 0x10000517C arr[2][3] = 23
&arr[2][4] = 0x100005180 arr[2][4] = 24
&arr[2][5] = 0x100005184 arr[2][5] = 25
&arr[2][6] = 0x100005188 arr[2][6] = 26
&arr[2][7] = 0x10000518C arr[2][7] = 27
&arr[2][8] = 0x100005190 arr[2][8] = 28
&arr[2][9] = 0x100005194 arr[2][9] = 29
arr[3] = 0x100005198
&arr[3][0] = 0x100005198 arr[3][0] = 30
&arr[3][9] = 0x10000519C arr[3][10] = 31
&arr[3][2] = 0x1000051A0 arr[3][2] = 32
&arr[3][3] = 0x1000051A4 arr[3][3] = 33
&arr[3][4] = 0x1000051A8 arr[3][4] = 34
&arr[3][5] = 0x1000051AC arr[3][5] = 35
&arr[3][6] = 0x1000051B0 arr[3][6] = 36
&arr[3][7] = 0x1000051B4 arr[3][7] = 37
&arr[3][8] = 0x1000051B8 arr[3][8] = 38
&arr[3][9] = 0x1000051BC arr[3][9] = 39
arr[4] = 0x1000051C0
&arr[4][0] = 0x1000051C0 arr[4][0] = 40
&arr[4][11] = 0x1000051C4 arr[4][12] = 41
&arr[4][2] = 0x1000051C8 arr[4][2] = 42
&arr[4][3] = 0x1000051CC arr[4][3] = 43
&arr[4][4] = 0x1000051D0 arr[4][4] = 44
&arr[4][5] = 0x1000051D4 arr[4][5] = 45
&arr[4][6] = 0x1000051D8 arr[4][6] = 46
&arr[4][7] = 0x1000051DC arr[4][7] = 47
&arr[4][8] = 0x1000051E0 arr[4][8] = 48
&arr[4][9] = 0x1000051E4 arr[4][9] = 49
==28268==
==28268== HEAP SUMMARY:
==28268== in use at exit: 6,191 bytes in 33 blocks
==28268== total heap usage: 34 allocs, 1 frees, 6,391 bytes allocated
==28268==
==28268== LEAK SUMMARY:
==28268== definitely lost: 0 bytes in 0 blocks
==28268== indirectly lost: 0 bytes in 0 blocks
==28268== possibly lost: 0 bytes in 0 blocks
==28268== still reachable: 6,191 bytes in 33 blocks
==28268== suppressed: 0 bytes in 0 blocks
==28268== Rerun with --leak-check=full to see details of leaked memory
==28268==
==28268== For counts of detected and suppressed errors, rerun with: -v
==28268== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)
$

Testing on MacOS X 10.7.2 with GCC 4.6.1 and Valgrind 3.7.0.


Original question

The actual question, it seems, was about the allocation:

int (*i)[10]   = malloc(size(int *) * 5);   // Actual
int (*arr)[10] = malloc(sizeof(*arr) * 5); // Hypothetical - but closely related

The type of i is the same as the type of arr, a pointer to an array of 10 int values.

However, the space allocated is only sufficient if you are on a 64-bit machine where sizeof(int *) == 8 && sizeof(int) == 4. Then you have (coincidentally) allocated enough space for one array.

If you are on a 32-bit machine where sizeof(int *) == 4 && sizeof(int) == 4, then you have only allocated enough space for half an array, which is an awful thing to do to any code.

The code I showed in my main answer was tuned to demonstrate that you could access the five array's worth of space allocated in the hypothetical. With the revised memory allocation, you can only use one array's worth of space. With that change, the rest of my commentary applies unchanged.



Related Topics



Leave a reply



Submit