C - select 2D slice from 3D array - c

I have a global 3D array declared like this:
TileType maps[DLVL_MAX][LEVEL_HEIGHT][LEVEL_WIDTH];
and a function in which I'd like to name one 2D slice of this array to make things less cumbersome, i.e. something like
void f(int dlvl) {
TileType level_map[LEVEL_HEIGHT][LEVEL_WIDTH] = &(maps[dlvl]);
...
}
At first sight this looks to me like it should be possible, since C array dimensions are ordered left to right. Yet I can't find the right expression for this. (Of course, I can just give level_map a TileType* type, but then I can't use double indexing as in level_map[x][y].)
Is it possible at all?

TileType level_map[LEVEL_HEIGHT][LEVEL_WIDTH] = &(maps[dlvl]);
&(maps[dlvl]) evaluates to an address, namely the address of the dlvlth element of maps.
You cannot use an address to initialise an array, which level_map is.
You could do
TileType (*plevel_map)[LEVEL_HEIGHT][LEVEL_WIDTH] = maps[dlvl];
The above statement defines and initialises plevel_map to point to the dlvlth element of maps.
You would then access the elements of dlvlth element of maps like this
(*plevel_map)[x][y]
Update
What you also could do is
TileType * pplevel_map = maps[dlvl][0];
And then access map[dlvl][0]'s element like this:
pplevel_map[x]
and then do
pplevel_map += sizeof(**maps);
to seek to maps[dlvl][1].
And then access map[dlvl][1]'s element (also) like this:
pplevel_map[x]
Update^2
To still be able access all "level"'s elements using [x][y] you could do:
TileType (*aplevel_map)[LEVEL_WIDTH] = maps[dlvl];
And then access map[dlvl]'s element like this:
aplevel_map[x][y]

TileType level_map[LEVEL_HEIGHT][LEVEL_WIDTH] = &(maps[dlvl]);
You can't do that because level_map is array, and array cannot be reassigned.
What you need is memcpy. Given what you need to assign to level_map is the first element of 3D maps (at index 0):
memcpy(level_map, &maps[0], sizeof(level_map));
You can do the same for other elements.
Edit:
I should have been clearer -- I'd like assignments to level_map elements to assign to the corresponding map element
Ok then you need to declare a pointer instead of array:
TileType (*level_map)[LEVEL_HEIGHT][LEVEL_WIDTH]; // pointer to 2D array
level_map = &maps[0]; // reassign pointer to the address of `maps` first element

Do yourself a favour
TileType maps[DLVL_MAX * LEVEL_HEIGHT* LEVEL_WIDTH];
Now always pass maps, and levelid (guess that's what you mean), y
co-ordinate, and x co-ordinate.
void foo(TileType *maps, int levelid, int x, int y)
{
TileType tile = BLANK;
map[levelid * LEVEL_HEIGHT * LEVEL_WIDTH + y * LEVEL_WIDTH + x]
= tile;
}
Then the problems just disappear.
The expression is a bit cumbersome, but you soon learn to live with it.

Related

Try to pass an array of int in a custom function, doens't get the content of the array in the custom function

I try to create an array of int in C, and then, use it in a custom function :
int a[] = {1,3,5,7,9};
int* new_a = extract(a, 2, 4);
// ...
int *extract(int* T, int a, int b){
int lenght_T = getLenghtOfSimpleArray(T);
...
}
I use the IDE visual code, when I inspect the code through the degugger, I get :
I don't understand why, in the debugger, the value of T is not {1,3,5,7,9}...
Where is my mystake ?
When you pass an array to a function it gets degraded to a pointer that points to the first element of the array. That means, T is an address in memory, so the big hex value shown in the debugger looks normal.
The debugger also shows *T, which is the value where the pointer points to, i.e. the first element of the array. The value is 1 as expected.
There is no way to find out the size/length of an array passed to a function this way, so it is not possible to make a working function getLenghtOfSimpleArray, except if you define an "invalid" value (sentinel value) which must be put to the last element of the array. In the general case, the caller must pass the size of the array to the function in addition to the array name = pointer to the first element.
example code with passing the array length
int a[] = {1,3,5,7,9};
int* new_a = extract(a, sizeof(a) / sizeof(a[0]), 2, 4);
int *extract(int* T, size_t length, int a, int b){
int lenght_T = getLenghtOfSimpleArray(T);
...
}
Arrays are not pointers. Pointers are not arrays.
T is not an array, it's a pointer to the first element. As you can see from your debugger, *T is 1, which is that first element.
Most debuggers support watches such as T[1] etc if you wish to inspect individual items beyond the first. Or they have a "range" feature that allows you to view a number of items.
In C, arrays are just values in the memory right next to each other, and the pointer only points to the first entry.
So in your case if you want to access the other values you have to access them with T[index]
The debugger only shows the first value of the array in this case.

C# - Tuple arrays are mutable, but tuple lists are not. How do I get around this?

I have an array of value pairs I want to modify. I need to add and remove values from this array as well, so I used a list. When I tried to use a list, I encountered an error.
Error CS1612 - Cannot modify the return value of 'List<(int, float)>.this[int]' because it is not a variable
So I decided I would investigate. I tried using an array instead, and it... worked fine? The following code only throws an error on arr1[0].Item1 += 1;.
static void Main()
{
List<(int, float)> arr1 = new List<(int, float)>() { (0, 0) };
(int, float)[] arr2 = new (int, float)[1];
arr1[0].Item1 += 1; // This line
arr2[0].Item1 += 1;
}
Why are tuple arrays mutable, but lists are not? Is this because arrays are simple blocks of data you can modify easily, but lists have a lot of backend behind them that complicates things? Is there a simple way to get around this, or am I going to have to make my own custom class?
Why are tuple arrays mutable, but lists are not?
The list itself is mutable, but not in the way you're doing it. Note that this isn't anything specific to tuples - it's just the case for any mutable struct.
The list indexer getter returns a value (i.e. a copy of the tuple in your case) - so modifying that value wouldn't modify the copy in the list. The compiler is trying to avoid you making a change to a value that's about to be thrown away. Array access doesn't do that - arr2[0] refers to the variable within the array. (An array is effectively a collection of variables.)
If you want to mutate the list, you can have to fetch the tuple, mutate it, then put it back:
var tuple = arr1[0];
tuple.Item1++;
arr1[0] = tuple;
Note that this also explains why you can't use list access expressions as arguments for ref parameters, but you can do the equivalent for arrays:
public void Method(ref int x) => x++;
public void CallMethod()
{
var list = new List<int> { 0 };
var array = new int[] { 0 };
Method(ref list[0]); // Error
Method(ref array[0]); // Valid
}

Multidimensional-array in Ceylon

I would like to work in Ceylon with a multidimensional array. Is this planned in Ceylon? If so, how can I declare it?
I would like to use this construct in Ceylon, as shown here in Java:
int x = 5;
int y = 5;
String[][] myStringArray = new String [x][y];
myStringArray[2][2] = "a string";
First, consider whether you really need an array (i.e. something with fixed length and modifiable elements), or whether a list (or list of lists) or a map might be better. Though from your example, you seem to need modification.
In the JVM, a "multidimensional" array is just an array of arrays.
In Java, new String[y] creates an array filled with null entries, which is not an allowed value of type String in Ceylon. So you can either have an array of String? (which allows null), or pre-fill your array with some other value, using e.g. Array.ofSize(...):
Array.ofSize(y, "hello")
The same is valid for arrays of arrays. We could do this:
value myStringArray = Array.ofSize(x, Array.ofSize(y, "hello"));
Though this would have the same array in each "row" of the 2D-array, which is not what we want (as replacing myStringArray[2][2] would replace all entries with a 2 as the second coordinate). Here the other Array constructor is useful, which takes an iterable:
value myStringArray = Array({ Array.ofSize(y, "hello") }.repeat(x));
This takes advantage of the fact that the iterable enumeration evaluates its arguments lazily, and thus the array constructor will get x different elements.
I like Paulo's answer, but here's an alternative approach, which allows us to use a comprehension to populate the 2D array:
//the size of the square 2D array
value n = 5;
//create it using a nested comprehension
value arr = Array {
for (i in 1..n-1) Array {
for (j in 0..n-1)
i==j then 1 else 0
}
};
//display it
for (row in arr) {
printAll(row);
}

Adding a struct to an array

Given a struct Element:
typedef struct {
char someString[9]
int value;
} Element
and an array elementList:
Element elementList[5];
is there an easy way to dynamically add an Element to each index of the list? I have tried creating a function add_element that takes in the list and modifies it there but I'd prefer something equivalent to Java's elementList[i] = new Element.
There's no need, that array consists of structure instances.
You can do e.g.:
strcpy(elementList[0].someString, "foo");
elementList[0].value = 4711;
This is not possible in Java, where everything is a reference, but in C you can do this. If you want a bunch of NULL-able references, in C you use pointers:
Element *elementList[5]; /* An array of 5 pointers to type Element. */
Then you have to use e.g. heap allocations to make sure there is memory before accessing the Element:
elementList[0] = malloc(sizeof *elementList[0]); /* This might fail! */
elementList[0]->value = 17;
As declared, you've created a 5-element array of Element instances; there's no need to allocate new Element objects. You can go ahead and read/assign each member of each element:
element[i].value = some_value();
strcpy( element[i].someString, some_string() );
If you want to emulate the Java method, you'd do something like the following:
Element *elementList[5]; // create elementList as an array of *pointers* to Element
...
elementList[i] = malloc( sizeof *elementList[i] ); // dynamically allocate each element
Note that in this case, you'd use the -> operator instead of the . operator to access each Element member, since each elementList[i] is a pointer to Element, not an Element instance:
elementList[i]->value = some_value();
strcpy( elementList[i]->someString, some_string() );
In either case, the array size is fixed; you cannot grow or shrink the number of elements in the array.

C Programming: Pointer to a row of a 2D array?

I wrote a function that returns a pointer to a 1D array. The function prototype is:
double* NameFunction (int,double*,double*)
The function seems to work fine with 1D array.
Here's the question: I'd like to use the function to fill one row of a 2D array.
How do I write in the calling function a pointer to the row of the 2D array to fill?
Can I use the same pointer structure to indicate a row of a 2D array as argument?
Yes just pass the name of the 2D array with the first index filled in:
NameFunction (12121212,&array[0],some pointer here) // for example if you want to pass the first row
A variable pointing to an array in C always contains just an address location i.e., the pointer to the starting of the array. So, whatever the array type, it just needs a pointer which is a *.So this function should work as it is now.
But you may need to change some programming logic.
You can take double foo[20] as 1×20 array, or you can take it as two-dimensional 4×5 array. Then you have the coordinates like this:
foo foo+1 foo+2 foo+3 foo+4
foo+5 foo+6 foo+7 foo+8 foo+9
foo+10 foo+11 foo+12 foo+13 foo+14
foo+15 foo+16 foo+17 foo+18 foo+19
So if you have a function that returns double *, you can pass it (or make it return) foo + 5*n to point at row n.
#define ROW_LEN 5
#define ROWS 4
void fillRow(double * row)
{
int i;
for (i = 0; i < ROW_LEN; i++)
{
row[i] = 12;
(row + i) = 12; // this is the same thing written differently
}
}
double arr[ROW_LEN * ROWS];
fillRow(arr + 2 * ROW_LEN); // fill third row
Note that C does not do any range checking at all, so if you are not careful and accidentally to something like arr[627] = 553 somewhere in your code, it's going to blindly overwrite everything that is at the computed address in the memory.

Resources