Get size of a simulated array using malloc - c

I have a simulated 2D array using pointers with malloc and I want to get the size of that array, since sizeof() returns me the size of the pointer.
My code (ANSI C):
void main(){
int s1=10;
int s2=15;
int ** rack=(int**)malloc(s1*sizeof(int**));
for(int i=0; i<s1; i++) rack[i]=(int*)malloc(s2*sizeof(int*));
}
I want a function (may by system, may do it myself) this way:
size(rack) //returns 10
size(rack[0]) //returns 15
Thanks in advance! (For more info I use GNU/Linux)

First of all, the way you allocate memory for your 2D array is wrong. You need to change it to :
void main(){
int s1 = 10;
int s2 = 15;
int** rack = malloc(s1*sizeof(int*));
if (rack == NULL)
return;
for(int i=0; i<s1; i++) {
rack[i]=malloc(s2*sizeof(int));
if (rack[i] == NULL)
return;
}
...
free(rack);
return;
}
Remember to always check malloc's result and also not to cast malloc's result.
In order to get your array's size, you can print s1*s2*sizeof(int) as you have allocated s1 pointers to int, each of which holds s2 ints.

Related

how to allocate arrays (in array of pointers) C -- can it be done in one line? with malloc

is there a simple one liner I can use in C to allocate arrays in (pointer of arrays)
This line creates 10 pointers of arrays
char *out[10];
I can't do this
char *out[100]=(char[10][100])malloc(sizeof(char)*10*100);
error: cast specifies array type
same error with
char *out[10]=(char*[10])malloc(sizeof(char)*10*100);
do I need to do it in loop like this
int main()
{
char *out[10];
int x=0;
while(x<10)
{
*(out+x)=malloc(sizeof(char)*100);// is this line correct?
x++;
}
*out[0]='x';
printf("%c\n",out[0][0]);
free(out);
return 0;
}
but this cause warning that
req.c:75:3: warning: attempt to free a non-heap object ‘out’ [-Wfree-nonheap-object]
75 | free(out);
so do I need to allocate and free each array in (array of pointers) in loop
Can't I do allocation and free arrays in array of pointer in one line instead of loop?
or is there anything thing in my loop wrong too
To allocate an array of pointers to strings, you need to do:
char** out = malloc(sizeof(char*[10]));
The whole point of using this form is that each pointer in that array of pointers can be allocated with individual size, as is common with strings. So it doesn't make sense to allocate such with a "one-liner", or you are using the wrong type for the task.
In case you don't need individual sizes but are rather looking for a char [10][100] 2D array with static size, then the correct way to allocate such is:
char (*out)[100] = malloc(sizeof(char[10][100]));
You can allocate the full array in one single step and have pointers inside that array:
char *out[10];
data = malloc(100); //sizeof(char) is 1 by definition
for (int x=0; x<10; x++) {
out[i] = data + x * 10;
}
*out[0] = 'x';
printf("%c\n",out[0][0]);
free(data); // you must free what has been allocated
int i;
char** out = (char**)malloc(sizeof(char*)*10);
for(i = 0; i<10;i++)
out[i] = (char*)malloc(sizeof(char)*100);
out[1][1] = 'a';
OR with same dimensions
#include <stdio.h>
#include <stdlib.h>
void main()
{
int r = 10, c = 100; //Taking number of Rows and Columns
char *ptr, count = 0, i;
ptr = (char*)malloc((r * c) * sizeof(char)); //Dynamically Allocating Memory
for (i = 0; i < r * c; i++)
{
ptr[i] = i + 1; //Giving value to the pointer and simultaneously printing it.
printf("%c ", ptr[i]);
if ((i + 1) % c == 0)
{
printf("\n");
}
}
free(ptr);
}

realloc a 2d-array with a void function in c

I am trying to modify a 2D array from a void function.
#include <stdio.h>
#include <stdlib.h>
void try_by_reference(int **arr){
*arr = realloc(*arr, sizeof *arr * 2);
}
int main(int argc, char **argv){
// declare dynamic 2d-array and allocate memory
int (*arr)[2] = malloc(sizeof *arr * 10);
// fill array
for (int i=0; i<10; i++){
arr[i][0] = i;
arr[i][1] = i+10;
}
// declare and fill a simpler dynamic array
int *tarr = malloc(sizeof(int) * 10);
for (int i=0; i<10; i++)
tarr[i] = i*2;
try_by_reference(&tarr);
try_by_reference(&arr); <-- this gets warning
free(arr);
free(tarr);
return 0;
}
Compiler says:
warning: incompatible pointer types passing 'int (**)[2]' to parameter of type 'int **'
What am I doing wrong?
Thank you!
_"I am trying to modify a 2D array from a void function."_
Here are some tips, and fixes that will allow you to update memory to an array of two pointers to int. (see comment in-line with your code)
void try_by_reference(int **arr){
//always use a temporary variable to call realloc, otherwise if failed attempt - memory leak will occur
int *tmp = realloc(*arr, 2 * sizeof(*arr));//this effectively reduces memory from original 10, to 2 instances of int
if(!tmp)//always check return of realloc, if it fails free original memory and return
{
free(*arr);
//set pointer to NULL here to provide way to test before
//freeing later in process. (See 'Reference' below)
*arr = NULL;//to prevent problems in subsequent free calls
return;
}
else *arr = tmp;
}
int main(int argc, char **argv){
// declare dynamic 2d-array and allocate memory
int *arr[2] = {NULL, NULL};//this is an array of 2 pointers to int - each
//need to be allocated
//it will result in an array shaped as array[2][10]
//after following calls to malloc.
arr[0] = malloc(10*sizeof(arr[0]));//original provides memory for 10 instances of int
if(arr[0])
{
arr[1] = malloc(10*sizeof(arr[1]));
if(arr[1])
{
// fill array
//for (int i=0; i<10; i++){
for (int i=0; i<10; i++){
//arr[i][0] = i;
//arr[i][1] = i+10;
arr[0][i] = i;//switch indices
arr[1][i] = i+10;//switch indices
}
}
}
// declare and fill a simpler dynamic array
int *tarr = malloc(sizeof(int) * 10);
for (int i=0; i<10; i++)
tarr[i] = i*2;
try_by_reference(&tarr);
//try_by_reference(&arr); <-- this gets warning
//pass address of each pointer to memory, one at a time
try_by_reference(&(arr[0]));
try_by_reference(&(arr[1]));
//To prevent UB from calling free on an already freed pointer
//test before calling free.
if(arr[0]) free(arr[0]);//need to free each of two pointers to memory
if(arr[1] free(arr[1]);//...
if(tarr) free(tarr);
return 0;
}
Reference regarding why set pointer to NULL after freeing. If the call to realloc() fails, thus resulting in freeing the original pointer, setting the pointer == NULL provides a way to test before calling free() later in process, thus avoiding the potential of invoking undefined behavior (UB).
There are several ways to create varying shapes of nD arrays memory in C, some of them easier to update memory than the form int *arr[2]. But I stay with this form to illustrate specifically a way to update it. Although it requires more rigor to access elements, for a int[2][10] implemented by pointers, I prefer creating an int *arr = malloc(2*10*sizeof(*arr));. Observe the following examples for ease of use comparisons. (using a 2D like, but of different dimensions):
int arr1[3][6] = {{1,2,3,4,5,6},{7,8,9,10,11,12},{13,14,15,16,17,18}};
//same memory as
int arr2[18] = {{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18}};
knowing that *(arr1 + 2*6 + 5) == arr2[2][5] = 18;
*(arr1 + 0*6 + 4) == arr2[0][4] = 5;
*(arr1 + 1*6 + 0) == arr2[1][0] = 7;
// | | |_2nd index range 0 - 5
// | |_ constant -> sizeof(arr1[0]/arr1[0][0])
// |1st index range is from 0 - 2
The same is true for dynamic memory. int **arr1 and *arr2
int **arr1 //requires 7 calls to malloc/free
int *arr2 //requires 1 call to malloc/free

Setting Dynamic arrays equal to eachother in C

int staticArrayA[10];
int staticArrayB[10];
int *dynamicArrayA = (int *)malloc(sizeof(int) * 10);
int *dynamicArrayB = (int *)malloc(sizeof(int) * 10);
From what I understand, the value of staticArrayA is a pointer to the 1st element in the array, however the pointer that represents this base address behaves like a const pointer and cannot be changed, in which case it makes sense that you cannot set:
staticArrayA = staticArrayB;
But what about dynamic arrays? if they are both just pointers to a contiguous block of bytes in memory, then why can't you set them equal to eachother?
dynamicArrayA = dynamicArrayB;
It seems like the address that dynamicArrayA points to would now be the same address that dynamicArrayB points to. Please give me some insight. Perhaps I am wrong, but here is what I was trying to do:
/* remove any element that is 0 from array. n is size of array */
void compressArray(int *array, int n) {
int size = n;
int index = 0;
int *nuArray = (int *)malloc(sizeof(int) * n);
assert(nuArray != NULL);
for (int i = 0; i < n; i++) {
if (array[i] != 0) {
nuArray[index] = array[i];
index++;
size--;
}
}
nuArray = realloc(nuArray, sizeof(int) * size);
assert(nuArray != NULL);
array = realloc(array, sizeof(int) * size);
assert(array != NULL);
array = nuArray; //This doesn't seem to work
free(nuArray);
}
int main(int argc, const char * argv[]) {
int *array = (int *)malloc(sizeof(int) * 10);
assert(array != NULL);
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) {
array[i] = 0;
} else {
array[i] = i;
}
}
compressArray(array, 10);
return 0;
}
I am sure that there are much simpler and more elegant ways to write the function, and i know that I can copy all the elements of nuArray into array and then use realloc() to reduce the size, however, I am just hoping someone can give some insight into the nature of dynamic arrays and explain some of this behavior and tell me why the assignment does not work, or if there are cases in which it does. Also, i could have the function return an int * and set array = to this function call and that works, however why can't i do it inside the function? Thanks for your time and for any help.
if they are both just pointers to a contiguous block of bytes in memory, then why can't you set them equal to each other?
Of course you can. You just have to know the ramifications.
int *dynamicArrayA = (int *)malloc(sizeof(int) * 10);
int *dynamicArrayB = dynamicArrayA;
Now dynamicArrayB and dynamicArrayA point to the same memory. You change the value of what one points to, the change will be visible through other pointer too.
dynamicArrayB[0] = 10; // dynamicArrayA[0] is 10.
dynamicArrayA[5] = 15; // dynamicArrayB[5] is 15.
If that's your objective, you can do that without any problem.
Update, in response to OP's comment
The line
array = nuArray; //This doesn't seem to work
changes the value of array locally in compressArray. That does not change the value of array in main.
You'll have to come up with a different method to return nuArray back to main.
One solution to the problem would be to change the return type of compressArray from void to char* and return nuArray from the function.
int *dynamicArrayA = (int *)malloc(sizeof(int) * 10);
int *dynamicArrayB = (int *)malloc(sizeof(int) * 10);
After this if you do this ( which ofcourse is possible ) -
dynamicArrayA = dynamicArrayB; //you want this then don't allocate memory to dynamicArrayA
Now , dynamicArrayA won't point to memory allocate by malloc to it previously , so you won't be able to free that memory block . Thus , can lead to memory leak.
You can use memcpy for this task -
/* allocate memory to both dynamicArrayA and to dynamicArrayB */
for(int i=0;i<10;i++){
dynamicArrayA[i]=i+1; // store value in dynamicArrayA
}
memcpy(dynamicArrayB,dynamicArrayA,sizeof(int)*10); //copy it to dynamicArrayB
for(int i=0;i<10;i++)
printf("%d",dynamicArrayB[i]); // print values
free(dynamicArrayA);
free(dynamicArrayB);
Let's take a look at what's actually happening at the end of compressArray:
array = nuArray;
After this statement, array now points to the same memory that nuArray points to. The memory that array previously pointed to is now accessible inside of compressArray, however array in main still points to the original memory block. That's because the address of this block is what was passed to compressArray, not the address of the array variable.
free(nuArray);
This frees the memory pointed to by nuArray. But since array contains the same value as nuArray, i.e. the address of the memory block pointed to by nuArray, now array points to a freed block of memory, and accessing it is undefined behavior.
When the function returns, the value of array in main is unchanged. That's because the value of array was passed in.
For this to work as expected, compressArray needs to take the address of a pointer (an int **) and change what that points to:
void compressArray(int **array, int n) { // "array" is a pointer to an array
int size = n;
int index = 0;
int *nuArray = (int *)malloc(sizeof(int) * n);
assert(nuArray != NULL);
for (int i = 0; i < n; i++) {
if ((*array)[i] != 0) { // note how we're now accessing the array
nuArray[index] = (*array)[i]; // same here
index++;
size--;
}
}
nuArray = realloc(nuArray, sizeof(int) * size);
assert(nuArray != NULL);
free(*array); // We don't need the memory array pointed to anymore, so free it
*array = nuArray; // This changes "array" in main. Also, don't free nuArray,
// otherwise *array will also point to freed memory
}
Then you call it like this:
compressArray(&array, 10);
// print the new contents of array
free(array); // We're done with it now, so free it

Trouble with using calloc with an array and returning a pointer

As a reference this is the second part of my assignment:
int* generateFibonacci(int size);
This function will take as input an integer called size. The value contained in the size variable
will represent how many numbers in the Fibonacci sequence to put into the array. The function
will use calloc to create the array of this size and then fill the array with size numbers from the
Fibonacci sequence, starting with 1 and 1. When the array is complete the function will return a
pointer to it.
My trouble come in play when I get the error in line 8 "warning: assignment makes and integer from pointer without a cast".
Another error I get is in line 19 "warning: return makes pointer from integer without a cast".
So my question is, how am I suppose to set up calloc to make the array with a size from a user, then return a pointer to it?
#include <stdio.h>
#include <stdlib.h>
int* generateFibonacci(int size)
{
int i, array[size];
array[size]=(int*)calloc(size, sizeof(int));
array[0]=0;
array[1]=1;
for(i = 2; i < size+1; i++)
array[i] = array[i-2] + array[i-1];
return *array;
}
void printHistogram (int array[], int size)
{
int i, j;
for(i=0; i <= size; ++i)
{
for(j=0; j < array[i]; j++)
{
printf("*");
}
printf("\n");
}
}
int main(void)
{
int array[100], size;
printf("how big will your Fibionacci number be? ");
scanf("%i", &size);
generateFibonacci(size);
printHistogram(array, size);
return 0;
}
how am I suppose to set up calloc to make the array with a size from a user, then return a pointer to it?
For a 1D array of int * Use printf() and scanf()
int *array = {0}; //Note, leaving this initialization method for posterity
//(See related comments below.)
//however agreeing with commentator that the more idiomatic
//way to initialize would be: int *array = NULL;
size_t size = 0;
printf("Enter order of array");
scanf("%d", &size);
array = malloc(size);//create memory with space for "size" elements
if(array){//do other stuff}
But it is unclear from your example, and the comment if you really intend using a 2D array....
As stated in the comments, You have created an int array, then attempted to create memory for it.
int i, array[size];
...
array[size]=(int*)calloc(size, sizeof(int));//wrong
As it is created, array does not need memory. Memory is created on the stack as automatic.
If you wanted a 2D array of int. Then you could do it like this:
int *array[size]; //create a pointer to int []
With this, you can create an array of arrays (in concept) in this way:
for(i=0;i<size;i++) array[i]= calloc(size, sizeof(int));//do not cast the output, not necessary
Now, you essentially have a size x size 2D array of int. It can be assigned values in this manner:
for(i=0;i<size;i++)
for(j=0;j<size;j++)
array[i][j]=i*j;//or some more useful assignment
By the way, adjust the parameters of the calloc() statement as needed, but note, casting its output is not necessary.
Regarding the return statement, your function is prototyped to return a int *.
int* generateFibonacci(int size){...} //requires a return of int *
If you decide to use a 1D array, i.e. int *array={0} (requiring that you allocate memory), then return:
return array;//array is already a `int *`, just return it.
If you are using the 2D array, then to return a int *, you must decide which of the size elements of the array you want to return:
return array[i];//where `i` can be any index value, from 0 to size-1

C - function returns an array

I'm writing a method that receives a number l and returns a vector of size l with random numbers. I have this code, but does not work
#include <time.h>
int makea (int z) {
int a1[z];
int i;
for (i = 0; i < tam; i++) {
a1[i]=srand(time(0));
}
return a1;
}
These are the errors that the compiler returns me
arrays1.c: In function 'makea':
arrays1.c:12: error: void value not ignored as it ought to be
arrays1.c:14: warning: return makes integer from pointer without a cast
arrays1.c:14: warning: function returns address of local variable
I think is a problem of pointers... but I'm not really sure
A few problems:
Your array is allocated on the stack, meaning that when your function exits, the memory you return will be invalid
In C, you cannot return an array from a function, it must first decay into a pointer.
So, to fix, use malloc and a pointer:
int *makea (int z) {
int *a1 = malloc(sizeof(int) * z);
int i;
srand(time(NULL));
for (i = 0; i < tam; i++) {
a1[i]= rand();
}
// remember to free a1 when you are done!
return a1;
}
Also note that using malloc can sometimes basically grant you the 'random number' scenario for free, negating the need to loop through the elements as the value returned from malloc is garbage (and thus random numbers).
However, also note that malloc is implementation-specific, meaning that an implementation could theoretically clear the memory for you before returning it.
Your best bet is:
Declare the array outside of the routine, and pass it in to initialize it:
void init_array (int a[], nelms)
Plan B is pass a pointer to a pointer, and have the routine allocate and initialize it
Like this:
void alloc_and_init_array (int **a_pp, int nelms)
{
*a_pp = malloc (sizeof (int) * nelms);
...
... or, equivalently ...
int *
alloc_and_init_array (int nelms)
{
int *a_p = malloc (sizeof (int) * nelms);
...
return a_p;
A local variable like your array is allocated on the stack. At function return it is removed from the stack, so the pointer you return points to an unallocated memory location.
You have to allocate the array with malloc() or pass an already existing array to the function.
#include <time.h>
int makea (int z) {
int *a1 = (int*)malloc(z*sizeof(int));
int i;
for (i = 0; i < tam; i++) {
a1[i]=srand(time(0));
}
return a1;
}
IMPORTANT: remember to free memory allocated somewhere outside, when you do not need it anymore.
Well, first off your function says that it returns an int, yet you want to return an array, so that is wrong. Of course, you can't return an array in C either...
Second, you will have to return a pointer. You cannot copy arrays via assignment or assign a new value to an array at all in C, so your function won't be very useful. Either return an int* or take an int** as an output argument and initialize it in your function.
Also, your array is locally allocated, so even if the compiler didn't complain you would be returning invalid memory.
int makea (int size, int **out_array) {
int *temp, i;
if(!out_array)
return 0;
temp = malloc(sizeof(int) * size);
if(!temp)
return 0;
srand(time(0));
for (i = 0; i < size; ++i)
temp[i] = rand();
*out_array = temp;
return 1;
}
int main() {
int *arr;
if(!makea(10, &arr)) {
printf("Failed to allocate array");
return -1;
}
return 0
}
Another note:
temp[i] = srand(time(0));
That is wrong. srand seeds the random number generator, but does not return a random number. You call srand to input the seed and then call rand to get a random number.

Resources