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++;
Related
I'm totally new here but I heard a lot about this site and now that I've been accepted for a 7 months software development 'bootcamp' I'm sharpening my C knowledge for an upcoming test.
I've been assigned a question on a test that I've passed already, but I did not finish that question and it bothers me quite a lot.
The question was a task to write a program in C that moves a character (char) array's cells by 1 to the left (it doesn't quite matter in which direction for me, but the question specified left). And I also took upon myself NOT to use a temporary array/stack or any other structure to hold the entire array data during execution.
So a 'string' or array of chars containing '0' '1' '2' 'A' 'B' 'C' will become
'1' '2' 'A' 'B' 'C' '0' after using the function once.
Writing this was no problem, I believe I ended up with something similar to:
void ArrayCharMoveLeft(char arr[], int arrsize, int times) {
int i;
for (i = 0; i <= arrsize ; i++) {
ArraySwap2CellsChar(arr, i, i+1);
}
}
As you can see the function is somewhat modular since it allows to input how many times the cells need to move or shift to the left. I did not implement it, but that was the idea.
As far as I know there are 3 ways to make this:
Loop ArrayCharMoveLeft times times. This feels instinctively inefficient.
Use recursion in ArrayCharMoveLeft. This should resemble the first solution, but I'm not 100% sure on how to implement this.
This is the way I'm trying to figure out: No loop within loop, no recursion, no temporary array, the program will know how to move the cells x times to the left/right without any issues.
The problem is that after swapping say N times of cells in the array, the remaining array size - times are sometimes not organized. For example:
Using ArrayCharMoveLeft with 3 as times with our given array mentioned above will yield
ABC021 instead of the expected value of ABC012.
I've run the following function for this:
int i;
char* lastcell;
if (!(times % arrsize))
{
printf("Nothing to move!\n");
return;
}
times = times % arrsize;
// Input checking. in case user inputs multiples of the array size, auto reduce to array size reminder
for (i = 0; i < arrsize-times; i++) {
printf("I = %d ", i);
PrintArray(arr, arrsize);
ArraySwap2CellsChar(arr, i, i+times);
}
As you can see the for runs from 0 to array size - times. If this function is used, say with an array containing 14 chars. Then using times = 5 will make the for run from 0 to 9, so cells 10 - 14 are NOT in order (but the rest are).
The worst thing about this is that the remaining cells always maintain the sequence, but at different position. Meaning instead of 0123 they could be 3012 or 2301... etc.
I've run different arrays on different times values and didn't find a particular pattern such as "if remaining cells = 3 then use ArrayCharMoveLeft on remaining cells with times = 1).
It always seem to be 1 out of 2 options: the remaining cells are in order, or shifted with different values. It seems to be something similar to this:
times shift+direction to allign
1 0
2 0
3 0
4 1R
5 3R
6 5R
7 3R
8 1R
the numbers change with different times and arrays. Anyone got an idea for this?
even if you use recursion or loops within loops, I'd like to hear a possible solution. Only firm rule for this is not to use a temporary array.
Thanks in advance!
If irrespective of efficiency or simplicity for the purpose of studying you want to use only exchanges of two array elements with ArraySwap2CellsChar, you can keep your loop with some adjustment. As you noted, the given for (i = 0; i < arrsize-times; i++) loop leaves the last times elements out of place. In order to correctly place all elements, the loop condition has to be i < arrsize-1 (one less suffices because if every element but the last is correct, the last one must be right, too). Of course when i runs nearly up to arrsize, i+times can't be kept as the other swap index; instead, the correct index j of the element which is to be put at index i has to be computed. This computation turns out somewhat tricky, due to the element having been swapped already from its original place. Here's a modified variant of your loop:
for (i = 0; i < arrsize-1; i++)
{
printf("i = %d ", i);
int j = i+times;
while (arrsize <= j) j %= arrsize, j += (i-j+times-1)/times*times;
printf("j = %d ", j);
PrintArray(arr, arrsize);
ArraySwap2CellsChar(arr, i, j);
}
Use standard library functions memcpy, memmove, etc as they are very optimized for your platform.
Use the correct type for sizes - size_t not int
char *ArrayCharMoveLeft(char *arr, const size_t arrsize, size_t ntimes)
{
ntimes %= arrsize;
if(ntimes)
{
char temp[ntimes];
memcpy(temp, arr, ntimes);
memmove(arr, arr + ntimes, arrsize - ntimes);
memcpy(arr + arrsize - ntimes, temp, ntimes);
}
return arr;
}
But you want it without the temporary array (more memory efficient, very bad performance-wise):
char *ArrayCharMoveLeft(char *arr, size_t arrsize, size_t ntimes)
{
ntimes %= arrsize;
while(ntimes--)
{
char temp = arr[0];
memmove(arr, arr + 1, arrsize - 1);
arr[arrsize -1] = temp;
}
return arr;
}
https://godbolt.org/z/od68dKTWq
https://godbolt.org/z/noah9zdYY
Disclaimer: I'm not sure if it's common to share a full working code here or not, since this is literally my first question asked here, so I'll refrain from doing so assuming the idea is answering specific questions, and not providing an example solution for grabs (which might defeat the purpose of studying and exploring C). This argument is backed by the fact that this specific task is derived from a programing test used by a programing course and it's purpose is to filter out applicants who aren't fit for intense 7 months training in software development. If you still wish to see my code, message me privately.
So, with a great amount of help from #Armali I'm happy to announce the question is answered! Together we came up with a function that takes an array of characters in C (string), and without using any previously written libraries (such as strings.h), or even a temporary array, it rotates all the cells in the array N times to the left.
Example: using ArrayCharMoveLeft() on the following array with N = 5:
Original array: 0123456789ABCDEF
Updated array: 56789ABCDEF01234
As you can see the first cell (0) is now the sixth cell (5), the 2nd cell is the 7th cell and so on. So each cell was moved to the left 5 times. The first 5 cells 'overflow' to the end of the array and now appear as the Last 5 cells, while maintaining their order.
The function works with various array lengths and N values.
This is not any sort of achievement, but rather an attempt to execute the task with as little variables as possible (only 4 ints, besides the char array, also counting the sub function used to swap the cells).
It was achieved using a nested loop so by no means its efficient runtime-wise, just memory wise, while still being self-coded functions, with no external libraries used (except stdio.h).
Refer to Armali's posted solution, it should get you the answer for this question.
I am trying to compare linear memory access to random memory access. I am traversing an array in the order of its indices to log performance of linear memory access. However to log memory's performance with random memory access I want to traverse my array randomly i.e arr[8], arr[17], arr[34], arr[2]...
Can I use pointer chasing to achieve this while ensuring that no index are accessed twice? Is pointer chasing most optimal approach in this case?
If your goal is to show that sequential access is faster than non-sequential access, simply pointer chasing the latter is not a good way to demonstrate that. You would be comparing access via a single pointer plus simple offset against deterrencing one or more pointers before offsetting.
To use pointer chasing, you'd have to apply it to both cases. Here's an example:
int arr[n], i;
int *unshuffled[n];
int *shuffled[n];
for(i = 0; i < n; i++) {
unshuffled[i] = arr + i;
}
/* I'll let you figure out how to randomize your indices */
shuffle(unshuffled, shuffled)
/* Do toning on these two loops */
for(i = 0; i < n; i++) {
do_stuff(*unshuffled[i]);
}
for(i = 0; i < n; i++) {
do_stuff(*shuffled[i]);
}
It you want to time the direct access better though, you could construct some simple formula for advancing the index instead of randomizing the access completely:
for(i = 0; i < n; i++) {
do_stuff(arr[i]);
}
for(i = 0; i < n; i++) {
do_stuff(arr[i / 2 + (i % 2) * (n / 2)]);
}
This will only work properly for even n as shown, but it illustrates the idea. You could go so far as to compensate for the extra flops in computing the index within do_stuff.
Probably the most apples-to-apples test would be to literally access the indices you want, without loops or additional computations:
do_stuff(arr[0]);
do_stuff(arr[1]);
do_stuff(arr[2]);
...
do_stuff(arr[123]);
do_stuff(arr[17]);
do_stuff(arr[566]);
...
Since I'd imagine you'd want to test with large arrays, you can write a program to generate the actual test code for you, and possibly compile and run the result.
I can tell you that for arrays in C the access time is constant regardless of the index being accessed. There will be no difference between accessing them randomly or sequentially other than the fact that randomizing will in itself introduce additional computations.
But, to really answer your question, you would probably be best off to build some kind of lookup array and shuffle it a few times and use that array to get the next index. Obviously, you would be accessing two arrays, one sequentially and another randomly, by doing so, thus making the exercise pretty much useless.
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, ¤tTile);
}
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().
I know there is a naive algorithm that is order N and I'm about convinced that's the only one to use. Is there any other that is:
Asymptotically better
Pipelineable i.e. RAW,WAR friendly
Multithreadable.
I'm sure there is one for (1) but I'm not so sure about (2) and (3). If you also want to mention why this is a good interview question. I'd love to know that as well.
The obvious method is easy to do in-place
void remove_every_kth(char *s, size_t len, int k)
{
// UNTESTED CODE, there might be an off-by-one or a wrong loop boundary
if (k < len)
return;
const char *endp = s + len;
size_t offset = 1;
// we skip the s[i] = s[i] memmove at offset=0.
for (s+=k-1 ; s + offset < endp-(k-1) ; s+=k-1) {
// every iteration copies k-1 characters, and advances s by k-1
memmove(s, s+offset, k-1);
offset++;
}
size_t lastchunk = endp - (s+offset); // some number (less than k) of bytes left in the input
memmove(s, s+offset, lastchunk);
s[lastchunk] = '\0';
}
// equivalently, we could have kept a pointer to the read position,
// like const char* read = s+offset;
// and incremented it by k, while incrementing s by k-1
// for (int i=0 ; i < k ; i++) // implicit length string
// if (!s[i]) return; // check for length < k
Since k is constant, you can calculate where to find the input character for any output position. out[i] = in[i + i/k]. There's nothing data-dependent, so this is certainly multithreadable if you don't need to do it in-place, and you have the length of the string in advance. Just farm out the necessary memcpy calls to multiple threads. (I wrote the simple version with memmove instead of a char-pointer loop to make this more obvious, as well as for much better performance with medium to large k. It probably sucks for small k.)
For multithreaded in-place, there's something to gain if k is large, so that even towards the end of a long string, the source and destination of most of the copying is within the same chunk. Each work unit does:
don't touch the first offset = chunk_number * chunk_size / k bytes, the previous work unit needs to read them.
save the second offset bytes to a temp array.
memmove(chunk + offset, chunk + offset*2, chunk_size - offset) (i.e. do the memmove for all the bytes that aren't needed by the previous work unit).
spin-wait for the previous chunk to be marked as done by the thread handling it. (Prob. with a separate data structure, because just watching the data at the last overlapping position won't work. It might be overwritten with the same value.)
copy from the temp buffer to the beginning of the chunk, where the data belongs
mark the work chunk as completed.
For small k, in-place multithread is futile, because most of the bytes in a chunk need to be overwritten with bytes from later chunks. (very large chunks help some.)
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]);