Segfault when trying to dynamicaly realocate a 2 dimensional array - arrays

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".

Related

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++;

2-D matrices using malloc failing to assign correct values

sorry, I'm relatively new to c and am trying to create two 2-D arrays using malloc. I was told that this method is computationally more efficient than creating a pointer array of arrays through a for loop (for large arrays).
int i, j;
double **PNow, **PNext, *Array2D1, *Array2D2;
//Allocate memory
PNow = (double**)malloc(3 * sizeof(double*));
PNext = (double**)malloc(3 * sizeof(double*));
Array2D1 = (double*)malloc(5 * sizeof(double));
Array2D2 = (double*)malloc(5 * sizeof(double));
//Create 2-Dimensionality
for(i = 0; i < 3; i++)
{
PNow[i] = Array2D1 + i * 5;
PNext[i] = Array2D2 + i * 5;
};
//Define Element Values
for(i = 0; i < 3; i++)
{
for(j = 0; j < 5; j++)
{
PNow[i][j] = 10.*(i + j);
PNext[i][j] = 1000.*(i + j);
};
};
//Output two matrices side-by-side.
for(i = 0; i < 3; i++)
{
for(j = 0; j < 5; j++)
{
printf("%6lg", PNow[i][j]);
if(j == 4)
{
printf("|");
};
};
for(j = 0; j < 5; j++)
{
printf("%6lg", PNext[i][j]);
if(j == 4)
{
printf("\n");
};
};
};
My problem is that the first matrix (PNow) turns out as I would expect, but for some reason half of the values in PNext are those of PNow, and I can't for the life of me figure out why it is doing this? I'm obviously missing something.. Also I am not overly clear on what "Array2D1 + i*5" is doing and how this makes PNow a 2-D array?
Any help would be really appreciated.
Thank you.
P.S. This is the output that I am getting, so you can see what I mean:
0 10 20 30 40| 20 30 40 50 20
10 20 30 40 50| 30 40 50 60 5000
20 30 40 50 60| 2000 3000 4000 5000 6000
In C you don't cast the result of mallocs, so your malloc lines should read
PNow = malloc(3*sizeof(double*));
Your problem is you're not actually allocating enough memory in Array2D1 and Array2D2. When you move past the first "row" in your array you're getting beyond your allocated memory! So you're in undefined behavior territory. In your case, it looks like your two matrices step all over each other (though my test just throws an error). You can solve this in two ways:
Specify the full size of your matrix in the malloc and do as you did:
Array2D1 = malloc(15*sizeof(double));
Array2D2 = malloc(15*sizeof(double));
Or malloc each line in your for loop:
for(i=0; i<3; i++){
PNow[i] = malloc(5*sizeof(double));
PNext[i] = malloc(5*sizeof(double));
}
Edit: On the topic of freeing in each example
For the first example, the freeing is straight forward
free(PNow);
free(PNext);
free(Array2D1);
free(Array2D2);
For the second, you must iterate through each line and free individually
for (i = 0; i < 3; i++) {
free(PNow[i]);
free(PNext[i]);
}
Edit2: Realistically, if you're going to hardcode your rows and columns in with a pre-processor macro, there's no reason to malloc at all. You can simply do this:
#define ROW 3
#define COL 5
double PNow[ROW][COL], PNext[ROW][COL];
Edit3: As for what Array2D1 + i * 5 is doing, PNow is an array of pointers, and Array2D1 is a pointer. By adding i * 5 you're incrementing the pointer by i * 5 (i.e., saying "give me a pointer to the memory that is i * 5 doubles away from Array2D1). So, you're filling PNow with pointers to the starts of appropriately sized memory chunks for your rows.
You code does not have 2D arrays, aka matrices. And your pointers cannot point to such an object either.
A proper pointer which can point to a 2D array would be declared like:
#define ROWS 4
#define COLS 5
double (*arr)[COLS];
Allocation is straight-forward:
arr = malloc(sizeof(*arr) * ROWS);
And deleting similar:
free(arr);
Indexing is like:
arr[row][col]
Notice the identical syntax only. The semantics are different.
Nothing more necessary and no need for hand-crafted pointer arrays.
The code above shows another important rule: Don't use magic values. Use constant-like macros instead. These should be #defined at the beginning or in a configuration-section of the code (typically somewhere near the top of the file or a distinct header file). So if you lateron change e.g. the length of a dimension, you don't have to edit all places you explicitly wrote it, but only change the macro once.
While the code above uses constants, you can as well use variables for the dimensions. This is standard C and called variable length array (VLA). If you pass the arrays to other functions, you have to pass them as additional arguments:
void f(size_t rows, size_t cols, double a[rows][cols]);
Remember array-arguments decay to pointers to the first element, so a is actually the same as arr above. The outermost dimension can be omitted, but as you need it anyway it is good for documentation to specify it, too.

Accessing portions of a dynamic array in 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().

Trimming an int array for bucket sort in C

I am writing a bucket sort program in C. After I merge small buckets into a large bucket, I need to remove the -1s I padded the small buckets with.
I'm pretty new to C, so there could be a very simple solution that I am overlooking.
This was my solution, which seems to return an array with 1 trailing junk value and trailing 0s that fill the array until it is the size of the untrimmed bucket (where the desired result is a bucket without -1s, junk values, and trailing 0s).
// A function to trim a bucket of a given size to a bucket containing no -1s
int* trimBucket(int* bucket, int size)
{
int n = 0, i = 0;
int* newBucket;
// This loop is to count the number of elements between 0 and 9999
for(n = 0; n < size; n++)
{
if(bucket[n] != -1 && bucket[n] < 10000)
i++;
}
// Create a new bucket equal to the number of elements counted
// Filled with -2 to differentiate from -1s contained in the bucket array
newBucket = allocateAndInitiateOneD(i, -2);
i = 0;
for(n = 0; n < size; n++)
{
// I only want values between 0-9999 to be put into the new array
if(bucket[n] != -1 && bucket[n] < 10000)
{
newBucket[i] = bucket[n];
i++;
}
}
free(bucket); // Am I doing this right?
return newBucket;
}
allocateAndInitiateOneD function:
// A function to allocate memory for a one dimensional array and fill it with the given value
int* allocateAndInitiateOneD(int x, int initialNum)
{
int runs = 0;
int* oneArray;
oneArray = malloc(sizeof(int) * x);
for(runs = 0; runs < x; runs++)
oneArray[runs] = initialNum;
return oneArray;
}
Could someone please help me understand what I'm doing wrong and how I could get the desired result?
Thanks for the help!
edit: I am compiling and running on a Unix system. Possibly not related, but this is a multi-processed program using the MPI library (this doesn't seem to be where the problem lies).
Looks like everything is working, but you need to return the new size from this function as well, without the idea of the length of the array, you can read right off the end of your newly chosen size and it will look like garbage (1 trailing junk value & all zeroes...).
An array in C has two pieces, always. Start pointer, and size. Sometimes the size is implicit, but it needs to be there somehow, or you'll just keep reading forever.
If you need to return multiple things from a function, either:
return (one or both) via a pointer parameter
return them both through a struct

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]);

Resources