How to get the size of dynamically allocated 2d array - c

I have dynamically allocated 2D array.
Here is the code
int **arrofptr ;
arrofptr = (int **)malloc(sizeof(int *) * 2);
arrofptr[0] = (int *)malloc(sizeof(int)*6144);
arrofptr[1] = (int *)malloc(sizeof(int)*4800);
Now i have to know that how many bytes are allocated in arrofptr,arrofptr[0],arrofptr[1]?
is there any way to know the size?
if we will print
sizeof(arrofptr);
sizeof(arrofptr[0]);
sizeof(arrofptr[1]);
then it will print 4.

You can't find size of arrofptr, because it is only a pointer to pointer. You are defining an array of arrays using that. There's no way to tell the size information with only a pointer, you need to maintain the size information yourself.

The only return value you get from malloc() is a pointer to the first byte of the allocated region (or NULL on failure). There is no portable, standard, way of getting the associated allocation size from such a pointer, so in general the answer is no.
The C way is to represent arrays and buffers in general with a pair of values: a base address and a size. The latter is typically of the type size_t, the same as the argument to malloc(), by the way.

if you want to keep track of the size of an allocated block of code you would need to store that information in the memory block that you allocate e.g.
// allocate 1000 ints plus one int to store size
int* p = malloc(1000*sizeof(int) + sizeof(int));
*p = (int)(1000*sizeof(int));
p += sizeof(int);
...
void foo(int *p)
{
if (p)
{
--p;
printf( "p size is %d bytes", *p );
}
}
alt. put in a struct
struct
{
int size;
int *array;
} s;

You can't get the length of dynamically allocated arrays in C (2D or otherwise). If you need that information save it to a variable (or at least a way to calculate it) when the memory is initially allocated and pass the pointer to the memory and the size of the memory around together.
In your test case above sizeof is returning the size of the pointer, and thus your calculation the size of the pointers is usually 4, this is why you got 4 and is likely to have the trivial result of 4, always.

Related

Should I change the pointer to an array?

for (int a=0; a<10; ++a) {
printf ("%d", a);
}
char *foo;
foo = (char*)malloc(a);
I want to store more than one char value in foo variable.
Should I change it to an array, since the buffer is only allocating 1 char length?
Is 1 the longest length that can be stored in this buffer?
Well, foo now points to some useable address of a bytes, because this is how malloc() works. It doesn't matter if its type is char *, void * or anything else, you can only use a bytes.
Here, you increment a to 10. That means you can store 10 bytes, being 10 chars, (because in the context of C, 1 char = 1 byte), starting at the address where foo points to. Using a pointer or an array is strictly equivalent.
Since the buffer is only allocating 1 char length...
No, it is not the case here.
Quoting from the C11 standard, chapter ยง7.22.3.4, The malloc function
void *malloc(size_t size);
The malloc function allocates space for an object whose size is specified by size and
whose value is indeterminate.
So, in case of
foo = malloc(a); //yes, the cast is not required
a memory of size same as the value of a will be allocated, considering malloc() is successful.
Simply put, if I write a snippet like
int * p = malloc(10 * sizeof*p);
then, I can also write
for (int i = 0; i < 10, i++)
p[i] = i;
because, I have allocated the required memory for 10 ints.
That said, please see this discussion on why not to cast the return value of malloc() and family in C..
There are a couple of things you could do in a case like this.
If you know at compile time how many chars you want to store you could make it an array char foo[10]; If you know that there is always going to be 10 (or less) characters you want to store.
If you are not sure how many chars it needs to hold at compile time you would typically do dynamic allocation of memory using malloc. Now when using malloc you specify how many bytes of memory you want so for 12 chars you would do malloc(12) or malloc(12 * sizeof(char)). When using malloc you need to manually free the memory when you are done using it so the benefit of being able to ask for arbitrary (within limits) sizes of memory comes at the cost of making memory management harder.
As a side note: You typically do not want to cast the return value of malloc since it can hide some types of bugs and void *, that malloc returns can be implicitly cast to any pointer type anyway.

Amount of memory to allocate to array of strings?

I have a char** which is designed to hold and unknown amount of strings with unknown length
I've initially allocated 10 bytes using
char **array = malloc(10);
and similarly, before adding strings to this array, I allocate
array[num] = malloc(strlen(source)+1)
I've noticed that my program crashes upon adding the 6th element to the array
My question is, how does memory with these arrays work? When I allocated 20 bytes, nothing happened, yet when I allocated 30, it suddenly could hold 10 elements. These were all strings of 2-3 characters in size. I'm struggling to think of a condition to realloc memory with, e.g
if condition{
memoryofarray += x amount
realloc(array, memoryofarray)
}
What exactly uses the memory in the char**? I was under the impression that each byte corresponds to how many lines they can hold, i.e. malloc(10) would allow the array to hold 10 strings. I need to know this to establish conditions + to know how much to increment the memory allocated to the array by.
Also, curiously, when I malloced
array[num] = malloc(0)
before assigning a string to that array element, it worked without problems. Don't you need to at least have strlen amount of bytes to store strings? This is confusing me massively
This line:
char **array = malloc(10);
allocates 10 bytes, however, remember that a pointer is not the same size as a byte.
Therefore you need to make sure you allocate an array of sufficient size by using the size of the related type:
char **array = malloc(10 * sizeof(char*));
Now that you have an array of 10 pointers you need to allocate memory for each of the 10 strings, e.g.
array[0] = malloc(25 * sizeof(char));
Here sizeof(char) is not needed but I added it to make it more obvious how malloc works.
If you want to hold 10 strings then you need to allocate memory for 10 char *'s and then allocate memory to those char pointers .You allocate memory of 10 bytes( not enough for 10 char *'s ) .Allocate like this -
char **array = malloc(10*sizeof(char *)); // allocate memory for 10 char *'s
And then do what you were doing -
array[num] = malloc(strlen(source)+1) // allocate desired memory to each pointer
note - take care that num is initialized and does not access out of bound index.
This will allocate enough memory for 10 pointers to char (char*) in array
char **array = malloc(10*sizeof(array[0]));
On a 64bit system the size of a char* is 8 bytes = 64 bits. The size of a char is typically 1 byte = 8 bits.
The advantage of using sizeof(array[0]) instead sizeof(char*) is that it's easier to change the type of array in the future.
char** is pointer to a pointer to char. It may point to the start of a memory block in the heap with pointers to char. Similarly char* is a pointer to char and it may point to the start of a memory block of char on the heap.
If you write beyond the allocated memory you get undefined behaviour. If you are lucky it may actually behave well! So when you do for example :
array[num] = malloc(0);
you may randomly not get a segmentation fault out of (good) luck.
Your use of realloc is wrong. realloc may have to move the memory block whose size you want to increase in which case it will return a new pointer. Use it like this :
if (condition) {
memoryofarray += amount;
array = realloc(array, memoryofarray);
}
Rather than allocating memory using the fault-prone style
pointer = malloc(n); // or
pointer = malloc(n * sizeof(type_of_pointer));
Use
pointer = malloc(sizeof *pointer * n);
Then
// Bad: certainly fails to allocate memory for 10 `char *` pointers
// char **array = malloc(10);
// Good
char **array = malloc(sizeof *array * 10);
how does memory with these arrays work?
If insufficient memory is allocated, it does not work. So step 1: allocate sufficient memory.
Concerning array[num] = malloc(0). An allocation of 0 may return NULL or a pointer to no writable memory or a pointer to some writable memory. Writing to that pointer memory is undefined behavior (UB) in any of the 3 cases. Code may crash, may "work", it is simply UB. Code must not attempt writing to that pointer.
To be clear: "worked without problems" does not mean code is correct. C is coding without a net. Should code do something wrong (UB), the language is not obliged to catch that error. So follow safe programming practices.
First allocate an array of pointers:
char* (*array)[n] = malloc( sizeof(*array) );
Then for each item in the array, allocate the variable-length strings individually:
for(size_t i=0; i<n; i++)
{
(*array)[i] = malloc( some_string_length );
}

Misconception of how memory is created using malloc()/calloc()

My concept of the way malloc()/calloc() create memory has always been that once an item is created, the address of the object stays the same. But a function I often use to create an array of strings, and one that seems to have always worked well, recently caused me to question my understanding, that is, memory addresses of objects can be (and are) moved simply by calling calloc/malloc.
To illustrate, here is the function I have used to create memory for an array of strings - char **:
char ** CreateArrayOfStrings(char **a, int numWords, int maxWordLen)
{
int i;
a = calloc(numWords, sizeof(char *)); //create array of pointers
if(!a) return a; //required caller to check for NULL
for(i=0;i<numWords;i++)
{
a[i] = calloc(maxWordLen + 1, 1); //create memory for each string
}
return a;
}
On my system, (Win7, 32bit compile, ANSI C) The line:
a = calloc(numWords, sizeof(char *)); //create array of pointers
Creates a block of contiguous memory, sized for numWords char *, in this case 7, yielding 28 bytes:
Memory spans from address 0x03260080 + 1C (0x0326009C)
Or:
a[0] is at 0x3200260080
a[1] is at 0x3200260084
a[2] is at 0x3200260088
a[3] is at 0x320026008C
a[4] is at 0x3200260090
a[5] is at 0x3200260094
a[6] is at 0x3200260098
Then, I create memory for each of numWords (7) strings
for(i=0;i<numWords;i++)
{
a[i] = calloc(maxWordLen + 1, 1); //maxWordLen == 5 in this example
}
Which results in the following:
This shows that the memory locations of the pointers a[1] - a[6] have been changed.
Can someone explain how/why this happens in malloc()/calloc()?
It appears that you are comparing apples to oranges:
When you print a[i] is at ... pointers, you show the addresses of elements inside the array a
However, when you shoe the memory layout, you show the values at these addresses, which are themselves pointers, so the whole picture looks confusing.
If you print the values at a[i] before assigning calloc results to them, you should get all zeros, because calloc NULLs out the memory. After the assignments, you see pointers to 6-byte blocks at each a[i], which makes perfect sense.
To summarize, your initial understanding of what happens when you allocate memory with malloc and calloc is correct: once a chunk of memory is allocated, its address* remains the same.
* On systems with virtual memory, I should say "its virtual address".
The memory of those addresses has not been changed. You are creating a 28-byte large block of space (a) and then at each element, dynamically allocating a second 6-byte block of space with its own address.
In other words, at a[1] (memory address 0x03260084), the value that is stored there is a pointer to memory address 0x32600D0.
To check the memory locations and the values at each one, try this:
for ( i = 0; i < 8; i++ )
{
printf("a[%d] %p %p\n",i,&(a[i]),a[i]);
}
When you call calloc(numWords, sizeof(char *)) you ask the operating system to allocate numWords pointers of size ``4 bytes each, on your system'', which is why the resulting block is 4 * numWords bytes, and it returns the address to the first one of them. So now you can store the addresses of the pointers that will hold the actual data. The nth call to calloc(maxWordLen + 1, 1) will then return the address to a block of size maxWordLen and store it at the memory location pointed to by a[n] which is simply the address returned by the first call to calloc plus n * sizeof(char *).

Dynamically allocated 2 dimensional arrays

Does anyone know what the third line "Free(array)" does? array here is just the address of the first element of array(in other words, a pointer to the first element in the array of int * right)? Why do we need the third line to free the "columns" of the 2D array? I basically memorized/understand that a is a pointer to means a holds the address of ____. Is this phrase correct?
For example: int **a; int * b; int c; b = &c = 4;
a = &b; This is correct right? Thankyou!!!
Also, in general, double pointers are basically dynamically allocated arrays right?
"Finally, when it comes time to free one of these dynamically allocated multidimensional ``arrays,'' we must remember to free each of the chunks of memory that we've allocated. (Just freeing the top-level pointer, array, wouldn't cut it; if we did, all the second-level pointers would be lost but not freed, and would waste memory.) Here's what the code might look like:" http://www.eskimo.com/~scs/cclass/int/sx9b.html
for(i = 0; i < nrows; i++)
free(array[i]);
free(array);
Why do we need the third line to free the "columns" of the 2D array?
The number of deallocations should match up with the number of allocations.
If you look at the code at the start of the document:
int **array;
array = malloc(nrows * sizeof(int *));
for(i = 0; i < nrows; i++) {
array[i] = malloc(ncolumns * sizeof(int));
}
you'll see that there is one malloc() for the array itself and one malloc() for each row.
The code that frees this is basically the same in reverse.
Also, in general, double pointers are basically dynamically allocated arrays right?
Not necessarily. Dynamically allocated arrays is one use for double pointers, but it's far from the only use.
Calls to malloc allocate memory on the heap, equal to the number of bytes specified by its argument, and returns the address of this block of memory. Your '2D array' is really a 1D array of int addresses, each pointing to a chunk of memory allocated by malloc. You need to free each of these chunks when you are done, making it available for others to use. But your 1D array is really just another malloc'd chunk of memory to hold these malloc'd addresses, and that needs to be freed also.
Also, when you use printf("%s", array) where array is an char *, the compiler sees the array as the address of array[0] but prints it right? I'm just curious if I'm understanding it right.
Yes, %s tells printf to go to whatever address you give it (an address of a char, aka a char*, let's say), and start reading and displaying whatever is in memory at that address, one character at a time until it finds a 'NULL character'. So in the case of a string, that is the expected behavior, since a string is just an array of chars, followed by the '\0' char.

How is initializing an array different from mallocing memory?

I am new to C++. I am having trouble differentiating between initializing an array and mallocing memory. To me, they seem to accomplish the same purpose.
Specifically, I can initialize an array via int myArray[] = {1, 2, 3};. I can also use malloc to obtain memory and assign it to a void pointer. Later, I free this memory.
What is the difference between these two methods? Does a computer store the data in the same places and in the same ways?
In C++ there are two different ways you can allocate memory. The first way allocates memory on the stack.
int arr[] = {1,2,3};
int arr[3];
Both of these lines of code create an array of size 3 on the stack. The only difference is the first line also initializes the values in the array.
The second way you can allocate memory is on the heap. The amount of memory available on the heap is usually much larger than is available on the stack. The new and malloc operations allocate memory on the heap.
int* arr = (int*) malloc(100*sizeof(int));
int* arr = new int[100];
Both of these lines of code create an array of size 100 on the heap. Now here's the difference between the two. In C++ you should always use new because it ensures that the constructors for each element in your array are called. It is also much more type safe, unlike malloc which isn't type safe at all since it just returns a void* to a chunk of bytes that can be interpreted anyway you'd please.
Now if you're dynamically allocating memory, meaning you don't know the size of the array until runtime, you should always allocate it on the heap using new/malloc.
Last thing to note is how you free your memory, using delete/free.
free(arr); //arr was allocated with malloc
delete[] arr; //arr was allocated with new
If you allocated memory with new it must be freed with delete. You can't mix and match new/malloc with delete/free. Lastly delete[] frees an array of objects. If you only allocated a single object then you just use delete.
Object* myobj = new Object;
delete myobj;
In my opinion, this question does not belong to here. But I will answer it. You can do that with:
int* myArray = (int *) malloc(3 * sizeof(int));
This means that you are creating memory location with memory size 3 * sizeof(int) [i.e. the size of the integer data type in C], and you re returning an int pointer to this memory location. [i.e. a pointer that points to the beginning of it, and deal with it as it if contains integers]. These memory slots are converted to int * (using (int *)), and called myArray. myArray is an int array (and an int pointer). Because arrays are actually pointers in C. Then you do:
for (int i = 0; i < 3; i++)
myArray[i] = i + 1;
There could be some issues in malloc. Therefore, after the initialization always check if myArray == NULL. If this is case, fix the error, and dont initialize the array with $\{1,2,3\}$. Otherwise, you will get a segmentation fault.
I wish I am not vague to you. But since you are using C++, I would suggest you use the new operator instead. you would do:
int myArray[] = new int[3];

Resources