Related
An example to illustrate:
#include <stdlib.h>
#include<stdio.h>
void simple_function(int s , int array[][s]);
int main(void){
int x;
/*Static 2D Array*/
int array[2][2];
/*Many Methods to Dynamically Allocate 2D Array....for example*/
/* Using Array of pointers*/
int *array1[2];
for(x=0;x<2;x++){array1[x] = calloc (2, sizeof(int));}
/*Using pointer to a pointer */
int **array2 = calloc (2, sizeof(int*));
for(x=0;x<2;x++){array2[x] = calloc (2, sizeof(int));}
/*Using a single pointer*/
int *array3 = calloc (4 , sizeof(int));
/* Codes To Fill The Arrays*/
/*Passing the Arrays to the function, some of them won't work*/
simple_function(2, array); /*Case 1*/
simple_function(2, array1); /*Case 2*/
simple_function(2, array2); /*Case 3*/
simple_function(2, array3); /*Case 4*/
return 0;
}
void simple_function (int s, int array[][s]){
int x,y;
for(x=0;x<s;x++){
for(y=0;y<s; y++){
printf ("Content is %d\n", array[x][y]);
}
}
}
My Question:
Is there a way to write the signature of the simple_function to let it accepts all cases regardless of the method that the user chose? If not, what is the most preferable for the function if I want to make a library?
You've actually declared two different types of objects, as shown below
Your array and array3 are both stored in memory as 4 contiguous ints. There's no additional information, you've simply reserved space for 4 ints, and the C specification requires that they are contiguous.
However, array1 and array2 are actually pointer arrays. Your code reserves memory for an array of two pointers, and each pointer points to an array of two ints. The ints will be arranged in groups of two, but the groups can be scattered anywhere in memory.
From this, it should be clear that the compiler cannot use the same code to access both types of array. For example, let's say that you're trying to access the item at array[x][y]. With a contiguous array, the compiler computes the address of that item like this
address = array + (x * s + y) * sizeof(int)
With a scattered array, the compiler computes the address like this
pointer = the value at {array + x * sizeof(int *)}
address = pointer + y * sizeof(int)
So you need two functions to handle those two cases. For the contiguous array, the function looks like this
void showContiguousArray( int s, int array[][s] )
{
for ( int x=0; x<s; x++ )
for ( int y=0; y<s; y++ )
printf( "array[%d][%d] = %d\n", x, y, array[x][y] );
}
For the scattered array, the function is
void showScatteredArray( int s, int **array )
{
for ( int x=0; x<s; x++ )
for ( int y=0; y<s; y++ )
printf( "array[%d][%d] = %d\n", x, y, array[x][y] );
}
Notice that those functions are identical, except for one thing, the type of the array argument. The compiler needs to know the type in order to generate the correct code.
If the array is declared in the same scope where it's used, then all of these details are hidden, and it seems that you're using the exact same code to access different types of arrays. But that only works because the compiler knows the type of the array from the earlier declaration. But if you want to pass the array to a function, then the type information must be explicitly specified in the function declaration.
Is there a way to write the signature of the simple_function to let it accepts all cases regardless of the method that the user chose?
"All the cases" apparently describes the different declarations array, array1, array2, and array3, the latter three of which are described in code comments as "Methods to Dynamically Allocate 2D Array." But none of the four types are the same as any of the others, and none of the latter three in fact declare 2D arrays nor pointers to such. None of them are even compatible with each other. Of the dynamic ones, only array3 can even usefully be converted to something comparable to array.
A dynamically-allocated 2D array would be referenced via a pointer of this type:
int (*array4)[2];
array4 = calloc(2 * sizeof(*array4));
So, no.
If not, what is the most preferable for the function if I want to make a library?
It depends on your objectives. If your function must be compatible with static 2D arrays, then something of the general form you presented, plus or minus the variable dimension, is the only alternative. If you want to support the pointer-to-pointer form, then that's fine, and usable with declarations like array1's and array2's, but not with array, array3, or array4.
Assuming that you want this for 2D arrays, perhaps this can get you started ...
void simple_function(int s, int t , int* array) {
int i, j;
for (i=0; i<s; i++) {
for (j=0; j<t; j++) {
// accessing your array elements
printf(" %d", *(array + i*t + j));
}
printf("\n");
}
}
int main(void)
{
int array[2][3];
array[0][0] = 1;
array[0][1] = 2;
array[0][2] = 3;
array[1][0] = 11;
array[1][1] = 12;
array[1][2] = 13;
array[2][0] = 21;
array[2][1] = 22;
array[2][2] = 23;
simple_function(3, 3 , array);
return 0;
}
The expression int **array2 is not a 2D array by the way, it is a variable that holds the address of a pointer variable.
I recently started programming C just for fun. I'm a very skilled programmer in C# .NET and Java within the desktop realm, but this is turning out to be a bit too much of a challenge for me.
I am trying to do something as "simple" as returning a two-dimensional array from a function. I've tried researching on the web for this, but it was hard for me to find something that worked.
Here's what I have so far. It doesn't quite return the array, it just populates one. But even that won't compile (I am sure the reasons must be obvious to you, if you're a skilled C programmer).
void new_array (int x[n][n]) {
int i,o;
for (i=0; i<n; i++) {
for (o=0; o<n; o++) {
x[i][o]=(rand() % n)-n/2;
}
}
return x;
}
And usage:
int x[n][n];
new_array(x);
What am I doing wrong? It should be mentioned that n is a constant that has the value 3.
Edit: Here's a compiler error when trying to define the constant: http://i.imgur.com/sa4JkXs.png
C does not treat arrays like most languages; you'll need to understand the following concepts if you want to work with arrays in C.
Except when it is the operand of the sizeof or unary & operator, or is a string literal being used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("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. This result is not an lvalue; it cannot be the target of an assignment, nor can it be an operand to the ++ or -- operators.
This is why you can't define a function to return an array type; the array expression will be converted to a pointer type as part of the return statement, and besides, there's no way to assign the result to another array expression anyway.
Believe it or not, there's a solid technical reason for this; when he was initially developing C, Dennis Ritchie borrowed a lot of concepts from the B programming language. B was a "typeless" language; everything was stored as an unsigned word, or "cell". Memory was seen as a linear array of "cells". When you declared an array as
auto arr[N];
B would set aside N "cells" for the array contents, along with an additional cell bound to arr to store the offset to the first element (basically a pointer, but without any type semantics). Array accesses were defined as *(arr+i); you offset i cells from the address stored in a and dereferenced the result. This worked great for C, until Ritchie started adding struct types to the language. He wanted the contents of the struct to not only describe the data in abstract terms, but to physically represent the bits. The example he used was something like
struct {
int node;
char name[14];
};
He wanted to set aside 2 bytes for the node, immediately followed by 14 bytes for the name element. And he wanted an array of such structures to be laid out such that you had 2 bytes followed by 14 bytes followed by 2 bytes followed by 14 bytes, etc. He couldn't figure out a good way to deal with the array pointer, so he got rid of it entirely. Rather than setting aside storage for the pointer, C simply calculates it from the array expression itself. This is why you can't assign anything to an array expression; there's nothing to assign the value to.
So, how do you return a 2D array from a function?
You don't. You can return a pointer to a 2D array, such as:
T (*func1(int rows))[N]
{
T (*ap)[N] = malloc( sizeof *ap * rows );
return ap;
}
The downside to this approach is that N must be known at compile time.
If you're using a C99 compiler or a C2011 compiler that supports variable-length arrays, you could do something like the following:
void func2( size_t rows, size_t cols, int (**app)[cols] )
{
*app = malloc( sizeof **app * rows );
(*app)[i][j] = ...; // the parens are necessary
...
}
If you don't have variable-length arrays available, then at least the column dimension must be a compile-time constant:
#define COLS ...
...
void func3( size_t rows, int (**app)[COLS] )
{
*app = malloc( sizeof **app * rows );
(*app)[i][j] = ...;
}
You can allocate memory piecemeal into something that acts like a 2D array, but the rows won't necessarily be contiguous:
int **func4( size_t rows, size_t cols )
{
int **p = malloc( sizeof *p * rows );
if ( p )
{
for ( size_t i = 0; i < rows; i++ )
{
p[i] = malloc( sizeof *p[i] * cols );
}
}
return p;
}
p is not an array; it points to a series of pointers to int. For all practical purposes, you can use this as though it were a 2D array:
int **arr = foo( rows, cols );
...
arr[i][j] = ...;
printf( "value = %d\n", arr[k][l] );
Note that C doesn't have any garbage collection; you're responsible for cleaning up your own messes. In the first three cases, it's simple:
int (*arr1)[N] = func(rows);
// use arr[i][j];
...
free( arr1 );
int (*arr2)[cols];
func2( rows, cols, &arr2 );
...
free( arr2 );
int (*arr3)[N];
func3( rows, &arr3 );
...
free( arr3 );
In the last case, since you did a two-step allocation, you need to do a two-step deallocation:
int **arr4 = func4( rows, cols );
...
for (i = 0; i < rows; i++ )
free( arr4[i] )
free( arr4)
Your function return void, so the return x; line is superfluous. Aside from that, your code looks fine. That is, assuming you have #define n 3 someplace and not something like const int n = 3;.
You can't return an array in C, multidimensional or otherwise.
The main reason for this is that the language says you can't. Another reason would be that generally local arrays are allocated on the stack, and consequently deallocated when the function returns, so it wouldn't make sense to return them.
Passing a pointer to the array in and modifying it is generally the way to go.
To return (a pointer to) a newly-created array of dimensions known at compile time, you can do this:
#define n 10 // Or other size.
int (*new_array(void))[n]
{
int (*x)[n] = malloc(n * sizeof *x);
if (!result)
HandleErrorHere;
for (int i = 0; i < n; ++i)
for (int o = 0; i < n; ++o)
x[i][o] = InitialValues;
return x;
}
…
// In the calling function:
int (*x)[n] = new_array();
…
// When done with the array:
free(x);
If the size is not known at compile time, you cannot even return a pointer to an array. C does support variable-length arrays but not in the return types of functions. You could instead return a pointer to a variable-length array through a parameter. That requires using a parameter that is a pointer to a pointer to an array of variable length, so it gets somewhat messy.
Also, the preferred choices between allocating an array in the caller dynamically, allocating an array in the caller automatically, allocating an array in the called function dynamically and using variable-lengths arrays or fixed-length arrays or even one-dimensional arrays with manual indexing depend on context, including what how large the array might be, how long it will live, and what operations you intend to use it for. So you would need to provide additional guidance before a specific recommendation could be made.
In C there's only pass/return by value (no pass by reference). Thus the only way of passing the array (by value) is to pass its address to the function, so that it can manipulate it through a pointer.
However, returning by value an array's address isn't possible, since by the time control reaches the caller, the function goes out of scope and its automatic variables go down with it too. Hence if you really have to, you can dynamically allocate the array, populate and return it, but the preferred method is passing the array and leaving the onus of maintaining the array to the caller.
As for the error, the only warning I get in GCC for this is warning: 'return' with a value, in function returning void which is simply meaning that you shouldn't return anything from a void function.
void new_array (int x[n][n]); what you're really doing here is taking a pointer to an array of n integers; the decayed type is int (*x)[n]. This happens because arrays decay into pointers generally. If you know n at compile time, perhaps the best way to pass is:
#define n 3
void new_array (int (*x)[n][n]) {
int i,o;
for (i=0; i<n; i++) {
for (o=0; o<n; o++) {
x[i][o]=(rand() % n)-n/2;
}
}
}
And call it as
int arr[n][n];
new_array(&arr);
You can pass around arbitrarily dimensions arrays like any another variable if you wrap them up in a struct:
#include <stdio.h>
#define n 3
struct S {
int a[n][n];
};
static struct S make_s(void)
{
struct S s;
int i, j;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++)
s.a[i][j] = i + j;
}
return s;
}
static void print_s(struct S s)
{
int i, j;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++)
printf(" %d", s.a[i][j]);
printf("\n");
}
}
int main(void) {
struct S s;
s = make_s();
print_s(s);
return 0;
}
You are probably declaring n as a constant integer:
const int n = 3;
Instead, you should define n as a preprocessor definition:
#define n 3
So, I was reading about pointers, and came across the concept of pointers to arrays. The thing is that a pointer to an array doesn't really seem useful at all, since instead of using a pointer to have an offset to access an array element, I could just get the element directly. However I feel as if I'm missing the reason why these can be useful.
So, in short, What is the point of pointers to arrays; How and why should they be used, and do they have any practical applications?
Edit: I meant this in the context of normal/simple arrays such as:
int array[5];
Edit: As Keith Pointed out, I'm specifically asking about pointers to arrays, for example char (*ptr)[42] which is a pointer to a 42-element array of char.
Unfortunately some answers you received show misbeliefs about pointers and arrays in C, in brief:
1) Pointer to array is not the same as pointer to first element.
2) Declaring array type is not the same as declaring pointer.
You can found full description in C faq part related to common confusion between pointers and arrays: http://c-faq.com/aryptr/index.html
Adressing your question - pointer to array is usefull to pass an entire array of compile-time known size and preserve information about its size during argument passing. It is also usefull when dealing with multi dimensional arrays when you what to operate on subarray of some array.
In most expressions, an object of type "array of T" will degrade to the address of the first array element, which will have the type "pointer to T". In this sense, a pointer type can be used to represent an array of items, and is used to do so when there is need to dynamically allocate an array.
// ptr used to dynamically allocate array [n] of T
T *ptr = malloc(n * sizeof(*ptr));
In the case of a pointer to an array, then, it can be used to represent an array of arrays, and/or dynamically allocate an array of arrays. So, a pointer to an array can be used to represent a 2-dimensional array.
// ptr used to dynamically allocate 2 dimensional array [n][10] of T
T (*ptr)[10] = malloc(n * sizeof(*ptr));
True pointers to arrays (which haven't really been addressed so far) are uncommon since arrays decay to a pointer to their first element in most contexts, and since arrays are contiguous in memory by definition that is usually all that is needed. They are also somewhat impractical compared to other pointer types since array types cannot be assigned to. They are similar to function pointers in that respect.
The biggest practical difference comes from the fact that they preserve the size of the array in situations where it would otherwise be lost to pointer decay, such as function calls and returns. Take the following code for example
void function(char (*array)[10]) {
for(size_t i = 0; i < sizeof(*a); i++);
(*a)[i] = i;
}
...
char a[10];
function(&a);
Besides allowing for this application of sizeof (which isn't terribly useful since the size is known as part of the parameter), this enforces the exact size of the passing argument as part of the type, which function(char array[10]) won't do, even with [static 10].
Returning has an unusual syntax:
char (*function(void))[10] {
static char array[10];
// do something with our static array
return &array;
}
char (*a)[10] = function();
// or even
char (*b)[sizeof(*function())] = function();
I don't think I've ever come across an application of this in the wild, but it is at least possible (and legal).
If you have an array of arrays a pointer to an array becomes useful, like in the following:
typedef float Point[3];
Point points[10];
Point *p;
for (p=points;p<points+10;++p) {
...
}
Here is real-world example of using pointers to arrays:
typedef double t_matrix33[3][3];
// Result = AB
// const double (* M1)[3], const double (* M2)[3], double (* Result)[3]
void Matrix33xMatrix33( const t_matrix33 M1, const t_matrix33 M2, t_matrix33 Result ) {
t_matrix33 copy;
const t_matrix33 * A = ( const t_matrix33 * )M1; // const double (* A)[3][3] = const double (* M1)[3]
const t_matrix33 * B = ( const t_matrix33 * )M2; // const double (* B)[3][3] = const double (* M2)[3]
int Raw;
int Col;
int i;
// !!! Make copies if Result is the same as M1 and/or M2!
//const double (* A)[3][3] == double (* Result)[3]
if( A == ( const t_matrix33 * )Result ) { // cast is must -- to get rid of gcc warnings
memcpy( copy, A, sizeof( t_matrix33 ) );
A = ( const t_matrix33 * )copy;
if( B == ( const t_matrix33 * )Result ) {
B = ( const t_matrix33 * )copy;
}
}
else if( B == ( const t_matrix33 * )Result ) {
memcpy( copy, B, sizeof( t_matrix33 ) );
B = ( const t_matrix33 * )copy;
}
for( Raw = 0; Raw < 3; ++Raw ) {
for( Col = 0; Col < 3; ++Col ) {
Result[ Raw ][ Col ] = 0;
for( i = 0; i < 3; ++i ) {
Result[ Raw ][ Col ] += (*A)[ Raw ][ i ] * (*B)[ i ][ Col ];
}
}
}
};
Thanks to A and B pointers we can avoid redundant memcopies in the case of M1 and/or M2 are not the same as Result
The one I can think of at the moment is (I am sure there are others as well), you want to make multidimensional array, however you don't have any data at the moment to save in the 2nd or 3rd dimension of the array. You don't want to waste the memory by conserving the space for 2nd and 3rd dimension of the array but you plan to allocate the memory later when you have data to store, thats when pointers to arrays come handy.
Eg.
for (int i=0; i<10; i++)
(*x)[i] = malloc(N * sizeof(*x));
// take input or put data in the array
Representation Of 2d Array In C:
This site explains it quite well. This should help you removing any confusions.
Im relatively knew to C, i am used to program in Java so i find C a little bit difficult in what concerns arrays. I still cofuse myself with this cases:
int a [];
int* a;
int *a;
In java, i would do something like this to return an array in a function:
int [] returnArr(int [] a){
... modify a ...
return a;
}
int [] a = {...};
int [] b = returnArr(a); ##
How can i do the same in C, specially the parts with ##.
EDITED:
I have this function:
float *normalizeValues(float *v, float maxY){
int size = sizeof(v) / sizeof(float);
float max = findMax(v);
float ratio = maxY / max;
int i;
for(i = 0; i < size ; ++i){
v[i] = v[i] * ratio;
}
return v;
}
And im doing the following:
float vert [] = {306, 319, 360, 357, 375, 374, 387, 391, 391, 70, 82, 94, 91, 108, 114, 125, 127, 131};
int i = 0;
float *vert2;
vert2 = normalizeValues(vert, 0.7);
for(i = 0; i < sizeof(vert2) / sizeof(float); ++i){
fprintf(stdout,": %f\n",vert2[i]);
}
And the output is only 1 element.
EDIT: To directly answer your updated question: you have to pass in the size of the array. C has no mechanism to store the size of arrays like Java does. If the compiler knows about the size of the array because the array is a global or local variable, not dynamically allocated, then you can use the sizeof() operator. Otherwise, you have to know the size separately, or use sentinel values in your array (such as a 0.0 at the end, or a NULL).
As for arrays, pointers and arguments in general, see below:
You will be returning a pointer to the array, which is indicated with the '*' syntax:
int *returnArr(int[] a) {
// modify a...
return a;
}
int a[] = { ... };
int *b;
b = returnArr(a);
A few things to note:
You can't do assignments in variable declarations that involve non-constant expressions (e.g., function calls). This might have changed in C99, though.
The brackets go after the variable name, unlike in Java where they are part of the type. Even though Java's syntax is more consistent, it doesn't quite make sense in C where you often give the array size in the brackets in the variable declaration:
int a[3] = { ... };
There's no way to specify that a function returns an array as opposed to a plain pointer. In C, array references decay to pointers (though pointers and arrays are NOT the same thing, as is commonly claimed). That means that whenever you pass an array around, C only provides a means to a pass a pointer to the array. The whole array isn't actually copied. As it happens, the name of the array is also a pointer to the first element of the array.
Please also take note of what user268396 says in their answer. If you are planning to create a new array and return it, you'll need to either allocate the array dynamically, or have a pointer to an already allocated array be passed in (which is what it seems like you are kind of doing anyway).
You can't. When the function returns the stack frame will be wiped out (typically) and your generated array will be clobbered by that. You can however edit the function prototype to accept a pointer to the array to modify. That kind of function argument is known as an "output parameter". Example:
void function func(int a, int b, int[2] to_modify)
{
to_modify[0] = a;
to_modify[1] = b;
}
int main()
{
int foo[2];
func(1, 2, foo);
printf("Result: foo[0] = %d, foo[1] = %d\n", foo[0], foo[1]);
return 0;
}
This will print "Result: foo[0] = 1, foo[1] = 2".
Hope this helps
#include<stdio.h>
void change(int *c)/*Pointer c now has the first location of the array a[]*/
{
*(c+0) = 0;/*assign values to the array by adding step-size to the first array position*/
*(c+1) = 1;
*(c+2) = 2;
*(c+3) = 3;
*(c+4) = 4;
}
main()
{
int a[5]={10,20,30,40,50}; /* Declare and Assign an array a[] of size 5.*/
int *b = a; /*Declare and assign a Pointer to the location of the array.*/
change(b); /*pass the pointer(which is now pointing to first position of array) to the change() function.*/
printf("%d,%d,%d,%d,%d,",a[0],a[1],a[2],a[3],a[4]);/*Print the changed value.*/
}
Output: 0,1,2,3,4,
From Java point of view, Pointers are simply like(not exactly) Object references.
Object O;
O = New SomeClassName();
Like Object Reference O is pointing to some Actual Object of type SomeClassName, so does pointers in C:
int *b;
b = &a;
Variable b is simply pointing to the address location to a.
Taking a deep dive into array concepts:
int a[5];
int *b = a;
Here we are just saying like Mr.*b point to the first location of group a i.e. a[0].
Now the power pointer in C is that from now on, here after:
*b means a[0]
*(b+1) means a[1]
*(b+2) means a[2]
*(b+3) means a[3]
*(b+4) means a[4]
This means you change in *(b+4), you're changing a[4].
int* returnArr(int a[]){
//modify a
return a;
}
One need mention is when you use an array in the parameter list of a function, it will be converted into a pointer. So in main(...)'s declaration, char *argv[] and char **argv are actually same. In this case, int a[] and int* a are same. But array and pointer is not the same thing.
Take the following code as an example:
int a[10];
int main(){
int *p = a;
p[5] = 4;
return p[5];
}
p is a pointer, when we access p[i], note that the address of p is not the address of a, the content of p is the address of a. Then the code will:
access the memory to get the content of p, i.e. the address of a.
compute the offset based on i and type of the pointer(int).
access the memory to get the result.
a is an array of int, if we access a[i], the address of a is just the address of a[0], the code will:
Compute the offset based on i and the type int.
Access the memory.
Pointer and array are different types. So if you declare int *p in one file and use it in that file, but define the p as an array in another file, that will cause problem.
You may also wonder about int *p = a, in ANSI, if you use an array(its name) as an expression, the compiler will convert it into a pointer, pointing to the very first element of the array.
Update based on Jim Balter's comments:
If you use an array(its name) as an expression, the compiler will not always convert it into a pointer, pointing to the very first element of the array. For instance, in sizeof(p->q->a), p->q->a is an expression but if a is an array it isn't converted into a pointer.
"Except when it is the operand of the sizeof operator or the unary &
operator, or is a string literal used to initialize an array, an
expression that has type ‘‘array of type’’ is converted to an
expression with type ‘‘pointer to type’’ that points to the initial
element of the array object.
In C, you can only return a pointer of an array in a function.
For example, if you want to return a string(array of char) in a function, you can return a pointer to a null-ended string. If you want to return an array of some other type(int, user-defined struct, etc), you can alloc some memory to store the array, and return the pointer of the array, return the size of the array in the parameter.
example:
int *function(int *size)
{
*size = 10;
int *intP = (int *)malloc((*size)*sizeof(int));
return intP;
}
Please consider the following 2-D Array:
int array[2][2] = {
{1,2},
{3,4}
};
As per my understanding:
- 'array' represents the base address of the 2-D array (which is the same as address of the first element of the array, i.e array[0][0]).
The actual arrangement of a 2-D Array in memory is like a large 1-D Array only.
Now, I know that base address = array. Hence, I should be able to reach the Memory Block containing the element: array[0][0].
If I forget about the 2-D array thing & try to treat this array as a simple 1-D array:
array[0] = *(array+0) gives the base address of the first array & NOT the element array[0][0]. Why?
A 2-D array does not store any memory address (like an Array of Pointers).
If I know the base address, I must be able to access this memory as a linear 1- Dimensional Array.
Please help me clarify this doubt.
Thanks.
array[0] is a one-dimensional array. Its address is the same as the address of array and the same as the address of array[0][0]:
assert((void*)&array == (void*)&(array[0]));
assert((void*)&array == (void*)&(array[0][0]));
Since array[0] is an array, you can't assign it to a variable, nor pass it to a function (if you try that, you'll be passing a pointer to the first element instead). You can observe that it's an array by looking at (array[0])[0] and (array[0])[1] (the parentheses are redundant).
printf("%d %d\n", (array[0])[0], (array[0])[1]);
You can observe that its size is the size of 2 int objects.
printf("%z %z %z\n", sizeof(array), sizeof(array[0]), sizeof(array[0][0]));
Here's a diagram that represents the memory layout:
+-------------+-------------+-------------+-------------+
| 1 | 2 | 3 | 4 |
+-------------+-------------+-------------+-------------+
`array[0][0]' `array[0][1]' `array[1][0]' `array[1][1]'
`---------array[0]---------' `---------array[1]---------'
`-------------------------array-------------------------'
"Thou shalt not fear poynter arythmethyc"...
int array[2][2] = { { 1, 2}, { 3, 4 } };
int *ptr = (int *)&array[0][0];
int i;
for (i = 0; i < 4; i++) {
printf("%d\n", ptr[i]);
}
Why does this work? The C standard specifies that multidimensional arrays are contigous in memory. That means, how your 2D array is arranged is, with regards to the order of its elements, is something like
array[0][0]
array[0][1]
array[1][0]
array[1][1]
Of course, if you take the address of the array as a pointer-to-int (int *, let's name it ptr), then the addresses of the items are as follows:
ptr + 0 = &array[0][0]
ptr + 1 = &array[0][1]
ptr + 2 = &array[1][0]
ptr + 3 = &array[1][1]
And that's why it finally works.
The actual arrangement of a 2-D Array in memory is like a large 1-D Array only.
yes, the storage area is continuous just like 1D arrary. however the index method is a little different.
2-D[0][0] = 1-D[0]
2-D[0][1] = 1-D[1]
...
2-D[i][j] = 1-D[ i * rowsize + j]
...
If I forget about the 2-D array thing & try to treat this array as a simple 1-D array: array[0] = *(array+0) gives the base address of the first array & NOT the element array[0][0]. Why?
the *(array+0) means a pointer to a array. the first element index in such format should be *((*array+0)+0).
so finally it should be *(*array)
A 2-D array does not store any memory address (like an Array of Pointers).
of course, you can . for example ,
int * array[3][3] ={ null, };
If I know the base address, I must be able to access this memory as a linear 1- Dimensional Array.
use this formal 2-D[i][j] = 1-D[ i * rowsize + j]...
Arrays are not pointers.
In most circumstances1, an expression of type "N-element array of T" will be converted ("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 type of the expression array is "2-element array of 2-element array of int". Per the rule above, this will decay to "pointer to 2-element array of int (int (*)[2]) in most circumstances. This means that the type of the expression *array (and by extension, *(array + 0) and array[0]) is "2-element array of int", which in turn will decay to type int *.
Thus, *(array + i) gives you the i'th 2-element array of int following array (i.e., the first 2-element array of int is at array[0] (*(array + 0)), and the second 2-element array of int is at array[1] (*(array + 1)).
If you want to treat array as a 1-dimensional array of int, you'll have to do some casting gymnastics along the lines of
int *p = (int *) array;
int x = p[0];
or
int x = *((int *) array + 0);
1. The exceptions are when the array expression is an operand of the sizeof or unary & operators, or is a string literal being used to initialize another array in a declaration.
I like H2CO3's answer. But you can also treat the pointer to the array as an incrementable variable like so:
int array[2][2] = { { 1, 2}, { 3, 4 } };
int *ptr = (int *)array;
int i;
for (i = 0; i < 4; i++)
{
printf("%d\n", *ptr);
ptr++;
}
the ++ operator works on pointers just fine. It will increment the pointer by one address of it's type, or size of int in this case.
Care must always be used with arrays in c, the following will compile just fine:
int array[2][2] = { { 1, 2}, { 3, 4 } };
int *ptr = (int *)array;
int i;
for (i = 0; i < 100; i++) //Note the 100
{
printf("%d\n", *ptr);
ptr++;
}
This will overflow the array. If you are writing to this you can corrupt other values in the program, including the i in the for loop and the address in the pointer itself.