Allocating a 3D array in C using malloc() - c

I'm trying to allocate a 3D array in C. As you can tell, it's to store image data, in the form Array[height][width][channel]; This is the code I have.
BYTE*** allocateImageArray(INT_32 width, INT_32 height, INT_32 channels) {
BYTE*** array;
INT_32 i, j;
array = malloc(height * sizeof(BYTE**));
for(i = 0; i < height; i++) {
array[i] = malloc(width * sizeof(BYTE*));
for(j = 0; j < channels; j++) {
array[i][j] = malloc(channels * sizeof(BYTE));
}
}
printf("Pixel Array Size: %d\n", sizeof(array));
return array;
}
It compiles fine. However, the array is always 8 at the end (Indicated by the sizeof). And when I try to access the array later in the code the program just crashes.
All answers are thanked in advanced.
EDIT: Forgot to include. I've worked out where the program crash occurs. It happens when I try to assign a value to one of the BYTES at the end of the array.

The sizeof operator doesn't work like that. Think if it more as a special #define macro that figures out the size of something based on its type.
So sizeof(array) is the same as sizeof(BYTE***) which is the same as sizeof(void*) which is apparently 8 for your computer.

BYTE** is just a pointer, so in the end sizeof(BYTE **) always returns 8.
You may try the following code:
#define value_at_index(a,i,j,k,m,n) (a)[(i)*m*n + (j)*n + (k)]
static BYTE*** allocateImageArray(int width, int height, int channels) {
BYTE (*array)[width][height];
array = malloc(width * height * channels * sizeof(BYTE));
array[1][2][3] = 1;
printf("array[1][2][3] = %d", array[1][2][3]);
return (BYTE***)array;
}
Doing so, you have a contiguous memory space for the 3-dimension array, then in the main() you can call like this:
BYTE ***array = allocateImageArray(10, 20, 30);
printf("array[1][2][3] = %d", value_at_index(array, 1, 2, 3, 10, 20));

The sizeof operator does not tell you the size of dynamically allocated arrays.
sizeof returns the size in bytes of the underlying datatype, which in your case is a pointer to a pointer to a pointer to a BYTE.
As array is still a pointer (regardless of what it points to) the returned size of 8 bytes makes sense.
Please refer to the sizeof operator explanation.
Aside:
I would also recommend having a look at Why does sizeof(x++) not increment x? for an interesting error that can prop up with the sizeof operator and assumptions that new programmers make about it.

sizeof(array) == the number of bytes for a pointer, which is 8 bytes in your case.

Related

Can someone please explain this. It deals with malloc and global array in C

If I'm trying to create a global array to hold an arbitrary number of integers in this case 2 ints. How is it possible that I can assign more numbers to it if I only allocate enough space for just two integers.
int *globalarray;
int main(int argc, char *argv[]) {
int size = 2;
globalarray = malloc(size * sizeof(globalarray[0]));
// How is it possible to initialize this array pass
// the two location that I allocated.
for (size_t i = 0; i < 10; i++) {
globalarray[i] = i;
}
for (size_t i = 0; i < 10; i++) {
printf("%d ", globalarray[i]);
}
printf("%s\n", "");
int arrayLength = sizeof(*globalarray)/sizeof(globalarray[0]);
printf("Array Length: %d\n", arrayLength);
}
When I run this it gives me
0 1 2 3 4 5 6 7 8 9
Array Length: 1
So I wanted to know if someone could clarify this for me.
(1) Am I creating the global array correctly?
(2) Why is the array length 1? When I feel that it should be 2 since I malloced the pointer for 2.
And background info on why I want to know this is because I want to create a global array (shared array) so that threads can later access the array and change the values.
How is it possible to initialize this array pass the two location that I allocated.
Short answer: This is undefined behaviour and anything can happen, also the appearance that it worked.
Long answer: You can only initialize the memory you've allocated, it
doesn't matter that the variable is a global variable. C doesn't prevent you from
stepping out of bounds, but if you do, then you get undefined behaviour and anything can happen
(it can "work" but it also can crash immediately or it can crash later).
So if you know that you need 10 ints, then allocate memory for 10 int.
globalarray = malloc(10 * sizeof *globalarray);
if(globalarray == NULL)
{
// error handling
}
And if you later need more, let's say 15, then you can use realloc to increase
the memory allocation:
globalarray = malloc(10 * sizeof *globalarray);
if(globalarray == NULL)
{
// error handling
// do not contiue
}
....
// needs more space
int *tmp = realloc(globalarray, 15 * sizeof *globalarray);
if(tmp == NULL)
{
// error handling
// globalarray still points to the previously allocated
// memory
// do not continue
}
globalarray = tmp;
Am I creating the global array correctly?
Yes and no. It is syntactically correct, but semantically it is not, because you are
allocating space for only 2 ints, but it's clear from the next lines that
you need 10 ints.
Why is the array length 1? When I feel that it should be 2 since I malloced the pointer for 2.
That's because
sizeof(*globalarray)/sizeof(globalarray[0]);
only works with arrays, not pointers. Note also that you are using it wrong in
two ways:
The correct formula is sizeof(globalarray) / sizeof(globalarray[0])
This only works for arrays, not pointers (see below)
We sometimes use the term array as a visual representation when we do stuff
like
int *arr = malloc(size * sizeof *arr)
but arr (and globalarray) are not arrays,
they are pointers. sizeof returns the amount in bytes that the
expression/variable needs. In your case *globalarray has type int and
globalarray[0] has also type int. So you are doing sizeof(int)/sizeof(int)
which is obviously 1.
Like I said, this only works for arrays, for example, this is correct
// not that arr here is not an array
int arr[] = { 1, 2, 3, 4 };
size_t len = sizeof arr / sizeof arr[0]; // returns 4
but this is incorrect:
int *ptr = malloc(4 * sizeof *ptr);
size_t len = sizeof ptr / sizeof ptr[0]; // this is wrong
because sizeof ptr does not returns the total amount of allocated
bytes, it returns the amount of bytes that a pointer needs to be stored in memory. When you are dealing with
pointers, you have to have a separate variable that holds the size.
C does not prevent you from writing outside allocated memory. When coding in C it is of the utmost importance that you manage your memory properly.
For your second question, this is how you would want to allocate your buffer:
globalarray = malloc(sizeof(int) * size);
And if you are on an older version of C than c11:
globalarray = (int*) malloc(sizeof(int) * size);

What is the difference between malloc(sizeof(int)) and malloc(sizeof(int*))

I'd like to allocate memory for the 2d int ptr below, but I'm not 100% positive I've done it correctly, so any pointers (ha ha) on that would be great. Is the way I free the array and its indexes in the for loop correct? Also, what is the difference between the first malloc and the second malloc: (int *) and (int)?
int **array = NULL;
int mem_size = 0;
int i = 0, j = 0;
// leaving out how mem_size is calculated, but it can vary
array = malloc(sizeof(int *) * mem_size);
if (array == NULL) {
// some error message
return;
}
for (i = 0; i < mem_size; i++) {
array[i] = malloc(sizeof(int) * 2);
if (!(array[i])) {
// some error message
for (j = 0; j < i; j++)
free(array[j]);
free (array);
return;
}
}
This is only a section of the code I wrote. At the end, I am freeing the array:
for (i = 0; i < mem_size; i++)
free(array[i]);
free(array);
It is just a compile time constant - size of pointer in first case, size of int in second. It may vary between systems (e.g. if compiling for 32bit systems, pointer would be 4 bytes, while on 64bit systems it is 8 bytes).
In case any of the mallocs fail in the for loop, should I be freeing the array there
You should be freeing everything you've allocated so far - each array[0..(i-1)] and array itself.
malloc(sizeof(int *) * mem_size)
Allocates memory for array of mem_size pointers.
malloc(sizeof(int) * 2);
Allocates memory for 2 ints.
Also you should consider allocating ordinary 1D array and just calculating index when you want to access it.
sizeof(int) is equal to 4 bytes
sizeof(int *) is also equal to 4 bytes
... since a pointer only holds 4 bytes.
When you call malloc(int) and malloc(int *) - in both cases, the memory manager allocates 4 bytes on the heap and returns a pointer to the allocated memory.
Since you are going to store that address into the array (which is a double pointer and can thus only hold the address of another pointer), the following is illegal:
array = malloc(sizeof(int *) * mem_size); --- illegal to use
You may implement what you want in the following way:
int *ptr = NULL;
int **p_ptr = NULL;
ptr=(int *)malloc(sizeof(int *));
p_ptr = &ptr;
**p_ptr = 100 or any other value; now, whatever changes you made will be reflected in the allocated size of 4 bytes
Each one of them is determined according to a different characteristic within your platform.
The size of int is determined by the compiler, which is typically designated for a specific processor.
So it is effectively derived from the CPU architecture.
It is usually 4 bytes, but may be 2 bytes on some platforms.
The size of int* (or any other pointer) is determined by the size of the virtual memory address space.
So it is effectively derived from the MMU architecture.
It is 4 bytes on 32-bit systems and 8 bytes on 64-bit systems.

Am I correctly allocating memory for my pointer arrays in C?

I am trying to track down a bug a big program. I think it is due to how I am passing arrays to my functions. Am I doing this correctly?
main(){
int *x = declarArray(x, 100);
int *y = declarArray(x, 100);
// lines of code....
x = arrayManip(x, 100);
// more code...
int i;
for(i=0; i<100; i++)
y[i] = x[i];
//more code...
free(x);
free(y);
}
This is how I manipulate arrays:
int *arrayManip(int *myarray, int length){
int i;
for(i=0; i<length; i++)
myarray[i] = i;
return array;
}
This is how I initialize the arrays:
int* declareArray(int *myarray, int length){
myarray = (int*) malloc(length*sizeof(int*));
if (myarray==NULL)
printf("Error allocating memory!\n");
int i;
for(i=0; i<length; i++)
myarray[i] = -888;
return myarray;
}
This code seems to work fine on a small scale, but maybe there is a problem once I have many more arrays of larger size that are often getting passed back and forth and copied in my program?
declarArray :
Name is not gramatically correct
The name of the function is not what it does
malloc with sizeof(int*), not sizeof(int). Guarantuee to be a bug in 64 bit machine
malloc fails, you print, but still write to null
passing myarray as argument is a noop as is
-888 is a magic number
There is no error check whatsoever
My advice. Throw it away and start fresh
No, as per my understanding.
You allocating one dim array => elements in that array should be integers and not pointers to integers so instead of this :
myarray = (int*) malloc(length*sizeof(int*));
it should be :
myarray = (int*) malloc(length*sizeof(int));
In function arrayManip you pass param named array, and than you trying to access it as myarray
This:
myarray = (int*) malloc(length*sizeof(int*));
allocates an array of length pointers to an integer, but then puts it into a pointer to an integer (i.e. an array of integers, not pointers to integers). If you want an array of integers, you want:
myarray = (int*) malloc(length*sizeof(int));
or (if you want to zero it):
myarray = (int*) calloc(length, sizeof(int));
which does the size x length calculation itself.
To allocate a list of pointers to integers, you want:
myarray = (int**) malloc(length*sizeof(int*));
or
myarray = (int**) calloc(length, sizeof(int*));
Unless you are fantastically concerned about speed, I find using calloc() results in fewer bugs from uninitialized arrays, and makes the reason for the allocated size more obvious.
The pointer is of word size [2 or 4 ,... depending on machine architecture]. whatever it may point to int,double,float,...
for integer pointer it works if it takes 4 bytes for int in machine. when u go for other data type it 'll lead you to error.
you should allot memory as
pointer = (DataType*) malloc (length * sizeof(DataType));
use malloc and to make your code clear.
void* malloc (size_t size);
malloc reference
use memset to allot default value [-888] for your array.
void *memset(void *str, int c, size_t n)

Is this code doing what I want it to do?

I want to create an integer pointer p, allocate memory for a 10-element array, and then fill each element with the value of 5. Here's my code:
//Allocate memory for a 10-element integer array.
int array[10];
int *p = (int *)malloc( sizeof(array) );
//Fill each element with the value of 5.
int i = 0;
printf("Size of array: %d\n", sizeof(array));
while (i < sizeof(array)){
*p = 5;
printf("Current value of array: %p\n", *p);
*p += sizeof(int);
i += sizeof(int);
}
I've added some print statements around this code, but I'm not sure if it's actually filling each element with the value of 5.
So, is my code working correctly? Thanks for your time.
First:
*p += sizeof(int);
This takes the contents of what p points to and adds the size of an integer to it. That doesn't make much sense. What you probably want is just:
p++;
This makes p point to the next object.
But the problem is that p contains your only copy of the pointer to the first object. So if you change its value, you won't be able to access the memory anymore because you won't have a pointer to it. (So you should save a copy of the original value returned from malloc somewhere. If nothing else, you'll eventually need it to pass to free.)
while (i < sizeof(array)){
This doesn't make sense. You don't want to loop a number of times equal to the number of bytes the array occupies.
Lastly, you don't need the array for anything. Just remove it and use:
int *p = malloc(10 * sizeof(int));
For C, don't cast the return value of malloc. It's not needed and can mask other problems such as failing to include the correct headers. For the while loop, just keep track of the number of elements in a separate variable.
Here's a more idiomatic way of doing things:
/* Just allocate the array into your pointer */
int arraySize = 10;
int *p = malloc(sizeof(int) * arraySize);
printf("Size of array: %d\n", arraySize);
/* Use a for loop to iterate over the array */
int i;
for (i = 0; i < arraySize; ++i)
{
p[i] = 5;
printf("Value of index %d in the array: %d\n", i, p[i]);
}
Note that you need to keep track of your array size separately, either in a variable (as I have done) or a macro (#define statement) or just with the integer literal. Using the integer literal is error-prone, however, because if you need to change the array size later, you need to change more lines of code.
sizeof of an array returns the number of bytes the array occupies, in bytes.
int *p = (int *)malloc( sizeof(array) );
If you call malloc, you must #include <stdlib.h>. Also, the cast is unnecessary and can introduce dangerous bugs, especially when paired with the missing malloc definition.
If you increment a pointer by one, you reach the next element of the pointer's type. Therefore, you should write the bottom part as:
for (int i = 0;i < sizeof(array) / sizeof(array[0]);i++){
*p = 5;
p++;
}
*p += sizeof(int);
should be
p += 1;
since the pointer is of type int *
also the array size should be calculated like this:
sizeof (array) / sizeof (array[0]);
and indeed, the array is not needed for your code.
Nope it isn't. The following code will however. You should read up on pointer arithmetic. p + 1 is the next integer (this is one of the reasons why pointers have types). Also remember if you change the value of p it will no longer point to the beginning of your memory.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define LEN 10
int main(void)
{
/* Allocate memory for a 10-element integer array. */
int array[LEN];
int i;
int *p;
int *tmp;
p = malloc(sizeof(array));
assert(p != NULL);
/* Fill each element with the value of 5. */
printf("Size of array: %d bytes\n", (int)sizeof(array));
for(i = 0, tmp = p; i < LEN; tmp++, i++) *tmp = 5;
for(i = 0, tmp = p; i < LEN; i++) printf("%d\n", tmp[i]);
free(p);
return EXIT_SUCCESS;
}
//Allocate memory for a 10-element integer array.
int array[10];
int *p = (int *)malloc( sizeof(array) );
At this point you have allocated twice as much memory -- space for ten integers in the array allocated on the stack, and space for ten integers allocated on the heap. In a "real" program that needed to allocate space for ten integers and stack allocation wasn't the right thing to do, the allocation would be done like this:
int *p = malloc(10 * sizeof(int));
Note that there is no need to cast the return value from malloc(3). I expect you forgot to include the <stdlib> header, which would have properly prototyped the function, and given you the correct output. (Without the prototype in the header, the C compiler assumes the function would return an int, and the cast makes it treat it as a pointer instead. The cast hasn't been necessary for twenty years.)
Furthermore, be vary wary of learning the habit sizeof(array). This will work in code where the array is allocated in the same block as the sizeof() keyword, but it will fail when used like this:
int foo(char bar[]) {
int length = sizeof(bar); /* BUG */
}
It'll look correct, but sizeof() will in fact see an char * instead of the full array. C's new Variable Length Array support is keen, but not to be mistaken with the arrays that know their size available in many other langauges.
//Fill each element with the value of 5.
int i = 0;
printf("Size of array: %d\n", sizeof(array));
while (i < sizeof(array)){
*p = 5;
*p += sizeof(int);
Aha! Someone else who has the same trouble with C pointers that I did! I presume you used to write mostly assembly code and had to increment your pointers yourself? :) The compiler knows the type of objects that p points to (int *p), so it'll properly move the pointer by the correct number of bytes if you just write p++. If you swap your code to using long or long long or float or double or long double or struct very_long_integers, the compiler will always do the right thing with p++.
i += sizeof(int);
}
While that's not wrong, it would certainly be more idiomatic to re-write the last loop a little:
for (i=0; i<array_length; i++)
p[i] = 5;
Of course, you'll have to store the array length into a variable or #define it, but it's easier to do this than rely on a sometimes-finicky calculation of the array length.
Update
After reading the other (excellent) answers, I realize I forgot to mention that since p is your only reference to the array, it'd be best to not update p without storing a copy of its value somewhere. My little 'idiomatic' rewrite side-steps the issue but doesn't point out why using subscription is more idiomatic than incrementing the pointer -- and this is one reason why the subscription is preferred. I also prefer the subscription because it is often far easier to reason about code where the base of an array doesn't change. (It Depends.)
//allocate an array of 10 elements on the stack
int array[10];
//allocate an array of 10 elements on the heap. p points at them
int *p = (int *)malloc( sizeof(array) );
// i equals 0
int i = 0;
//while i is less than 40
while (i < sizeof(array)){
//the first element of the dynamic array is five
*p = 5;
// the first element of the dynamic array is nine!
*p += sizeof(int);
// incrememnt i by 4
i += sizeof(int);
}
This sets the first element of the array to nine, 10 times. It looks like you want something more like:
//when you get something from malloc,
// make sure it's type is "____ * const" so
// you don't accidentally lose it
int * const p = (int *)malloc( 10*sizeof(int) );
for (int i=0; i<10; ++i)
p[i] = 5;
A ___ * const prevents you from changing p, so that it will always point to the data that was allocated. This means free(p); will always work. If you change p, you can't release the memory, and you get a memory leak.

append to dynamically allocated array in c

I try realloc but it didn't work
this is the code. thanks for your help
trial = malloc (4 * sizeof(int));
trial[0] = 1; trial[1] = 4;trial[2] = 7;trial[3] = 11;
trial = (int*)realloc(trial, sizeof(int) * 5);
trial[sizeof(trial)-1] = 23;
int a;
for(a = 0; a < sizeof(trial); a++){
printf("TRIAL %d \n", trial[a]);
}
And the output look like this
TRIAL 1
TRIAL 4
TRIAL 7
TRIAL 23
It should be
TRIAL 1
TRIAL 4
TRIAL 7
TRIAL 11
TRIAL 23
The problem is that sizeof does not tell you how many elements are in the array; it tells you how much space the pointer (which points to the first element) takes up. So sizeof(trial) == sizeof(int*), and not the number of elements. You need to store the length separately.
sizeof will return sizeof(int *), which is the size of the pointer. You will have to keep track of the size of the pointer seperately.
Also, you should not return realloc() to the pointer you are reallocating. If realloc returns NULL, it will not modify the pointer and you will lose it. It is best to use a temporary pointer as follows:
int *p;
int *tmp;
/*...*/
tmp = realloc(p, NEW_SIZE);
if (tmp != NULL) p = tmp;
else { /*...*/ }
sizeof() on dynamically allocated memory only returns the size of the type, not the size of the block allocated. So sizeof(trial) in this case will return 4, the size of an int*.
sizeof(trial) == a constant (probably 4 or 8). It won't be the count of elements you allocated.
You need something like
int n = 100;
trial = realloc(trial, n*sizeof(*trial));
trial[n-1] = K; // K is some number.
sizeof returns the size of the type, in this case the size of an int * which I assume is 4 bytes. So you are making the array size 5, but you are setting element (4 - 1) to 23. You'll need to keep track of the size of the array through a variable.

Resources