Related
I can pass int arrays to both of these functions (1d and 2d arrays). What is the difference between them? With the second function you need to specify the size of the array. Why?
void foo(int *a, int cols)
void bar(int (*a)[N])
I have a program where I want to pass 2d int arrays to functions. Which is the better one to use and does it matter?
There are significant differences difference between these methods for 2D matrices
in the first method you pass a pointer to int, which is not the proper type for the matrix, even after implicit decaying.
cols is an int argument in the first prototype, whereas it is a constant N in the second one. In both cases, the number of rows is not specified, so it must be implicit, either because it is constant or because the matrix is square.
You will need to write the index computations explicitly in the first case and you can use a[row][col] in the second, which will be simpler, more readable and compile to more efficient code.
Note that since C99, there is a 3rd possibility allowing you to use the array syntax even for a variable number of columns. Here is an example:
#include <stdio.h>
#include <stdlib.h>
void init_matrix(int rows, int cols, int (*a)[cols]) {
int x = 0;
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
a[r][c] = x++;
}
}
}
void print_matrix(int rows, int cols, const int (*a)[cols]) {
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
printf("%3d%c", a[r][c], " \n"[c == cols - 1]);
}
}
}
int main() {
int cols = 4, rows = 3;
int (*a)[cols] = malloc(sizeof(*a) * rows);
init_matrix(rows, cols, a);
print_matrix(rows, cols, a);
return 0;
}
Difference between int* a and int (*a)[N] in functions?
While int* a is a pointer to int, int (*b)[N] is a pointer to an array of N ints. These are different types, and are not compatible.
b can only point to an array of N ints while a can point to an int wether it's in an array or not. When you pass an array as argument you are really passing a pointer to its first element, it's commonly said that it decays to a pointer. Another difference is that if you increment b it will point to the next block of N ints whereas if you increment a it will just point to the next int.
I have a program where I want to pass 2d int arrays to functions. Which is the better one to use and does it matter?
It matters, for foo, it hints to a flat array with cols width, of course with some arithmetic you can treat it as a 2D array, bar is a more natural use for a 2D array.
The memory layout will probably be the similar, and using a flat array to store elements in such a way that you can use it as a 2D array is perfectly fine. I personally find it less messy and more clear to use a pointer to array, instead of pointer to int, when I need a 2D array.
Example:
#include <stdio.h>
#include <stdlib.h>
#define N 5
#define M 5
void bar(int (*a)[N]) {
// prints 20, 4 bytes * 5 (can be different deppending on the size of int)
printf("Size of 'a' is %zu\n\n", sizeof *a);
// populate the array
int c = 1;
for (int i = 0; i < N; i++)
for (int j = 0; j < M; j++)
a[i][j] = c++;
for(int i = 0; i < N; i++){
printf("a[%d][0] = %2d\n", i, **a);
// incrementing 'a' will make it point to the next array line
a++;
}
putchar('\n');
}
Output:
Size of a is 20
a[0][0] = 1
a[1][0] = 6
a[2][0] = 11
a[3][0] = 16
a[4][0] = 21
int main() {
int(*a)[N] = malloc(sizeof *a * M);
bar(a);
// prints the complete array
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
printf("%2d ", a[i][j]);
}
putchar('\n');
}
free(a);
}
In this code a is a 2D array N x M which is passed to bar to be populated. I added some handy prints and comments for clarification. See it live: https://godbolt.org/z/1EfEE5ed7
Output:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
With the second function you need to specify the size of the array. Why?
You don't have to specify the entire size of the entire 2D array, but you do have to specify the number of columns, i.e. the size of the sub-array.
The reason why the compiler must know the size of the sub-array is that this information is required for offset calculations.
For example, if you define a 2D array like this
int arr[2][4];
then the array elements will be stored in memory in the following order:
arr[0][0]
arr[0][1]
arr[0][2]
arr[0][3]
arr[1][0]
arr[1][1]
arr[1][2]
arr[1][3]
If the compiler wants to for example access arr[1][2], it will need to know how many columns there are per row, i.e. how big each sub-array is. If the compiler does not know that there are 4 columns per row, then the compiler has no way of knowing where to find arr[1][2]. However, if the compiler knows that there are 4 columns per row, it will know that the 5th element of the 2D array is the start of the second row, so it will know that arr[1][2] is the 7th element of the 2D array.
I can pass int arrays to both of these functions (1d and 2d arrays).
Although accessing a 2D array as a 1D array may work on most compilers, it is undefined behavior according to the ISO C standard. See this question for further information:
One-dimensional access to a multidimensional array: is it well-defined behaviour?
Which is the better one to use and does it matter?
The first one is better in the sense that it allows you to specify the number of columns at run-time, whereas with the second one, the number of columns must be set at compile-time, so you are less flexible.
However, as stated above, depending on your compiler, it may not be safe to access a 2D array as a 1D array. Therefore, it would probably be best to pass 1D arrays to the first function and 2D arrays to the second function.
However, it is not clear how the second function is supposed to know how many rows the 2D array contains, since this information is not passed to the function as an argument. Maybe the function is assuming a fixed number of rows, or maybe it is not intended to be used for 2D arrays at all. The information that you have provided in the question is insufficient to answer this.
I am trying to globally define a multidimensional array. The dimensions will ultimately depend on some other computations. Here I'll just consider n and B to be 5 but I place them inside function2 to stress that the dimensions are not known initially. At some point I'll also need to duplicate this array. The code below gives the error Subscripted value is not an array, pointer, or vector on the line where I'm printing the array2 entries. How can I fix this error and is there anything else I need to change to accomplish this?
int n,B;
double ** array;
double ** array2;
void function(){
double array[n][B][n];
for(int i = 1; i <= n; i++){
for(int j = 1; j <= B; j++){
for(int k = 1; k <= n; k++){
array[i-1][j-1][k-1] = i*j*k;
}
}
}
}
void function2(){
n=5;
B = 5;
function();
array2 = array;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= B; j++){
for(int k = 1; k <= n; k++){
printf("%lf",array2[i-1][j-1][k-1]);
}
}
}
}
int main(){
function2();
return 0;
}
Oops... I am trying to globally define a multidimensional array. The dimensions will ultimately depend on some other computations... Don't. At least do not try that in C language. Arrays are not first class citizens in C, not speaking of multi-dimensional ones. Said differently AFAIK, there is no way in C to declare a multi-dimensional array where all dimensions but the last one are not compile time constants.
But there are another problems in your code: double ** array; at global level declares a pointer to pointer (or a pointer to array) which is a totally different animal than a multi-dimensional array. And double array[n][B][n]; (wrongly) declares a totaly independant multi-dim. array, hiding the global symbol.
So my advice is:
avoid if possible globaly defined variables. There are indeed correct use cases but most of the time, it is cleaner to pass them as parameter of functions, possibly inside structs
make your choice between a multi-dimensional array and an array of pointers. The former is a consecutive containers where all dimensions but the last have to be constant, the latter if much more versatile, because each row could have a different size. But it is slightly more complex to declare and slightly less efficient.
int a1[5], a2[6], a3[7];
int **parray = {a1, a2, a3};
elt_i_j = parray[i][j];
do not forget about the good old idiom allowing to see a 1-D array as a multi-dim one:
size_t size1, size2, size3;
// compute the sizes...
int *array = malloc(size1, size2, size3);
elt_i_j_k = array[k + size2 * (j + size1 * i)]
Good luck in learning C arrays...
First note that in function2 :
function();
array2 = array;
array refers to the global variable, while function initialized its local variable array and not the global one. So array and array value NULL
Subscripted value is not an array, pointer, or vector
array2 is only known as double ** array2; so array2[i-1][j-1][k-1] cannot be resolved because it needs at least the last two dimensions. Note also it is strange to use a double pointer for a 3D array.
If you want to use array2 supposing it is in fact double array2[n][B][n] you can cast it as double (*)[B][n], but in your code array2 is NULL. Or of course you have array2 as a double * and you compute yourself the right offset to access the double you want
First thing, arrays in C are stored in contiguous memory locations. So if you do not provide the number of rows or the number of columns, how will the compiler know how many rows and columns there are?
So, you have to specify the rows and columns at the start.
However, you can have some workaround. Refer to this Initializing Arrays in C/C++ With Unknown Size
There are few issues in the code which you should have a look at:
functions() has a local declaration of array2. So,
double ** array2;
and
array2 = array;
are different.
You can't assign arrays in C. You can copy them with the memcpy() function, declared in string.h as follows:
memcpy(&array2, &array, sizeof array2);
array2 is declared as double ** array2; so array2[i-1][j-1][k-1] cannot be resolved.
Happy coding!
Is it possible to write a function which accept 2-d array when the width is not known at compile time?
A detailed description will be greatly appreciated.
You can't pass a raw two-dimensional array because the routine won't know how to index a particular element. The 2D array is really one contiguous memory segment.
When you write x[a][b] (when x is a 2d array), the compiler knows to look at the address (x + a * width + b). It can't know how to address the particular element if you don't tell it the width.
As an example, check http://www.dfstermole.net/OAC/harray2.html#offset (which has a table showing how to find the linear index for each element in an int[5][4])
There are two ways to work around the limitation:
1) Make your program work with pointer-to-pointers (char *). This is not the same as char[][]. A char * is really one memory segment, with each value being a memory address to another memory segment.
2) Pass a 1d pointer, and do the referencing yourself. Your function would then have to take a "width" parameter, and you could use the aforementioned formula to reference a particular point
To give a code example:
#include <stdio.h>
int get2(int *x) { return x[2]; }
int main() {
int y[2][2] = {{11,12},{21,22}};
printf("%d\n", get2((int *)y));
}
This should print out 21, since y is laid out as { 11, 12, 21, 22 } in memory.
C supports variable-length arrays. You must specify the width from a value known at run-time, which may be an earlier parameter in the function declaration:
void foo(size_t width, int array[][width]);
One way is use the good old "pointer to array of pointers to arrays" trick coupled with a single continuous allocation:
/* Another allocation function
--------------------------- */
double ** AnotherAlloc2DTable(
size_t size1, /*[in] Nb of lines */
size_t size2 /*[in] Nb of values per line */
)
{
double ** ppValues;
size_t const size1x2 = size1*size2;
if(size1x2 / size2 != size1)
return NULL; /*size overflow*/
ppValues = malloc(sizeof(*ppValues)*size1);
if(ppValues != NULL)
{
double * pValues = malloc(sizeof(*pValues)*size1x2);
if(pValues != NULL)
{
size_t i;
/* Assign all pointers */
for(i=0 ; i<size1 ; ++i)
ppValues[i] = pValues + (i*size2);
}
else
{
/* Second allocation failed, free the first one */
free(ppValues), ppValues=NULL;
}
}/*if*/
return ppValues;
}
/* Another destruction function
---------------------------- */
void AnotherFree2DTable(double **ppValues)
{
if(ppValues != NULL)
{
free(ppValues[0]);
free(ppValues);
}
}
Then all you have to do is pass a char ** to your function. The matrix is continuous, and usable as mat[x][y].
Possible accessor functions:
int get_multi(int rows, int cols, int matrix[][cols], int i, int j)
{
return matrix[i][j];
}
int get_flat(int rows, int cols, int matrix[], int i, int j)
{
return matrix[i * cols + j];
}
int get_ptr(int rows, int cols, int *matrix[], int i, int j)
{
return matrix[i][j];
}
An actual multi-dimensional array and a fake one:
int m_multi[5][7];
int m_flat[5 * 7];
Well-defined ways to use the accessor functions:
get_multi(5, 7, m_multi, 4, 2);
get_flat(5, 7, m_flat, 4, 2);
{
int *m_ptr[5];
for(int i = 0; i < 5; ++i)
m_ptr[i] = m_multi[i];
get_ptr(5, 7, m_ptr, 4, 2);
}
{
int *m_ptr[5];
for(int i = 0; i < 5; ++i)
m_ptr[i] = &m_flat[i * 7];
get_ptr(5, 7, m_ptr, 4, 2);
}
Technically undefined usage that works in practice:
get(5, 7, (int *)m_multi, 4, 2);
[Warning - this answer addresses the case where the number of columns - the WIDTH - is known]
When working with 2D arrays, the compiler needs to know the number of columns in your array in order to compute indexing. For instance, if you want a pointer p that points to a range of memory to be treated as a two-dimensional set of values, the compiler cannot do the necessary indexing arithmetic unless it knows how much space is occupied by each row of the array.
Things become clearer with a concrete example, such as the one below. Here, the pointer p is passed in as a pointer to a one-dimensional range of memory. You - the programmer - know that it makes sense to treat this as a 2D array and you also know (must know) how many columns are there in this array. Armed with this knowledge, you can write code to create q, that is treated by the compiler as a 2D array with an unknown number of rows, where each row has exactly NB columns.
I usually employ this when I want the compiler to do all the indexing arithmetic (why do it by hand when the compiler can do it?). In the past, I've found this construct to be useful to carry out 2D transposes from one shape to another - note though that generalized 2D transposes that transpose an MxN array into an NxM array are rather beastly.
void
WorkAs2D (double *p)
{
double (*q)[NB] = (double (*)[NB]) p;
for (uint32_t i = 0; i < NB; i++)
{
for (uint32_t j = 0; j < ZZZ; j++) /* For as many rows as you have in your 2D array */
q[j][i] = ...
}
}
I believe a nice solution would be the use of structures.
So I have an example for 1d-Arrays:
Definition of the struct:
struct ArrayNumber {
unsigned char *array;
int size;
};
Definition of a function:
struct ArrayNumber calcMultiply(struct ArrayNumber nra, struct ArrayNumber nrb);
Init the struct:
struct ArrayNumber rs;
rs.array = malloc(1);
rs.array[0] = 0;
rs.size = 1;
//and adding some size:
rs.size++;
rs.array = realloc(rs.array, rs.size);
hope this could be a solution for you. Just got to change to a 2d Array.
Suppose I have a function, int function(int N, int c[N]){...}, taking as parameters an integer and an array. Suppose now I have a double array **c of size 'N times 2' and suppose, I want to apply the function function to one column of the double arrow, c[i][0], i varying from to N-1. How am I supposed to use this function. Does it looks like something like function(N,*c[0]) ?
Does anyone can help ?
An array in C always decays to a pointer to its first element when passed into a function. This is good to know in some situations.
As an example, you could write
int list[10];
func (int *x) {
int i;
for (i = 0; i < 10; i++) {
printf("%d", x[i]);
}
}
x[i] is really just syntactic sugar. In C, when you use bracket notation to access an element of an array, it gets converted to *(x + i), where x is the name of the array.
This works because of pointer arithmetic. If x is the name for an array of 10 integers, then the value of x in an expression is the address of the first integer of the array.
x + i will always point to the i-th element after x (C takes into account the size of the element type stored in the array, and increments the pointer accordingly).
Thus, when passing 2d arrays, the array decays to a pointer to its first element - which is an array.
A function signature taking a 2d array can be written as
func(int x[][columns] {
...
}
// but could also be written as
func(int (*x)[columns]) {
...
}
which indicates that x is a pointer to an array of integers.
Sometimes you need to write a function to accept a 2 dimensional array where the width is not known until run time. In this case, you can pass a pointer to the [0][0] element and also pass the two dimensions, and then use pointer arithmetic to get the right element. For example,
print_2d_array (int *x, height, width) {
int i, j;
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
printf("%d", x[i * width + j]);
}
}
}
int list[10][10];
print_2d_array (&list[0][0], 10, 10);
would work for a dynamically allocated 2d array.
In c langauge, for single dimentional array you no need to mention the size of the array in the function arguments while passing an array to that function.
If it is a single dimentional array
...
int a[10];
func(10, a);
...
void func(int size, int x[]) //no need to mention like int x[10]
{
//here x is not an array. Its equivalent to int *
printf("%d", sizeof(x)); // this will print 4 or 8 not 40
}
If it is 2D array
...
int a[10][5];
func (10, a);
...
void (int rows, int x[][5]) //here int x[][] is invalid
{
}
I am new to C programming and this is my problem:
I want to store the first value of each array in a new array, then the second value of each array in a new array and so on.
I could declare the array of pointers but I don't know how I use it!
Please I need Help.
int main()
{
int t1[4]={0,1,2,3};
int t2[4]={4,5,6,7};
int t3[4]={8,9,10,11};
int t4[4]={12,13,14,15};
int *tab[4]={t1,t2,t3,t4};
int i,j,k,l;
for (i=0; i<4;i++)
{
printf("%d\t", *tab[i]);
}
return 0;
}
When I do this, I store just the first value of each array.
Your terminology is a little bit all over the place. I think the easiest way to answer your question is to go through your code line by line.
int main()
{
int t1[4]={0,1,2,3}; //Declares a 4 integer array "0,1,2,3"
int t2[4]={4,5,6,7}; //Declares a 4 integer array "4,5,6,7"
int t3[4]={8,9,10,11}; //Declares a 4 integer array "8,9,10,11"
int t4[4]={12,13,14,15}; //Declares a 4 integer array "12,13,14,15"
int *tab[4]={t1,t2,t3,t4};//Declares a 4 pointer of integers array "address of the first element of t1, address of the first element of t2, ..."
int i,j,k,l; //Declares 4 integer variables: i,j,k,l
for (i=0; i<4;i++)
{
printf("%d\t", *tab[i]); //print out the integer that is pointed to by the i-th pointer in the tab array (i.e. t1[0], t2[0], t3[0], t4[0])
}
return 0;
}
Everything you are doing seems ok until your loop. You are showing only the first integer of every array because you are not going through them. To iterate over them, your code should look like this:
for (i=0; i<4;i++)
{
for (j=0; j<4; j++)
{
printf("%d\t", *(tab[j] + i));
}
}
The above code uses two loop counters, one (the i) to go through the positions in the array (first value in the array, second value in the array, etc.); the other to go through the different arrays (the j). It does this by retrieving the pointer stored in tab[j] and creating a new pointer that has the right offset to show the value for the ith column. This is called pointer arithmetic (there is additional information about pointer arithmetic here)
Most people find the syntax *(tab[j] + i) to be clunky, but it is more descriptive of what is actually happening. In C, you can rewrite it as tab[j][i], which is much more usual.
You have stored the data as you intended, you just need to access it properly
for (i=0; i<4;i++)
{
for (j = 0; j < 4; j++) {
int* temp = tab[i];
printf("%d\t", temp[j]); // or try the next line...
printf("%d\t", *(temp + j)); // prints same value as above line
printf("%d\t", tab[i][j]; // the same value printed again
}
}
All of the above print the same value, it is just different ways of accessing that value using pointer arithmetic. Each element of tab is a int* the value of each is the address of your other defined int[] arrays at the start
Edit: In response to the comment of Jerome, you can achieve that by declaring 4 arrays
int tab1[4]={*t1,*t2,*t3,*t4};
int tab2[4]={*(t1+1),*(t2+1),*(t3+1),*(t4+1)};
int tab3[4]={*(t1+2),*(t2+2),*(t3+2),*(t4+2)};
int tab4[4]={*(t1+3),*(t2+3),*(t3+3),*(t4+3)};
Now tab1 contains the first elements of each array, tab2 the second elements, and so on.
Then you can use
int *tttt[4]={tab1,tab2,tab3,tab4};
for (i=0; i<4;i++) {
for (j = 0; j < 4; j++) {
printf("%d\t", tttt[i][j]);
}
}
to print what you wanted. If you declared another pointer array like you did at the start
int* tab[4] = {t1,t2,t3,t4};
then essentially in matrix terms, tttt is the transpose of tab
You store everything but you just don't show it. Try
for (i=0; i<4;i++)
{
for (j=0; j<4; j++)
printf("%d\t", *(tab[i]+j));
}
int* (*a[5])[5][5][5] declares an array of 5 pointers to a 3d array of pointers to ints
int* (*(*a[5])[5])[5][5][5] declares an array of 5 pointers to an array of 5 pointers to a 3d array of pointers to ints.
#include <stdio.h>
int main()
{
int t1[4]={0,1,2,3};
int t2[4]={4,5,6,7};
int t3[4]={8,9,10,11};
int t4[4]={12,13,14,15};
int (*tab[4])[4]={&t1,&t2,&t3,&t4};
int i,j,k,l;
for (i=0; i<4;i++)
{
printf("%d\t", (*tab[i])[1]);
}
return 0;
}
There's a difference between t2 and &t2. Though they have the same value their types are different. int [4] vs int (*)[4]. The compiler will throw a warning (clang) or error (gcc).
int a[4] is conceptually at compiler level a pointer to an array of 4 as well as being the array itself (&a == a).
int (*a)[4] is conceptually at compiler level a pointer to a pointer to an array of 4 as well as being a pointer to the array itself (a == *a) because it's pointing to an array type where the above is true.
At runtime, if an int * and int (*a)[4] point to the same address, they are physically identical – it's just an address, the same address. The type only matters in how the compiler interprets and produces arithmetic operations with that address and the assembly it actually outputs based on the type. You can cast the address to any type you want in order to achieve the desired code output to manipulate data at the address it holds. An int a[4] type however is physically the array itself but you use it as if there is a pointer a to it in memory which is given the same address as the array itself. A pointer to int a[4] means 'a pointer to the address range a that is treated by the compiler as an array with int element width, where the compiler treats the start of the array as if it were a pointer to the array', and any operations on that type will be consistent in a derefernce chain i.e. you must at compiler level use (*a)[0] to access the first element if the type is a pointer to an array, but if you cast the same address to int * then you need to use a[0] to access the member.