Last active
June 11, 2019 11:47
-
-
Save willeccles/afce021697ae6ca33f2d3abbfa7318d8 to your computer and use it in GitHub Desktop.
Using pointers to make huge blobs of data less painful to work with.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
/* | |
The problem: | |
Say you have an array of N*M items. This is essentially | |
a 2D array, kept contiguously in memory (for example, | |
you have 15 devices, and their data is given to you | |
in a huge blob of 10 bytes each). We will call this | |
data_raw. Now, you know that you can get device0's data | |
by getting the first 10 items, and device1's data by | |
using 0+i*10 as an index, but that's ugly. | |
Instead, we can simulate a 2D array by using a list of | |
pointers to the huge array. We will call this | |
data_nice. This does use extra memory, in this case: | |
DEV_COUNT * sizeof(uint8_t*) | |
However, if the memory is available, this can just make | |
life easier. | |
Rationale: | |
Sure, it would be more efficient (by a decent amount) | |
to not do this. However, I recently ran into a situation | |
where a huge amount of code was using a 2D array, which | |
I would have had to replace with a giant blob of data. | |
Refactoring this would take forever! Luckily, using this | |
solution, a small performance hit (in that case, a very | |
small hit) resulted in less work to make old code | |
compatible. It also makes the code more readable anyway. | |
*/ | |
// Experiment values: | |
#define DEV_COUNT 15UL | |
#define DEV_BYTES 10UL | |
typedef unsigned char uint8_t; // byte type | |
// Our data: | |
uint8_t* data_raw; | |
// Convenience array: | |
uint8_t** data_nice; | |
int main(void) { | |
// simulate getting data from devices | |
data_raw = malloc(DEV_COUNT * DEV_BYTES * sizeof(uint8_t)); | |
for (int i = 0; i < DEV_COUNT * DEV_BYTES; i++) { | |
data_raw[i] = i; | |
} | |
// but now we want to get data the nice way | |
data_nice = malloc(DEV_COUNT * sizeof(uint8_t*)); | |
for (int i = 0; i < DEV_COUNT; i++) { | |
data_nice[i] = data_raw + (i * DEV_BYTES); | |
} | |
// now let's print the data for proof that it worked | |
puts(" Device | Data"); | |
for (int i = 0; i < DEV_COUNT; i++) { | |
printf(" %6d | ", i + 1); | |
for (int j = 0; j < DEV_BYTES; j++) { | |
printf("%s%3d", (j?", ":" "), | |
data_nice[i][j]); | |
} | |
puts(""); | |
} | |
// and of course, don't forget to clean up | |
free(data_nice); | |
free(data_raw); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment