In C we have two dimensional arrays, i.e. a[m][n].
In one dimensional arrays a is a pointer to the start of the array.
What about two dimensional arrays? Does a[i] hold a pointer to the start of the i row in an array? And thus a[i] is an array of pointers that is passed to a function in the following matter function(int **a, m, n)?
Does a[i] hold a pointer to the start of the i row in an array?
No. The data of a 2D array in C is a contiguous block of elements plus some clever indexing access. But a 2D array is an array of arrays, not an array of pointers.
Formally, the a[i] holds a 1D array. This may decay to a pointer to the first element of the ith row in certain contexts, but its type is still T[n], for some type T that you have not specified.
In one dimensional arrays a is a pointer to the start of the array.
Not correct. a is an array. When you use a in an expression, it "decays" into a pointer to the first element. To better understand this, read this chapter of the C FAQ, particularly this one.
What about two dimensional arrays? Does a[i] hold a pointer to the start of the i row in an array?
No. In a 2D array, a[i] is an array, while int a[x][y]; is an array of arrays. There are no pointers anywhere.
You might be confused because C allows this syntax: int a[][N] = ...;, but that syntax merely means that the size of the array of arrays depends on the number of items in the initialization list.
Related
I just discovered zero-length arrays and I'd like to use it for a 2d array, the advantage of these arrays is to avoid pointers inside a structure so we can just free the structure instead of having to free it's data, so it can better be used inside a container structure like a linked list for example without having to pass a destructor function, but the problem is I can't figure out how to use it for 2d arrays. I have a structure looking like this:
struct s_arg
{
int argc;
char argv[0][0];
};
But the problem is: how to keep track of each member size without another array containing sizes? Is this possible to do this with no malloc for struct members ?
No.
The only reason an array can be used with no size known is because you do not need to know the size in order to access elements. Given an array a, a[0] is at the start of the array, a[1] is one element beyond that, and so on. The location of any element a[i] can be computed without knowing the size of the array.
Naturally, for an array to exist, somebody has to allocate memory for it, and so they must know the size. So the creator of an array must know its size, but the user does not need to.
GCC allows zero-length arrays as an extension so that a structure can have an array at its end, where the memory is allocated by the creator of the structure, who knows its size. Except to support old software, this extension became unnecessary once the C standard supported arrays of unknown size (declared with no size, [], called flexible array members).
For two-dimensional arrays, the ability to use an array without knowing its size does not apply. Given a two-dimensional array of char named a, a[i][j] is located j elements after the start of a[i]. Each of those elements is a char, so calculating j char beyond a[i] is easy. And a[i] starts i elements after the start of a. But the elements of a are arrays of char. To know how big i elements is, you must know the size of the element; you must know the size of the array of char.
So a two-dimensional array cannot be used unless the size of the second dimension is known.
There are ways to use a two-dimensional array whose second-dimension size is known at run-time, including:
Use a one-dimensional array and calculating indices into it manually, as with a[i*size + j].
Use a one-dimensional array and convert its address. For example, from some structure s with member m, (char (*)[size]) s.m, which can then be used as ((char (*)[size]) s.m)[i][j]. (See other Stack Overflow questions and answers for language-lawyer issues about treating one-dimensional arrays as two-dimensional arrays.)
Also, your member name argv suggests you might want this structure to store command-line arguments passed as a parameter of main. If so, you should be mindful that the argv second parameter of main is a pointer to pointers, not a pointer to an array. The data in those strings is generally not arranged in memory for use as a two-dimensional array of char. You could copy the strings into a two-dimensional array, but that would generally be wasteful.
Can I look at a two dimensional array as a one dimensional array of pointers, which the j index is a pointer to the array of the j row of the matrix?
For example if I have an array[4][4]. Is arr[2] the pointer to the second row array?
No. The data is continuous in memory.
arr[2] would know the size of a single array and add 2 times that to the array pointer to get to the appropriate offset.
I may be true... It is the case if you allocated it that way : How do I work with dynamic multi-dimensional arrays in C?. However, the best way to go may to use something like &arr[2][0]. Bye, Francis
Can I look at a two dimensional array as a one dimensional array of pointers, which the j index is a pointer to the array of the j row of the matrix?
Yes. But always remember that arrays are not pointers. In case of 2D array array[M][N], spaces are allocated for each of the array element array[i] (i is int here). But in case of array of pointers *array[M], you need to allocate space for each element of array.
For example if I have an array[4][4]. Is arr[2] the pointer to the second row array?
Yes. arr2 decays to the pointer to the row 2
I often use to memorize all matrixes in a single vector, because my book says it's faster to use a single vector.And the access to a matrix is slower in time.
If I have a code like this one:
int main(int argc, char **argv)
{
int mat[10][10],i;
for(i=0;i<10;i++)
mat[i][0]=99;
int *ptr=&mat[0][0];
for(i=0;i<10;i++)
{
printf("%d\n",*ptr);
ptr+=10;
}
return 0;
}
I tried to run it 4/5 times and all times prints 10 times 99.
So also matrixes are memorized in contigous positions of memory? Always?
If yes, why the access to a vector is faster?
If by 'matrix' you mean two-dimensional array, then yes they're in contiguous memory. 2D arrays in C are just arrays of arrays (row major). If by vector you mean 1D array, then there's no reason it should be faster than accessing a 2D array.
Well, arrays (in C) are stored in contiguous memory, and since that your mat is array of arrays, it also stored in a contiguous memory. I think that dereferencing by one index (when you have some separating 1D arrays) may be a little faster than dereferencing by two indexes (in matrix), but the difference is too small to worry about.
C has no multidimensional arrays like in other languages, it called them multidimensional but they are really arrays of arrays.
And C arrays are contiguous.
(C99, 6.2.5p20) "An array type describes a contiguously allocated nonempty set of objects with a particular member object type, called the element type."
Can anyone provide me with a formula so that I can understand the memory representation of an n-dimensional(n>=2) array like this "How_are_two-dimensional_arrays_represented_in_memory"?
This calculation is applicable for 2D-arrays only.
How to calculate, suppose, a 5D array?
Ok....
I think I found the answer: Array_data_structure#Two-dimensional_arrays
A 2-dimensional array in C is nothing more or less than an array of arrays. A 3-dimensional array is an array of arrays of arrays. And so on.
The relevant section from the C99 standard is 6.5.2.1, "Array subscripting":
Successive subscript operators designate an element of a
multidimensional array object. If E is an n-dimensional array
(n ≥ 2) with dimensions i × j × . . . × k, then E (used as
other than an lvalue) is converted to a pointer to an (n −
1)-dimensional array with dimensions j × . . . × k. If the unary *
operator is applied to this pointer explicitly, or implicitly as a
result of subscripting, the result is the pointed-to (n −
1)-dimensional array, which itself is converted into a pointer if used
as other than an lvalue. It follows from this that arrays are stored
in row-major order (last subscript varies fastest).
Some confusion is caused by the fact that the indexing operator is defined in terms of pointer arithmetic. This does not imply that arrays are "really pointers" -- and in fact they very definitely are not. Declaring an array object does not create any pointer objects at all (unless of course it's an array of pointers). But an expression that refers to the array usually (but not always) "decays" to a pointer to the array's first element (that's a pointer value, not a pointer object).
Now simple array objects, of however many dimensions, are quite inflexible. Prior to C99, all array objects had to be of a fixed size determined at compile time. C99 introduced variable-length arrays (VLAs), but even so a VLA's size is fixed when it's declared (and not all compilers support VLAs, even 12 years after the C99 standard was issued).
If you need something more flexible, a common approach is to declare a pointer to the element type, and then allocate an array using malloc() and have the pointer point to the array's first element:
int *ptr = malloc(N * sizeof *ptr);
if (ptr == NULL) /* handle allocation failure */
This lets you refer to elements of the heap-allocated array using the same syntax you'd use for a declared fixed-size array object, but in arr[i] the expression arr decays to a pointer, whereas in ptr[i] `ptr is already a pointer.
The same thing can be extended to higher dimensions. You can allocate an array of pointers, and then initialize each pointer to point to the beginning of an allocated array of whatever.
This gives you something that acts very much like a 2-dimensional (or more) array, but you have to manage the memory yourself; that's the price of the greater flexibility.
Strictly speaking, this is not a 2-dimensional array. A 2-dimensional array, as I said above, is only an array of arrays. It's probably not entirely unreasonable to think of it as a 2-D array, but that conflicts with the usage in the C Standard; it's similar to referring to a linked list as a 1-D array.
The comp.lang.c FAQ is a good resource; section 6, which covers arrays and pointers, is particularly excellent.
A 2 dimensional array is really an array of pointers to arrays. A 2-dimensional array of integers a[i][j] will take up i*sizeof(int*) for the array of pointers, and i*j*sizeof(int) for the final array.
A 3-D array a[i1][i2][i3] is an array of pointers to arrays of pointers to arrays. The first level of arrays contains i1 pointers, the second level contains i1*i2 pointers, the third level contains i1*i2*i3 integers.
In general, an N-dimensional array with sizes i1..iN will have N-1 levels of arrays of pointers and 1 level of arrays of ints. The arrays in level N have length iN and there are product of i1..iN-1 arrays in that level.
So, a 5-D array:
1 array, length i1, of pointers
i1 arrays, length i2, of pointers
i1*i2 arrays, length i3, of pointers
i1*i2*i3 arrays, length i4, of pointers
i1*i2*i3*i4 arrays, length i5, of ints
Hope that helps (and I hope I got the indices right).
That wikipedia link you posted refers to a /different kind of multidimensional array/. By default, C multidimensional arrays are the way I just described. You can also abstract them as a single dimensional array. This saves memory and makes the entire array contiguous, but it makes accessing elements somewhat more complex. For the 5-D example:
// WARNING I AM CHANGING NOTATION. N1..N5 are the lengths in each direction.
// i1..i5 are the indicies.
int* bigarray = malloc(sizeof(int)*N1*N2*N3*N4*N5);
// now instead of bigarray[i1][i2][i3][i4][i5], write this:
*(bigarray + i1*N2*N3*N4*N5 + i2*N3*N4*N5 + i3*N4*N5 + i4*N5 + i5);
each term there is an offset times the number of elements we need to offset. For example, to increment by one first-dimension level we need to traverse the the four remaining dimensions once to 'wrap around', if you will.
How arrays are stored in memory for C is not, as I recall, standardized. But for some information about arrays, and how they might be stored in memory, see the following two links:
http://webster.cs.ucr.edu/AoA/Windows/HTML/Arraysa2.html
http://publications.gbdirect.co.uk/c_book/chapter5/arrays.html
The first link is more general, and discusses different ways of storing arrays, while the second discusses the most likely way a C array may be layout in memory.
What's the difference between declaring multidimensional arrays like this:
int a[5][5];
or this
int* a[5];
?
Which one is better to use? Thanks.
Both may be used to declare 2-dimensional arrays.
In the first case, 25 int elements are allocated in a contiguous region in memory.
In this case the expression a[i][j] is translated by the compiler to *(a + i*5 + j).
The second one allocates 5 pointers to int. You can make it work as a two dimensional array by allocating vectors of int and making these pointers point to these vectors.
In this case a[i][j] means get the pointer that a[i] points to, then look up the 5th element in that vector. I.e. a[i][j] is translated to *(a[i] + j).
Note that in the second case, rows need not be of the same length.
int a[5][5]; says that the compiler should allocate enough memory to store 25 ints, and to treat it as a two-dimensional array called a.
int* a[5]; says that the compiler should allocate enough memory to store 5 pointers to integers, and treat it as an array of pointers called a. To actually use this as a two-dimensional array, you will have to allocate more memory and initialize those pointers to point at it. For example:
int * a[5];
for(int i = 0; i < 5; i++){ a[i] = malloc(sizeof(int) * 5); }
Without knowing your requirements it's hard to say which one is better for you. The second one allows you to efficiently swap two rows and is generally more flexible, but it takes more code to allocate and free the data structure.
The first one you are declaring bidimensional array (an array of arrays).
The second you're declaring an array of pointers to ints which can used as multidimensional array.
Is int *array[32] a pointer to an array of 32 ints, or an array of 32 pointers to int? Does it matter?
Take a look at http://www.cplusplus.com/doc/tutorial/arrays/ for declaring multidimensional arrays
Which is better apple or orange ?
this notation int a[ROWS][COLS]is used to create rectangular 2D array which dimensions are known at declaration time.
And this int * a[ROWS] notation is used when number of columns are unknown at 2D array declaration time OR number of columns can vary in run-time OR simply one wants to create non-rectangular (jagged) array like this:
1 2 3 4
4 6
7 1 1 1 5 6 7
9