Initializing multidimensional arrays in C - c

I'm just a tad confused about initializing multidimensional arrays in C...
This works:
int foo[2][MAX] = {
{2,4,34,43,23,0},
{2,4,34,43,23,0}
};
But this does not:
int foo[2][MAX];
foo = {
{2,4,34,43,23,0},
{2,4,34,43,23,0}
};
How come?

This syntax is for initialization, but in the second case you are using it for assignment which will not work.
type varName = someValue; // this is declaration and initialization
type varName; // this is declaration
varName = someValue; // this is assignment and not initialization
That is initialization can only be done at the declaration time, else it's a normal assignment.

The { syntax is only valid when you're initializing and declaring an array at the same time.
After declaring it, you need to use the complete syntax:
foo[0][0] = 2;
Technically speaking, C only has one-dimensional arrays. You create multidemnsional arrays by making arrays of arrays. The name of an array is converted to a pointer to its first element, and only the outer array is converted to a pointer. It's a pointer to an array of MAX ints, or int(*)[MAX].

As you said, this syntax is used to initialize an array, but in your second piece of code:
int foo[2][MAX];
Here, foo is uninitialized, and then
foo = {
{2,4,34,43,23,0},
{2,4,34,43,23,0}
};
This is assignment, not initialization.

Multidimensional or not, arrays in C are not copyable, which means that there's no way to assign anything to the entire array using core language features after the initialization is complete.
However, it is still possible to copy arrays by using memcpy function. In combination with compound literals it allows you to do what you tried to do. You just have to use a different syntax
int foo[2][MAX];
memcpy(
foo,
(int[2][MAX]) {
{2,4,34,43,23,0},
{2,4,34,43,23,0}
},
sizeof foo);

In C99 (or in gcc as an extension) you can make use of compound literals:
int (*foo)[MAX];
foo = (int [][MAX]) {
{2,4,34,43,23,0},
{2,4,34,43,23,0}
};
But note that foo must be declared as a pointer to MAX int's (not as a 2D array)

You have misunderstood the concept of 'initialization' and 'assignment`.
For example
int a = 10; // Initialization
Initialization is nothing but declaration + assignment.
But
int a; // Declaration
a = 10; // Assignment
When you do like this-
int foo[2][MAX] = {
{2,4,34,43,23,0},
{2,4,34,43,23,0}
};
internally it came to know 2 rows and MAX columns. It will initialize the whole array.
But-
int foo[2][MAX];
foo = {
{2,4,34,43,23,0},
{2,4,34,43,23,0}
};
Here foo represent the starting address of the array. Here you are trying to assign the values to 2D array. when you are trying to assign values to array it doesn't know how many rows and how many columns are there. so it is not possible and not allowed.
When you want to assign the input to array A better solution is scan it from user/ at run time-
int foo[2][MAX],i,j;
for(i=0;i<2;i++){
for(j=0;j<max;j++)
scanf("%d",&foo[i][j]);
}

Related

Error while returning an array from a function in C

I have a question.
I am unable to compile my program.
This is a very simple program, that assigns an array, to a variable and passes it as an argument in a function. Now on returning this array it returns the array.
Now, I am facing a syntax error, that follows this way:
p2.c:3:4: error: expected identifier or ‘(’ before ‘[’ token
int[] lifo(int[] arr)
I am unable to resolve the error, for the following program:
#include<stdio.h>
int[] lifo(int[] arr)
{
return arr;
}
int main()
{
int arr1[100],arr2[100],arr[100];
int arr1_size,arr2_size,arr_size,i;
printf("Enter size of array1: \n");
scanf("%d",&arr1_size);
printf("Enter size of array2: \n");
scanf("%d",&arr2_size);
printf("Enter elements of array1: \n");
for(i=0;i<arr1_size;i++)
{
scanf("%d",&arr1[i]);
}
printf("Enter elements of array2: \n");
for(i=0;i<arr2_size;i++)
{
scanf("%d",&arr2[i]);
}
printf("Combining 2 arrays: \n");
arr_size=arr1_size+arr2_size;
arr=lifo(arr1);
for(i=0;i<arr1_size;i++)
{
printf("%d\n",arr[i]);
}
return 0;
}
In C, arrays can't be returned from a function, and they can't be passed to a function either. But let's start with this: Your declaration of an array is wrong here:
int[] lifo(int[] arr)
In C, the brackets in an array declaration go after the declarator. So, to write a function taking and returning an array, the "correct" syntax would look like this:
int lifo(int arr[])[]
If you try this, a good compiler will give you an error like this:
error: ‘lifo’ declared as function returning an array
It just isn't allowed to return an array.
The compiler doesn't complain about the parameter int arr[] though: That's because of a special rule for function parameters -- if they have array type, they are automatically adjusted to the corresponding pointer type. So, the following function declarations are exactly the same:
void lifo(int arr[]);
void lifo(int *arr);
You can't pass or return arrays. But the syntax allows a function to look like it would take an array -- it instead takes a pointer to the first element of this array.
In C you always pass arrays by its address, for example its beginning. To do it you have to use pointers. It means that your function's definition is invalid. It should looks like:
int* lifo(int* arr)
{
return arr;
}
But this implementation does not have any sense because the output points to the same location as the input. Please refer to the books which explain you how the arrays are handled in C.
lifo(int[] arr)
Turn this into:
lifo( int * arr )
or
lifo( int arr[] )
Note that even the second variant will still be passing a pointer, and not an array. (For one, you will not be able to determine the number of elements by sizeof().) You are still able to use indexed access on arr, but you can do that on any pointer.
As for the return value, use int *. It is, after all, what you will be returning -- another pointer, not an array.
(Your function lifo is, of course, a non-op... I will assume this is for example's sake only.)

function prototype return 2D array in C

I am not very good at C and I am really confused about double array. Below is an outline of a code I have a question about. Main function calls CreateRandConn function and passes it a 2D array filled with 0 as an argument. CreateRandConn function takes a 2D array as a parameter, changes some of the value in 2DArray from 0 to 1 and returns the changed 2DArray back to main. I want to indicate in the function prototype the return type of CreateRandConn function is a 2D array. How do I indicate that? I don't really understand the syntax. Is what I wrote wrong? Is the way I am passing the 2DArray as a parameter in the function header incorrect? If so, how I do write it? I still get confused about the relationship between pointers and double arrays. Can someone explain it with the below code outline? Hopefully someone knows what my question is...
//Function prototype
int ** CreateRandConn(char * RandRoom[7], int my2DArray[7][7], char * room_dir);
//Function
int ** CreateRandConn(char * RandRoom[7], int my2DArray[7][7], char * room_dir)
{
...
return my2DArray;
}
int main()
{
int 2DArray[7][7] = {0};
2DArray = CreateRandConn(RandRoomArray, my2DArray[7][7], room_dir);
return 0;
}
I don't really understand the syntax.
Ok, so let's recap the basics:
One cannot assign to an array variable.
If an array gets passed to a function it "decays" to a pointer to its 1st element.
A multidimensional array is just an array of arrays. So a 2D-array is a 1D-array of 1D-arrays, a 3D-array is a 1D-array of 2D-arrays, a 4D-array is a 1D-array of 3D-arrays, and so on ...
A pointer p to an array of N elements of type T is to be defined as: T (*p)[N]
Now for you example:
You have
int 2DArray[7][7] = ...;
for the sake of clarity of the following explanations I change this to be
int a[5][7] = ...;
So this then is passed to a function. Where the following happens/applies:
Following 1. above, it is not possible to pass an array, as if it were possible one would assign it to the variable inside the function, as arrays cannot be assigned, one cannot pass an array.
Following 2. above, the function would need to define the related variable as "a pointer to the arrays 1st element".
Following 3. above, the a's 1st element is an int [7]
Following 4. above, a pointer to an int[7] will be defined as: int(*)[7].
So the function's relevant variable would look like:
... func(int (*pa)[7])
pa points to the 1st element of a. As a side note: From this pointer a the function cannot derive how many elements a actually "provides", will say: how many valid element after the one a points to will follow, so this needs to be passed to the function as well:
... func(int (*pa)[7], size_t rows)
From the steps so far we learned, that an array is not passed, but just a pointer to it's 1st element *1 is passed, is copied into the function's local variable (pa here).
From this directly follows that an array cannot be passed back as the function's return value, but just a pointer to an array's element (typically the 1st)
Looking at how a pointer to an array is defined: T (*p)[N] we know need to derive how a function returning a pointer to an array would look. The function's defalcation somewhat needs to become the p above. So taking T as int and N as 7 we then get:
int (*func(int (*pa)[7], size_t rows))[7];
The trivial implementation and usage then would be:
#include <stdlib.h> /* for size_t */
#define ROWS (5)
#define COLS (7)
int (*func(int (*pa)[COLS], size_t rows))[COLS];
int (*func(int (*pa)[COLS], size_t rows))[COLS]
{
for (size_t i = 0; i < rows; ++i)
{
for (size_t j = 0; j < COLS; ++j)
{
pa[i][j] = 0;
}
}
return pa;
}
int main(void)
{
int a[ROWS][COLS];
int (*pa)[COLS] = func(a, ROWS);
return EXIT_SUCCESS;
}
*1
(which sloppy, but wrongly spoken often is referred to as "a pointer to an array is passed", which in general it is not, but just here, as it's a 2D-array, will say the array's elements are arrays themselves).
If you understood the above, then just for completeness following a less strange looking (but also probably less educational ;-)) version of the above function declaration. It may be declared by using a typedef construct hiding away the somehow complicated declaration of the array-pointers as parameter and return type.
This
typedef int (*PA)[COLS];
defines a type pointing a an array of COLS of ints.
So using PA we can instead of
int (*func(int (*pa)[COLS], size_t rows))[COLS];
write
PA func(PA pa, size_t rows))[COLS];
This version is identical to the above.
And yes it looks simpler, but brings along the fact, that pointers pa and the function's return value) are not identifiable as being pointers by just looking at their definition. Such constructs are considered "bad practice" by many fellow programmers.

integer array initialization error in C

I'm trying to initialize my array in the following way but get an expression syntax error:
int LineOne[ARRAY_LENGTH];//where ARRAY_LENGTH is a constant of length 10
if(SOME_CONDITION_IS_TRUE){
LineOne[ARRAY_LENGTH] = {0,1,0,0,1,1,1,0,1,1};
}
It really depends on the rest of the code (how you want to use the array), what solution is the best. One other way to do it could be...
int* LineOne = 0;
if(SOME_CONDITION_IS_TRUE) {
static int* init = {0,1,0,0,1,1,1,0,1,1};
LineOne = init;
}
You cannot have array literals in "classic" C, except as initializers when the variable is being defined.
In C99, you can use compound literals to do this, but you must repeat the type in a cast-like expression before the literal:
LineOne = (int[ARRAY_LENGTH]) { 0,1,0,0,1,1,1,0,1,1 };
You can not do it that way. You could use an alternate array and copy it:
#include <string.h>
…
int values[] = {0,1,0,0,1,1,1,0,1,1};
int LineOne[ARRAY_LENGTH];//where ARRAY_LENGHT is a constant of length 10
if(SOME_CONDITION_IS_TRUE)
memcpy(LineOne, values, sizeof(values));

C existing pointer to fixed-size array

Let's say that any C function has a pointer already declared, but not assigned any value yet. We will int for our examples.
int *ptr;
The goal of the function is not to assign ptr any dynamic memory on the heap, so no malloc call. Instead, we want to have it point to an array of fixed size n. I know I could accomplish this like so:
int arr[n];
ptr = arr;
However, the code could get very messy and hard to read if we need to do this many times in a function, ie, a struct of many pointer fields all need to point to an array of fixed length. Is there a better way to accomplish this in one line? I was thinking of something similar to below, but it looks too ambiguous and uncompilable:
int *ptr;
// Many other things happen in between...
ptr[n];
***EDIT***
Here, the below additional information may help guide some more answers (not saying that the current answers are not fine). In my use case, the pointers are declared in a struct and, in a function, I am assigning the pointers to an array. I want to know if there is a simpler way to accomplish this than in the below code (all pointers to point to fixed-length array):
struct foo {
int* a;
short* b;
char* c;
...
};
void func(void) {
struct foo f;
int n = ...;
int tempArr1[n];
f.a = tempArr1;
short tempArr2[n];
f.b = tempArr2;
char tempArr3[n];
f.c = tempArr3;
...
}
You cannot declare an array and assign it to an existing pointer in a single declaration. However, you can assign an array pointer to a newly declared pointer, like this:
int arr[n], *ptr = arr;
If you insist on staying within a single line, you could use an ugly macro, like this:
#define DECL_ASSIGN_INT_ARRAY(name,size,pointer) int name[(size)]; pointer = name;
The clarity of this one-liner is far lower than that of a two-line version from your post, so I would keep your initial version.
EDIT (in response to the edit of the question)
Another option is to create an unused pointer variable in a declaration, and assign your pointer in an initializer, like this:
void func(void) {
struct foo f;
int n = ...;
int tempArr1[n], *tempPtr1 = f.a = tempArr1;
short tempArr2[n], *tempPtr2 = f.b = tempArr2;
char tempArr3[n], *tempPtr3 = f.c = tempArr3;
...
}
This seems like a clear case where you're in need of some refactoring. Take the similar statements, extract them into a new function (by passing a reference to the struct and the data you want the struct fields to point to) and give this new function a meaningful name.
This is probably more maintainable and readable than some fancy pointer arithmetic shortcut that you'll forget about in a few weeks or months.
The difference between ptr and arr in you example is you can change ptr's value. So I guess you want to move ptr through the array.
So how about this:
int arr[n], id=0;
And you change the value of id and use arr+id as ptr.
I guess the way to do this is to use a macro. Something like (untested)
#define autoptr(name,size) int Arrayname[size]; name = Arrayname;
I'm not clear why this is helping I think it might "look ugly" but will be easier to maintain without the macro. In general, hiding what you are actually doing is a bad thing.

Returning a pointer of a multidimensional array

I'm Java programmer and I'm struggling with this simple stuff.
How can I return this multidimensional array? Does it have to return a ** pointer? How can I get it in another file?
static MoveDirection ghost_moves[GHOSTS_SIZE][4];
MoveDirection** get_ghost_moves() {
return ghost_moves;
}
A 2D array is not a pointer to a pointer. Arrays and pointers are fundamentally different types in C and C++. An array decays into a pointer to its first element (hence the frequent confusion between the two), but it only decays at the first level: if you have a multidimensional array, it decays into a pointer to an array, not a pointer to a pointer.
The proper declaration of get_ghost_moves is to declare it as returning a pointer to an array:
static MoveDirection ghost_moves[GHOSTS_SIZE][4];
// Define get_ghost_moves to be a function returning "pointer to array 4 of MoveDirection"
MoveDirection (*get_ghost_moves())[4] {
return ghost_moves;
}
This syntax syntax is extremely confusing, so I recommend making a typedef for it:
// Define MoveDirectionArray4 to be an alias for "array of 4 MoveDirections"
typedef MoveDirection MoveDirectionArray4[4];
MoveDirectionArray4 *get_ghost_moves() {
return ghost_moves;
}
I believe that you want the following:
MoveDirection ( * get_ghost_moves() ) [GHOSTS_SIZE][4];
In the above get_ghost_moves is a function returning a pointer to an array of array of MoveDirection, with dimensions GHOSTS_SIZE and 4.
I found the following two sites very useful for learning how to understand C declarations:
Reading C type declarations
cdecl - converts C declarations into words.
#define MAX 20
char canopy[20][MAX];
typedef char frank[MAX];
frank friend[MAX];
frank *getList()
{
return friend;
}
void test(int n)
{
frank *list = getList();
int i;
for (i = 0; i < 5; i++ )
{
printf("list[%d] %s\n\r", i, list[i]);
}
}
int main(void)
{
int i, nf;
for (i = 0; i < 5; i++ )
{
snprintf(friend[i], MAX, "test%d", i);
printf("test[%d] %s \n\r", i, friend[i]);
}
test(5);
return 0;
}
No, just a single * is all you need. The key is to think about how your data is arranged in memory: an array is just a series of items of the same type, laid out contiguously in memory. In this context it doesn't matter what shape or size the array is - you're just returning a pointer to the start of it, which means you're returning the address of the first item.
Of course, whoever you're returning that pointer to will have to know what the shape and size of the array are.
One of the nice things about C and pointers is that everything's just a number, and memory is just a big array of bytes. Once you get comfortable thinking like that, it all falls into place.
A multidimensional array is not an array of pointers. It is a single memory block. It only has meaning inside the scope where it is declared.
You can't cleanly return that as you have here.. you would have to return a MoveDirection[GHOSTS_SIZE][4].
ghost_moves occupies a contiguous set of GHOSTS_SIZE*4 MoveDirections in memory: its equivalent to a MoveDirection*
It cannot be used with a pointer to pointer, but with a single pointer.
If you want to use two operator[]-s to index your array you've got two options:
use a variable of type: MoveDirection (*ghost_moves) [GHOST_SIZE] and then just do ghost_moves[i][j]
this is mostly to have a pointer to pointer, usually is not a good solution: have ghost_moves of type MoveDirection**
for example:
MoveDirection ghost_moves_original[GHOST_SIZE][4];
MoveDirection *ghost_moves[GHOST_SIZE];
ghost_moves[0] = ghost_moves_original;
ghost_moves[1] = ghost_moves_original + GHOST_SIZE;
...

Resources