How to categorize elements of array in C - c

I have a problem regarding arrays.
So, I have an array with the size of 255 (let's call it array(255)). I have an integer named block also.
I want to categorize this arrays (I hope the term is right).
What I want is:
If the chosen array element is
From (0-63) , block = 0
From (64-127) , block = 1
From (128-191), block = 2
From (192-255), block = 3
I know with this case I can just use if statement. But what if I scale up my array size into thousands?
I can't use rows of If statement.
Is there any simpler and more efficient solution for this?

You can simply do it with an integer division:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdint.h>
#include <inttypes.h>
int main(void)
{
uint8_t array[255] = {0};
srand(time(NULL));
for(size_t i=0; i<sizeof(array)/sizeof(array[0]); i++)
{
array[i] = rand() % 256;
printf("Array[%zu]= %"PRIu8"\tblock= %"PRIu8"\n", i, array[i], array[i] / 64 );
}
}

You should do something like:
int array[255];
...
int getArrayItemByCateg(int category, int index) {
return array[category * 64 + index];
}

If you have only an pointer to your element in your code you could use something like the following function:
int getBlock(void* array, void* arrayElement, size_t size)
{
return (int)((arrayElement - array) / (size * 64));
}
This function can be uses for different array types but the origin array has to be known when you are calling this function. See the following examples:
uint32_t array_u32[256];
uint16_t array_u16[256];
printf("array u32 index 32 is block %d\n", getBlock(array_u32, &array_u32[32], sizeof(array_u32[0])));
printf("array u32 index 129 is block %d\n", getBlock(array_u32, &array_u32[129], sizeof(array_u32[0])));
printf("array u16 index 32 is block %d\n", getBlock(array_u16, &array_u16[32], sizeof(array_u16[0])));
printf("array u16 index 129 is block %d\n", getBlock(array_u16, &array_u16[129], sizeof(array_u16[0])));
The following result will be printed:
array u32 index 32 is block 0
array u32 index 129 is block 2
array u16 index 32 is block 0
array u16 index 129 is block 2
Also see the code at IDEONE.

How about a multidimensional array? Information: Tutorials Point - Multidimensional Arrays
This may not be an elegant solution but it is pretty simple. This may not be ideal for larger scale data however larger scale data may be best using a binary or quad tree anyhoo.
Multidimensional Array:
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
const int COLUMN_SIZE = 64;
const int ROW_SIZE = 4;
// Access index of row using the labels below
const int BLOCK_ONE = 0;
const int BLOCK_TWO = 1;
const int BLOCK_THREE = 2;
const int BLOCK_FOUR = 3;
int main(int argc, char* argv[]) {
int array[ROW_SIZE][COLUMN_SIZE] = {0};
srand(time(NULL));
/* Initialise array */
for(int x = 0; x < ROW_SIZE; x++) {
for(int i = 0; i < COLUMN_SIZE; i++) {
array[x][i] = rand() % (ROW_SIZE * COLUMN_SIZE);
}
}
/* Test */
for(int x = 0; x < ROW_SIZE; x++) {
for(int i = 0; i < COLUMN_SIZE; i++) {
printf("Array[%d][%d]: %d\n", x, i, array[x][i]);
}
printf("\n");
}
return 0;
}

Related

Array cleaning in C

I don't know how to clean an array from the elements which indexes stored in the other array. I need to complete the following C-program consisting of main(…) and function
void clear_MSBs( unsigned char dest_array[], unsigned char array_indices []).
Beginning of code:
#define N 8
#define M 5
int main()
{
unsigned char dest_array[N] = {248,249,250,251,252,253,254,255};
unsigned char array_indices[M] = {0,2,3,6,7}; // contains M=5 elements
clear_MSBs(dest_array, array_indices);
// print the modified dest_array[] here
return 0;
}
Note: It is guaranteed that all indices stored in the second array are within the
allowed range.
I would really appreciate your help.
If by cleaning, you mean marking the element as invalid (which is probably what you want), then you could just loop over the indices array, and use the i-th element of the indices array as the index for the destination array.
Example:
#include <stdio.h>
#define N 8
#define M 5
void clear_MSBs(unsigned char dest_array[], unsigned char array_indices [])
{
for(int i = 0; i < M; ++i)
dest_array[array_indices[i]] = 0;
}
int main()
{
unsigned char dest_array[N] = {248,249,250,251,252,253,254,255};
unsigned char array_indices[M] = {0,2,3,6,7}; // contains M=5 elements
clear_MSBs(dest_array, array_indices);
// print the modified dest_array[] here
for(int i = 0; i < N; ++i)
if(dest_array[i] != 0)
printf("%d ", dest_array[i]);
printf("\n");
return 0;
}
Output:
249 252 253
PS: The code assumes that an invalid element has the 0 value.
You just need to overwrite what you're deleting with the next value in the array, propagate that change, and then keep in mind where the new end is.
In C++, though, it would be better to use a std::vector:
std::vector<int> array; // initialize array... // delete element at index 2
array.erase(array.begin() + 2);

Seg Fault when accessing an array initialised with malloc

Below is a simplified extract of a program I'm writing. I'm having issues accessing elements towards the end of the array.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main(int n, char *args[n]){
// create 4D array scores[10000][100][100][100] on heap
uint64_t arraySize = 1; // this avoids overflow
arraySize *= 10000;
arraySize *= 100;
arraySize *= 100;
arraySize *= 100;
int (*scores)[10000][100][100] = malloc(arraySize);
for (int i = 0; i < 10000; i++) {
for (int j = 0; j < 100; j++) {
printf("%d, %d, %d\n", i, j, scores[i][j][0][0]);
}
}
}
The program loops through the 4D array score and as a test I'm printing the contents of the array. The loop starts off as planned, printing in the format "i, j, 0" for each i and j, until the last success "25, 0, 0".
From this point on I get random numbers rather than 0, starting with "25, 1, 1078528" up until "25, 45, 1241744152" which is then followed by "Segmentation fault (core dumped)".
After fiddling around I found the first non-zero array member to be scores[25][0][7][64].
So I guess I'm running out of space and so am accessing memory I shouldn't be? If anyone knows or has an idea as to how I could fix this I'd really appreciate it.
My PC is running Ubuntu 16.10 64bit, has 16GB RAM and 16GB swap
Edit
After implementing the following suggestions I get a return value of "calloc: Cannot allocate memory".
int (*scores)[100][100][100] = calloc(arraySize, sizeof(int));
if (scores == NULL) {
perror("calloc");
return 1;
}
If I comment out the new if statement (and run the for loop) I get an immediate seg fault. This also happens if I use malloc:
int (*scores)[100][100][100] = malloc(arraySize * sizeof(int));
Why could this be? Surely my system has enough memory
Cheers
Check the return value of malloc() and determine if it failed to allocate.
You forgot to multiply the size of int.
The type of result should be int (*)[100][100][100], not int (*)[10000][100][100].
Using value of buffer allocated via malloc() and not initialized invokes undefined behavior, so don't do that.
Try this:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
int main(int n, char *args[n]){
// create 4D array scores[10000][100][100][100] on heap
uint64_t arraySize = 1; // this avoids overflow
arraySize *= 10000;
arraySize *= 100;
arraySize *= 100;
arraySize *= 100;
int (*scores)[100][100][100] = calloc(arraySize, sizeof(int));
if (scores == NULL) {
perror("calloc");
return 1;
}
for (int i = 0; i < 10000; i++) {
for (int j = 0; j < 100; j++) {
printf("%d, %d, %d\n", i, j, scores[i][j][0][0]);
}
}
}
Your pointer to a variable length array does not use correct array sizes.
The array is: [10000][100][100][100]
but the pointer is: [100][10000][100][100]
And you need to multiply the array size times the size of the object, in this case size of type int.
The pointer definition should be:
int (*scores)[100][100][100] = malloc(arraySize*sizeof(int));
The allocated elements are not initialized. Reading them will yield indeterminate values.
The correct type to store the size of bytes that need to be allocated, is size_t, not uint64_t.
One of the correct ways to allocate the array is:
const size_t bytes = sizeof( int[10000][100][100][100] );
int (*scores)[100][100][100] = malloc( bytes );
(This of course assumes that size_t can represent that value.)
Did you try:
int (*scores)[10000][100][100] = malloc(sizeof(int)*arraySize);
Bye.

Confusing values when copying to another array

I am trying to copy values from one array to another in C. The original array is of type long int, and it is inputted to the function as *pixel_frequency. The array I want to copy to is temp, and it is a 2D array. However, when I try to copy the values, pixel_frequency is fine but temp gives strange results. Below is the relevant code and some sample output.
Code:
struct node *generate_nodes(long int *pixel_frequency) {
int i;
int temp[max_value + 1][2];
for (i = 0; i < (max_value + 1); i++) {
temp[i][0] = i;
temp[i][1] = pixel_frequency[i];
printf("Frequency for %d is %d\n", temp[i][0], temp[i][1]);
}
...
Output (each frequency is supposed to be 256):
Frequency for 0 is 150160
Frequency for 1 is 256
Frequency for 2 is 256
Frequency for 3 is 256
Frequency for 4 is 255
...
Frequency for 254 is 892677956
Frequency for 255 is 1868789101
Below is an example version of code using your code snippet, take care of the return type and other things.
Instead of using a global variable for array size, you can pass it as a function argument so , it will be easy to identify the size of array you passed.
void generate_nodes(long int *pixel_frequency, size_t size) {
size_t i;
long int temp[size][2];
for (i = 0; i < size; i++) {
temp[i][0] = i;
temp[i][1] = pixel_frequency[i];
printf("Frequency for %ld is %ld\n", temp[i][0], temp[i][1]);
}
}
If you have declared pixel_frequency as a local variable in a function and used the address of array after the variable went out of scope, will lead to undefined behaviour.
int main(void) {
size_t max_len = 5000;
size_t i;
long int* pixel_frequency = malloc(max_len*sizeof(long int));
for( i = 0; i < max_len; ++i) {
pixel_frequency[i] = (i%256);
}
generate_nodes(pixel_frequency, max_len);
return 0;
}

C: Dynamic memory allocation using pointer to array with fixed number of chars

so I guess this is more a stylistic question.
I need to write into a dynamic array of elements with the size of 3 bytes. (bitmap with pixel size of 24bpp)
So, every element would have to be a char[3].
If I want to avoid using a struct pixel{ char R, char G, char B}, to avoid the usage of preprocessor statements, is it possible to write it as
char* pixel[3]
and allocate in steps of 3*sizeof(char)?
To account for height and width, I would need a char** pixel[3], and having to allocate in single char steps would make that a char*** pixel.
So I guess I'm looking for a way to avoid using a pointer-pointer-pointer.
Thanks!
Do you mean N blocks of 3 unsigned char' s [0...255]?
Note the difference:
unsigned char *pixel[3] -> array of pointers to char
Vs
unsigned char (*pixel)[3] -> pointer to array of chars
#include <stdio.h>
#include <stdlib.h>
#define N 4
int main(void)
{
unsigned char (*pixel)[3];
pixel = malloc(sizeof(*pixel) * N);
pixel[0][0] = 0;
pixel[0][1] = 128;
pixel[0][2] = 255;
/* ... */
pixel[3][0] = 0;
pixel[3][1] = 128;
pixel[3][2] = 255;
printf("R:%d G:%d B:%d\n", pixel[0][0], pixel[0][1], pixel[0][2]);
free(pixel);
return 0;
}
If you don't know N before hand replace malloc with realloc
You can simulate this using a 1D array. Say you want to allocate a wxh rectangle of pixels. You could write.
char *pixels = (char *) malloc(w*h*3*sizeof(char));
Now the 3 color bytes appear contiguous in memory and you can access any cell using some arithmetic
You can get/set the color channels at cell (i,j) by defining the macros:
#define r(p, i, j) ((p)[(3*((w)*(i)+(j)))])
#define g(p, i, j) ((p)[(3*((w)*(i)+(j)) + 1)])
#define b(p, i, j) ((p)[(3*((w)*(i)+(j)) + 2)])
Call looks like r(pixels, 0, 1).
If you don't want structs, you can't avoid writing char***.
But you can use a type, to make it more stylish.
So the best solution matching your requirements seems to be:
#include <stdlib.h>
typedef char*** pixelmap_t;
int main() {
int channels = 3, width = 10, height = 10;
pixelmap_t test = malloc(width*height*channels);
int x = 1, y = 2, channel = 0;
test[x][y][channel] = 3;
free(test);
return 0;
}
It seems, I totally fucked up. I confused the following two things:
When you declare a static 3D-Array pixels[100][100][3], then the type is not char***. It is a one-dimensional array of 300 consecutive items in memory.
When you declare a char*** and assign 300 items in memory, then dereferencing all of the dimensions with the pixels[x][y][z] syntax results in derefrencing the first dimension and interpreting the value in memory as pointer and derefrencing this pointer instead of computing the correct offset in a 3D-Array.
That means, I overlooked, that the array[x][y][z] accessor syntax has two different semantics. The first I would call the array ([x][y][z]) semantic for 3D-arrays and the second I would call the ((array[x])[y])[z] semantics for char*** (I used the brackets for emphasizing).
This code snipped compiles and works (tested it) - but does not use heap memory.
For heap memory I don't know an other solution than those, which have been posted already (malloc(width*height*channels) and access with pixels[c + channels*(y + x*height)]).
#include <stdlib.h>
#include <stdio.h>
int main() {
int channels = 3, width = 10, height = 10;
char test[width][height][channels];
char *ptr = (char*) test;
for (int i = 0 ; i < channels * width * height ; i++) {
ptr[i] = (char) (i % 255);
}
for (int x = 0 ; x < width ; x++) {
for (int y = 0 ; y < height ; y++) {
for (int c = 0 ; c < channels ; c++) {
int d = (int) test[x][y][c];
printf("%d %d - %d : %d\n", x, y, c, d);
}
}
}
return 0;
}

malloc a char[][]

I am trying to malloc a char to have rows and columns with one letter in each cell. Something similar to int x[i][j] where I have i*rows and j*columns. Basically I want to make this:
|
1
222
33333
4444444
I tried with this code but it gives me an error: assignment makes an integer from pointer without a cast
A=(char**) malloc (5*sizeof(char*));
for(i=0;i<N+2;i++)`{
A[i]=(char*) malloc(7*sizeof(char));
}
for(i=0;i<3;i++){
for(j=0;j<7;j++){
left=3;
right=3;
if((j>=left)&&(j<=right)){
A[i][j]=i;
}
}
left--;
right++;
}
I would go with different approach:
#define STEPS 5
#define ARRAY_SIZE STEPS*STEPS
The size of the array in your case can be easily calculated by the formula above.
Now, you just need to allocate fixed size of bytes, and fill it. That's it. Even more, the version below will simply out-beat your version in simplicity and performance.
int i, j;
char *array;
array = malloc(ARRAY_SIZE);
for (i = 0; i < STEPS; i++)
for (j = 0; j < (i * 2 + 1); j++)
*(array + i * STEPS + j) = i + 1;
Proof.
This compiles fine for me, as long as I add this around your code snippet; note that "A" was declared as being of type "char **". It won't work if you write, say "char A[][]".
#include <stdlib.h>
int main() {
const int N = 10;
int i, j, left, right;
char **A;
/* your code */
return 0;
}

Resources