Accessing portions of a dynamic array in C? - c

I know, another dynamic array question, this one is a bit different though so maybe it'll be worth answering. I am making a terrain generator in C with SDL, I am drawing 9 chunks surrounding the screen, proportional to the screen size, that way terrains can be generated easier in the future.
This means that I have to be able to resize the array at any given point, so I made a dynamic array (at least according to an answer I found on stack it is) and everything SEEMS to work fine, nothing is crashing, it even draws a single tile....but just one. I am looking at it and yeah, sure enough it's iterating through the array but only writing to one portion of memory. I am using a struct called Tile that just holds the x, y, w, and h of a rectangle.
This is the code I am using to allocate the array
Tile* TileMap = (Tile*)malloc(0 * sizeof(Tile*));
int arrayLen = sizeof(TileMap);
TileMap = (Tile*)realloc(TileMap, (totalTiles) * sizeof(Tile));
arrayLen = sizeof(totalTiles * sizeof(Tile));
The totalTiles are just the number of tiles that I have calculated previously are on the screen, I've checked the math and it's correct, and it even allocates the proper amount of memory. Here is the code I use to initialize the array:
//Clear all elements to zero.
for (int i = 0; i < arrayLen; i++)
{
Tile tile = {};
TileMap[i] = tile;
}
So what's weird to me is it is considering the size of a tile (16 bytes) * the totalTiles (78,000) is equaling 4....When I drill down into the array, it only has one single rect in it that gets cleared as well, so then when I go calculate the sizes of each tile:
//Figure out Y and heights
for (int i = startY; i <= (startY*(-1)) * 2; i += TILE_HEIGHT)
{
TileMap[i].y = i * TILE_HEIGHT;
TileMap[i].h = TILE_HEIGHT;
//Figure out X and widths
for (int j = startX; j <= (startX*(-1)) * 2; j += TILE_WIDTH)
{
TileMap[i].x = i * TILE_WIDTH;
TileMap[i].w = TILE_WIDTH;
}
}
*Side note, the startX is the negative offset I am using to draw chunks behind the camera, so I times it by -1 to make it positive and then time it by two to get one chunk in front of the camera
Alright, so obviously that only initializes one, and here is the render code
for (int i = 0; i < totalTiles; i++)
{
SDL_Rect currentTile;
currentTile.x = TileMap[i].x;
currentTile.y = TileMap[i].y;
currentTile.w = TileMap[i].w;
currentTile.h = TileMap[i].h;
SDL_RenderDrawRect(renderer, &currentTile);
}
free(TileMap);
So what am I doing wrong here? I mean I literally am just baffled right now...And before Vectors get recommended in place of dynamic arrays, I don't really like using them and I want to learn to deal with stuff like this, not just implement some simple fix.

Lots of confusion (which is commonplace with C pointers).
The following code doesn't provide expected answer :arrayLen = sizeof(totalTiles * sizeof(Tile));
totalTiles * sizeof(Tile) is not even a type, I'm surprised it compiles at all. Edit : See molbnilo comment below. so it provides the size of the return type.
Anyway, proper answer should be :
arrayLen = totalTiles;
Because that's what you need in your next loop :
//Clear all elements to zero.
for (int i = 0; i < arrayLen; i++)
{
Tile tile = {};
TileMap[i] = tile;
}
You don't need the size of the table, you need its number of elements.
There are other confusions in your sample, they don't directly impact the rest of the code, but better correct them :
Tile* TileMap = (Tile*)malloc(0 * sizeof(Tile*)); : avoid allocating a size of 0.
int arrayLen = sizeof(TileMap); : no, it's not the arrayLen, just the size of the pointer (hence 4 bytes on 32-bits binaries). Remember TileMap is not defined as a table, but as a pointer allocated with malloc() and then realloc().

Related

Segfault when trying to dynamicaly realocate a 2 dimensional array

I'm working on a system that has several structs area that interact with each other, the areas are stored in a regular array called storage, which is dynamically reallocated whenever you need to add or remove them.
The way I'm handling the interactions is with a 2-dimensional array called overlap, that stores 1 byte values. There are a column and a row for every single element of the storage.
The value at overlap[x][y] represents the interaction that the element storage[x] had with the element storage[y].
The areas also have layers and layerMasks that control with which elements they can interact.
For example, an area in layer 1 with the masks 2, 3, and 4. May interact only with areas in the layer 2, 3 and 4. And can only be interacted with by areas with mask 1. The layers range from 0 to 63.
In order to do this, I need to position the areas inside the storage and overlap in a way that I'll be able to distinguish the layers, and for that, I'll be using the array sPosthat stands for storage position. This array will have 65 elements, one for each layer plus one. The values in sPos are the position of the first area in the storage that is in a layer equal or bigger than the sPos' value's index, and sPos[64] is the size of the storage.
This is how I'm handling things:
area * addArea(area * toAdd) {
// realocating the storage and overlap.
storage = realloc(storage, sizeof(area *) * (sPos[64] + 1));
if (!storage) {error handling} // Error handling is a printf("addArea\n") and a return NULL.
overlap = realloc(overlap, sizeof(unsigned char *) * (sPos[64] + 1));
if (!overlap) {error handling}
// Realloc works as malloc for NULL pointers, so setting this to NULL will allocate it when reallocating the rows.
overlap[sPos[64]] = NULL;
// Moving the elements in layers greater than or equal to toAdd->layer.
for (int i = sPos[64]; i > sPos[toAdd->layer]; i--) overlap[i + 1] = overlap[i];
// reallocating the rows of the overlap, and moving their elements as well.
for (int i = 0; i < sPos[64]; i++) {
overlap[i] = realloc(overlap[i], sizeof(unsigned char) * sPos[64] + 1);
if (!overlap[i]) {error handling}
for (int j = sPos[64]; j > sPos[toAdd->layer]; j--) overlap[i][j + 1] = overlap[i][j];
}
// Seting the new elements of overlap to 0 (no interaction).
for (int i = 0; i <= sPos[64]; i++) {
overlap[sPos[toAdd->layer]][i] = 0;
overlap[i][sPos[toAdd->layer]] = 0;
}
// Moving the elements in storage to place toAdd in the position sPos[toAdd->layer]
for (int i = sPos[64]; i > sPos[toAdd->layer]; i--) storage[i] = storage[i - 1];
storage[sPos[toAdd->layer]] = toAdd;
// Adding 1 to every element of sPos with an index greater than toAdd->layer.
for (int i = toAdd->layer + 1; i <= 64; i++) sPos[i]++;
return toAdd; // returns the argument, or NULL in case of error.
}
When adding areas with different layers, nothing bad seems to happen. But when I try to add areas in the same layer I get a segfault with no error warnings called. usually when having 4 or more elements and trying to add one in an occupied layer.
Using gdb, I figured that the error happens when reallocating the rows of overlap, but I can't quite understand why.
First, to improve the readability and debuggability of your code, don't try to inline a statement on the same line as a for-loop declaration.
That is, don't do this:
for (int i = 0; i < N; i++) doSomething(i);
Do this:
for (int i = 0; i < N; i++) {
doSomething(i);
}
The above is just plain easier to use when stepping through in the debugger line by line.
Back to the original problem at hand. Your memory corruption issue.
You allocated this:
overlap = realloc(overlap, sizeof(Unsigned char *) * (sPos[64] + 1));
Let's imagine sPos[64] was equal to 10. Therefore you allocated 10+1 == 11 bytes.
Thus, valid array index values for overlap are from [0..10] inclusive.
Then you initialize your array as follows:
for (int i = sPos[64]; i > sPos[toAdd->layer]; i--) {
overlap[i + 1] = overlap[i];
}
The first statement executed within the for loop would then be:
overlap[11] = overlap[10];
Oops! overlap[11] is out of range. Hence, undefined behavior when you write to that memory location. You probably corrupted the heap.
You probably want to something like this instead (I'm making assumptions about what you are really trying to do)
int lastIndex = sPos[64];
int firstIndex = toAdd->layer + 1;
for (int i = lastIndex; i >= firstIndex; i--) {
overlap[i] = overlap[i-1];
}
Also, you could use memmove to do this work for you, provided you calculate the pointer math correctly. (Again, I'm making assumptions on your array boundaries):
memmove(overlap+firstIndex+1, overlap+firstInex, lastIndex-firstIndex);
I'm also going to point out that when you attempt to do this array shift to the right, there's absolutely no guarantee that overlap[i-1] doesn't point to garbage. If your realloc size is less than or equal to the original allocated length of that array, you're fine. But if it's "growing" the array, you should assume that realloc returned a completely new array and the original overlap array has been trashed.
My overall advice is for you to be cognizant of what the valid array indices are for each array you have allocated when you use them in a loop. It's quite possible this isn't your only "off by 1 error".

most efficient way to move Array elements (pure C, no stdlib)?

so i am writing a program, and i want to move all elements in the array N places to the left. wether the first elements of the array get added to the end or deleted: i don't care, the last N elements need to be nulled out anyway. i could ofcourse just make a copy of that array.
like this:
int *buffer = [loads of elements, these get assigned dynamically];
int *tmpbuffer = buffer;
for (int i = 0; i < sizeof(buffer); i++) {
buffer[i] = tmpbuffer[i + N];
}
(please ignore any pointer and sizeof mistakes, this is a really quick sketch)
but i doubt that'll be efficient at all. this is an array with roughly 4400 elements. but that will be expanded to a LOT more elements later.
what am i trying to do?
see it like a terminal program, but slightly different. so there are a few text lines, and when there are more than N lines, the top most line will be deleted and there will be a new line at the bottom. even though this sounds like a 3d array (one array for all the vertical lines, and one for the text lines), it's not.
this is done without any external library's, because it's for a "kernel". (you might say that i am prob not skilled enough to do so, and you're definetly right, right now i only have VGA ouput and basic terminal, but when all lines are filled, it just erases the entire screen. i just like to learn this way: have an objective and chase it.)
i hope i provided enough info. if i didn't i'll try to provide it.
Your approach
// sizeof(buffer) is sizeof (apointer); I replaced that with (nelems - N)
for (int i = 0; i < nelems - N; i++) {
buffer[i] = tmpbuffer[i + N];
}
looks very efficient to me.
You may want to compare with a pure pointer-based approach, but I doubt there will be any difference
src = buffer + N;
dst = buffer;
for (int i = 0; i < nelems - N; i++) *dst++ = *src++;

C: How to generate a fixed number of objects with an array of pointers

I would like to create 11 text layers for a pebble watch face.
Without a loop the code would look something like.
static TextLayer *time_layer_a;
static TextLayer *time_layer_b;
... and so on.
How can I do this with a loop and put the pointers to the the objects in a list like structure?
list: in this case array or chain would be a better word because the collection of pointers is for a display with a fixed number of text layers. And the number of layers will not be changed during the duration of the program. In C, a list is a structure that can be dynamically resized. Using "list like" could mislead helpful people to the assumption that the sought method of chaining is expected to be dynamic. This is not correct. A structure that uses a fixed allocation of memory is preferred.
Edit: an array as suggested by John3136 worked perfectly. The array has the added benefit of generating the object pointers with its deceleration. And it's a plus that John3136 gave a way to have the code automatically adjust to the size of the array. This is a useful tool to have.
Here is the code as applied to create text layers for my watch face.
declarations:
int i;
static TextLayer* layers[11];
loading method:
// by John3136
// Note the sizeof() stuff means this works unchanged even if you change
// the number of layers.
for(i = 0; i < (short)(sizeof(layers) / sizeof(layers[0])); i++) // (short) converts unsigned interger to +- int
{
layers[i] = text_layer_create(GRect((bounds.size.w/4)*((i + 1)%4),
(bounds.size.h/PBL_IF_ROUND_ELSE(5,4))*((i > 2)
? ((i > 6)
? 3
: 2 )
: 1),
(bounds.size.w / 4) ,(bounds.size.h/PBL_IF_ROUND_ELSE(5,4))));
}
unloading method:
for(i = 0; i < (short)(sizeof(layers) / sizeof(layers[0])); i++)
{
text_layer_destroy(layers[i]);
}
Easiest way that meets your requirements as we know them: An array of 11 pointers to TextLayers.
static TextLayer* layers[11];
You can then populate with:
int i;
// Note the sizeof() stuff means this works unchanged even if you change
// the number of layers.
for(i = 0; i < sizeof(layers) / sizeof(layers[0]); i++)
{
layers[i] = some_func_that_creates_a_layer();
}

Shifting by 1 an array of C structures

I have an array of structures that I am trying to shift left by 1 array node. The total size of the array is huge (about 3 gigabytes), so even though I know the exact size of array I need, it is too big to declare on the stack (even though I have 16 gig of ram and am writing a 64bit program), thus complicating things by forcing me to do dynamic memory alloc:
struct s_ptx
{
short streamIndex;
double raw;
char rawDx;
} *Ptx[100];
void allocateMemory(void)
{
ptxTotal = 300;
for (int i = 0; i < 100; ++i)
Ptx[i] = (struct s_ptx*) calloc( ptxTotal, sizeof(struct s_ptx));
}
void shiftDataStructures(void)
{
for (int j = 100 - 1; j > 0; --j)
Ptx[j] = Ptx[j - 1];
}
But I get wrong results, because the shiftDataStructures function is not working. Any ideas of how I need to rewrite this.
You are not shifting structs, only pointers. I wonder what you really are thinking you are achieving here?
Also, why do you need to shift array indexes at all, why not use, say, linked list or a ring buffer. As to what the error itself would be, I have no clue because you provide insufficient data; your loop is running in correct direction as not to overwrite the pointers.
Try swapping the data inside the structures of instead of shifting the pointers. The resultant will result in a circular array where Ptx[99] will be circulated to Ptx[0].
Sample code:
// Change codes in the following line
for (int j = 100 - 1; j > 0; --j)
//Ptx[j] = Ptx[j - 1];
swap(Ptx[j], Ptx[j - 1]);

How do you dynamically allocate a contiguous 3D array in C?

In C, I want to loop through an array in this order
for(int z = 0; z < NZ; z++)
for(int x = 0; x < NX; x++)
for(int y = 0; y < NY; y++)
3Darray[x][y][z] = 100;
How do I create this array in such a way that 3Darray[0][1][0] comes right before 3Darray[0][2][0] in memory?
I can get an initialization to work that gives me "z-major" ordering, but I really want a y-major ordering for this 3d array
This is the code I have been trying to use:
char *space;
char ***Arr3D;
int y, z;
ptrdiff_t diff;
space = malloc(X_DIM * Y_DIM * Z_DIM * sizeof(char))
Arr3D = malloc(Z_DIM * sizeof(char **));
for (z = 0; z < Z_DIM; z++)
{
Arr3D[z] = malloc(Y_DIM * sizeof(char *));
for (y = 0; y < Y_DIM; y++)
{
Arr3D[z][y] = space + (z*(X_DIM * Y_DIM) + y*X_DIM);
}
}
You can't change the array ordering implicit in the language. The array ordering is standard in C.
If you want to change the way your ordering occurs, just change how you access your array, ie: [x][z][y] instead of [x][y][z].
I think the only way to do this is to write your own wind/unwind functionality on a contiguous datastore. In other words you are going to have to write your own map to calculate the storage position of your values.
If you are trying to make a certain order traversal of your array more efficient, you could always transform the incoming matrix before you put it into the array and then do the transform again when you get it out. C style multi-dimensional arrays are packed order, so the math might get a bit tricky (and is beyond what I can detail out here in the time I have).
Sorry for not having a better answer, but I hope that helps
Using an array of pointers can speed things up, but at the cost of greater complexity. If you're not certain you need the performance, then you might try using a C macro:
#define ARR3D(x,y,z) space[(x) + XDIM*((y) + Y_DIM*(z))]
This assumes that x, y, and z are the innermost, middle, and outermost dimensions, respectively.
Pseudocode:
malloc a chunk of memory big enough for
the char *** pointer for z,
the char ** pointers for y, which will get pointed to by zs
the char * pointers for x, which will get pointed to by ys
the big block of data that they will, in the end, be pointed to by xs
assign z's, y's, x's so that
contiguous blocks from the big block of data are adjacent in the y dimension
(instead of adjacent in the x dimension, as would be normal)
I have done the single-malloc trick for 2D arrays, simply because of the mental exercise and the added convenience of a single malloc / single free, and it works beautifully (just make sure to get a well-aligned memory chunk). I never thought of using this to subvert memory adjacency.

Resources