C - malloc array in function and then access array from outside - c

Here is how I malloc an int var and then access this var outside of the function
int f1(int ** b) {
*b = malloc(sizeof(int));
**b = 5;
}
int main() {
int * a;
f1(&a);
printf("%d\n", *a);
// keep it clean :
free(a);
return 0;
}
Using same logic above, how do I malloc a 1 dim array inside a function and then access it outside of the func?
Please help, I am bit confused with pointers to array.

In exactly the same way but with some different arithmetic. You can think of what you are doing now as allocating an array with one element. Just multiply sizeof(int) by the number of elements you want your array to have:
int f1(int ** b, int arrsize) {
*b = malloc(sizeof(int) * arrsize);
// then to assign items:
(*b)[0] = 0;
(*b)[1] = 1;
// etc, or you can do it in a loop
}
int main() {
int * a, i;
int size = 20;
f1(&a, size); // array of 20 ints
for (i = 0; i < size; ++i)
printf("%d\n", a[i]); // a[i] is the same as *(a + i)
// so a[0] is the same as *a
// keep it clean :
free(a);
return 0;
}

(untested, but I believe it'll work)
int f1(int ** b) {
*b = malloc(sizeof(int)*4);
(*b)[0] = 5;
(*b)[1] = 6;
(*b)[2] = 7;
(*b)[3] = 8;
}
int main() {
int * a;
f1(&a);
printf("%d %d %d %d\n", a[0], a[1], a[2], a[3]); // should be "5 6 7 8"
// keep it clean :
free(a);
return 0;
}

You are almost there *b = malloc(sizeof(int)); allocates space for a single int ( a bit pointless since the pointer is at least as big as this)
The more normal usage is *b = malloc(number_of_ints*sizeof(int));
Remember that the [] syntax just does the array maths for you (a+10) and a[10] point to exactly the same thing memory location, so you can allocate it using malloc, pass the poitner and refer to it as an array.
The only things about arrays and pointers that is complicated (apart from remembering when to use * and &) is that malloc() works in bytes, so you need to tell it the sizeof an int. But the int * it returns knows about ints so to get to the next value you only need to do a++ or a+1 or a[1] even though it is really 4 or 8 bytes different in value.

Instead of malloc()ing a single int, malloc the array.
int f1(int * b) {
b = malloc(ARRAY_LENGTH * sizeof(int));
*b = 5;
b[1] = 6;
*(b + 2) = 7;
}

You'll want to use a calloc call instead of malloc (See this: http://www.manpagez.com/man/3/calloc/)

Related

different ways to declare a matrix c

I don't really understand why method 1 works but not method 2. I don't really see why it works for characters and not an int.
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
/// WORK (METHODE 1)
char **string_array = malloc(sizeof(char **) * 10);
string_array[0] = "Hi there";
printf("%s\n", string_array[0]); /// -> Hi there
/// DOES NOT WORK (METHODE 2)
int **int_matrix = malloc(sizeof(int **) * 10);
int_matrix[0][0] = 1; // -> Segmentation fault
/// WORK (METHODE 3)
int **int_matrix2 = malloc(sizeof(int *));
for (int i = 0; i < 10; i++)
{
int_matrix2[i] = malloc(sizeof(int));
}
int_matrix2[0][0] = 42;
printf("%d\n", int_matrix2[0][0]); // -> 42
}
In terms of the types, you want to allocate memory for the type "one level up" from the pointer you're assigning it to. For example, an int pointer (an int*), points to one or more ints. That means, when you allocate space for it, you should allocate based on the int type:
#define NUM_INTS 10
...
int* intPtr = malloc(NUM_INTS * sizeof(int));
// ^^ // we want ints, so allocate for sizeof(int)
In one of your cases, you have a double int pointer (an int**). This must point to one or more int pointers (int*), so that's the type you need to allocate space for:
#define NUM_INT_PTRS 5
...
int** myDblIntPtr = malloc(NUM_INT_PTRS * sizeof(int*));
// ^^ "one level up" from int** is int*
However, there's an even better way to do this. You can specify the size of your object it points to rather than a type:
int* intPtr = malloc(NUM_INTS * sizeof(*intPtr));
Here, intPtr is an int* type, and the object it points to is an int, and that's exactly what *intPtr gives us. This has the added benefit of less maintenance. Pretend some time down the line, int* intPtr changes to int** intPtr. For the first way of doing things, you'd have to change code in two places:
int** intPtr = malloc(NUM_INTS * sizeof(int*));
// ^^ here ^^ and here
However, with the 2nd way, you only need to change the declaration:
int** intPtr = malloc(NUM_INTS * sizeof(*intPtr));
// ^^ still changed here ^^ nothing to change here
With the change of declaration from int* to int**, *intPtr also changed "automatically", from int to int*. This means that the paradigm:
T* myPtr = malloc(NUM_ITEMS * sizeof(*myPtr));
is preferred, since *myPtr will always refer to the correct object we need to size for the correct amount of memory, no matter what type T is.
Others have already answered most of the question, but I thought I would add some illustrations...
When you want an array-like object, i.e., a sequence of consecutive elements of a given type T, you use a pointer to T, T *, but you want to point to objects of type T, and that is what you must allocate memory for.
If you want to allocate 10 T objects, you should use malloc(10 * sizeof(T)). If you have a pointer to assign the array to, you can get the size from that
T * ptr = malloc(10 * sizeof *ptr);
Here *ptr has type T and so sizeof *ptr is the same as sizeof(T), but this syntax is safer for reasons explained in other answers.
When you use
T * ptr = malloc(10 * sizeof(T *));
you do not get memory for 10 T objects, but for 10 T * objects. If sizeof(T*) >= sizeof(T) you are fine, except that you are wasting some memory, but if sizeof(T*) < sizeof(T) you have less memory than you need.
Whether you run into this problem or not depends on your objects and the system you are on. On my system, all pointers have the same size, 8 bytes, so it doesn't really matter if I allocate
char **string_array = malloc(sizeof(char **) * 10);
or
char **string_array = malloc(sizeof(char *) * 10);
or if I allocate
int **int_matrix = malloc(sizeof(int **) * 10);
or
int **int_matrix = malloc(sizeof(int *) * 10);
but it could be on other architectures.
For your third solution, you have a different problem. When you allocate
int **int_matrix2 = malloc(sizeof(int *));
you allocate space for a single int pointer, but you immediately treat that memory as if you had 10
for (int i = 0; i < 10; i++)
{
int_matrix2[i] = malloc(sizeof(int));
}
You can safely assign to the first element, int_matrix2[0] (but there is a problem with how you do it that I get to); the following 9 addresses you write to are not yours to modify.
The next issue is that once you have allocated the first dimension of your matrix, you have an array of pointers. Those pointers are not initialised, and presumably pointing at random places in memory.
That isn't a problem yet; it doesn't do any harm that these pointers are pointing into the void. You can just point them to somewhere else. This is what you do with your char ** array. You point the first pointer in the array to a string, and it is happy to point there instead.
Once you have pointed the arrays somewhere safe, you can access the memory there. But you cannot safely dereference the pointers when they are not initialised. That is what you try to do with your integer array. At int_matrix[0] you have an uninitialised pointer. The type-system doesn't warn you about that, it can't, so you can easily compile code that modifies int_matrix[0][0], but if int_matrix[0] is pointing into the void, int_matrix[0][0] is not an address you can safely read or write. What happens if you try is undefined, but undefined is generally was way of saying that something bad will happen.
You can get what you want in several ways. The closest to what it looks like you are trying is to implement matrices as arrays of pointers to arrays of values.
There, you just have to remember to allocate the arrays for each row in your matrix as well.
#include <stdio.h>
#include <stdlib.h>
int **new_matrix(int n, int m)
{
int **matrix = malloc(n * sizeof *matrix);
for (int i = 0; i < n; i++)
{
matrix[i] = malloc(m * sizeof *matrix[i]);
}
return matrix;
}
void init_matrix(int n, int m, int **matrix)
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
matrix[i][j] = 10 * i + j + 1;
}
}
}
void print_matrix(int n, int m, int **matrix)
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
printf("%d ", matrix[i][j]);
}
printf("\n");
}
}
int main(void)
{
int n = 3, m = 5;
int **matrix = new_matrix(n, m);
init_matrix(n, m, matrix);
print_matrix(n, m, matrix);
return 0;
}
Here, each row can lie somewhere random in memory, but you can also put the row in contiguous memory, so you allocate all the memory in a single malloc and compute indices to get at the two-dimensional matrix structure.
Row i will start at offset i*m into this flat array, and index matrix[i,j] is at index matrix[i * m + j].
#include <stdio.h>
#include <stdlib.h>
int *new_matrix(int n, int m)
{
int *matrix = malloc(n * m * sizeof *matrix);
return matrix;
}
void init_matrix(int n, int m, int *matrix)
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
matrix[m * i + j] = 10 * i + j + 1;
}
}
}
void print_matrix(int n, int m, int *matrix)
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
printf("%d ", matrix[m * i + j]);
}
printf("\n");
}
}
int main(void)
{
int n = 3, m = 5;
int *matrix = new_matrix(n, m);
init_matrix(n, m, matrix);
print_matrix(n, m, matrix);
return 0;
}
With the exact same memory layout, you can also use multidimensional arrays. If you declare a matrix as int matrix[n][m] you will get what amounts to an array of length n where the objects in the arrays are integer arrays of length m, exactly as on the figure above.
If you just write that expression, you are putting the matrix on the stack (it has auto scope), but you can allocate such matrices as well if you use a pointer to int [m] arrays.
#include <stdio.h>
#include <stdlib.h>
void *new_matrix(int n, int m)
{
int(*matrix)[n][m] = malloc(sizeof *matrix);
return matrix;
}
void init_matrix(int n, int m, int matrix[static n][m])
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
matrix[i][j] = 10 * i + j + 1;
}
}
}
void print_matrix(int n, int m, int matrix[static n][m])
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
printf("%d ", matrix[i][j]);
}
printf("\n");
}
}
int main(void)
{
int n = 3, m = 5;
int(*matrix)[m] = new_matrix(n, m);
init_matrix(n, m, matrix);
print_matrix(n, m, matrix);
int(*matrix2)[m] = new_matrix(2 * n, 3 * m);
init_matrix(2 * n, 3 * m, matrix2);
print_matrix(2 * n, 3 * m, matrix2);
return 0;
}
The new_matrix() function returns a void * because the return type cannot depend on the runtime arguments n and m, so I cannot return the right type.
Don't let the function types fool you, here. The functions that take a matrix[n][m] argument do not check if the matrix has the right dimensions. You can get a little type checking with pointers to arrays, but pointer decay will generally limit the checking. The last solution is really only different syntax for the previous one, and the arguments n and m determines how the (flat) memory that matrix points to is interpreted.
The method 1 works only becuse you assign the char * element of the array string_array with the reference of the string literal `"Hi there". String literal is simply a char array.
Try: string_array[0][0] = 'a'; and it will fail as well as you will dereference not initialized pointer.
Same happens in method 2.
Method 3. You allocate the memory for one int value and store the reference to it in the [0] element of the array. As the pointer references the valid object you can derefence it (int_matrix2[0][0] = 42;)

Concat Arrays in C

I'm exercising a bit in programming C.
One task is to concat two dynamic arrays. The elements of the second array should be added to the end of the first array. The following is given:
void concatArrays(int* numbers1, int length1, int* numbers2, int length2)
{
//code
}
And that is my code to solve the task:
#include <stdio.h>
#include <stdlib.h>
void concatArrays(int* numbers1, int length1, int* numbers2, int length2)
{
numbers1 = (int*)realloc(numbers1, sizeof(int*) * (length1 + length2));
for (int count = 0; count < length2; count++)
{
numbers1[length1 + count] = numbers2[count];
}
}
int main()
{
int* num = (int*)malloc(sizeof(int*) * 6);
num[0] = 1;
num[1] = 2;
num[2] = 3;
num[3] = 4;
num[4] = 5;
num[5] = 6;
int* numbers = (int*)malloc(sizeof(int*) * 4);
numbers[0] = 1;
numbers[1] = 2;
numbers[2] = 3;
numbers[3] = 4;
concatArrays(num, 6, numbers, 4);
for (int count = 0; count < 10; count++)
{
printf("%d - ", num[count]);
}
return 0;
}
Unfortunately, it doesn't work. I do know that the code does work if I used a pointer to a pointer:
void concatArrays(int** numbers1, int length1, int** numbers2, int length2) { //code }
Nonetheless, that seems to be not allowed regarding the task requirements.
Do you have any idea how I could change my code meeting the requirements to solve the task?
Thank you in advance.
Edit:
I forgot:
The output:
1 - 2 - 3 - 4 - 5 - 6 - 2054454589 - 32767 - -1280384664 - 32767 -
void concatArrays(int* numbers1, int length1, int* numbers2, int length2)
Given prototype is pass by value for your case.
Hence when you reallocate the memory.
numbers1 = (int*)realloc(numbers1, sizeof(int*) * (length1 + length2));
You are allocating for local copy not for original copy.
Note that it is not guaranteed that new pointer returned by realloc
will be same as old.
code does work if I used a pointer to a pointer.
That is because you will be passing by reference any modification inside function will update the original variables.
Thus allocate the more memory in the main itself.
int* num = (int*)malloc(sizeof(int) * 10);
There is a failure in the memory allocation, respective on type.
Note that the values of array are ints, so by the allocation they occupy not a pointer size memory more likely int size spaces:
so the allocation should look like this for int arrays:
void concatArrays(int** numbers1, int* length1, const int* numbers2, const int length2)
{
*length1 = *length1 + length2;
*numbers1 = (int*)realloc(*numbers1, sizeof(int) * (*length1));
...
}
Note that the size of an int pointer (int*) may be different than the size of a pure int type.

Why does a pointer to a multidimensional array return segmentation fault when accessed after passing the pointer to a function?

So I don't really know what this problem is really called so searching and googling leads to different answers which does not answer my question.
This is the code:
#include <stdio.h>
#include <stdlib.h>
void gen_matrix(int **array, int rm, int cm) {
// int ** array;
int r, c;
array = (int **) malloc(sizeof(int *) * rm);
for (int r = 0; r < rm; ++r) {
array[r] = (int *) malloc(sizeof(int) * cm);
for (int c = 0; c < cm; ++c) {
array[r][c] = 1;
} // c
} // r
}// gen_matrix
int main() {
int **a;
gen_matrix(a, 2, 2);
printf("%d", a[0][0]);
return 0;
}
The problem is that printf() in main() returns Segmentation Fault. What I found out is that the address that the pointer a in main() points to does not change when malloc() is used inside gen_matrix().
In gen_matrix(), I can access the array just fine, but after I return to main(), the pointer a does not point to the array malloc() created.
Thank you.
You are losing the update to array when gen_matrix() returns, because you are not passing it the address of a. You could add an extra indirection level by passing in the address of a to gen_matrix(), but it would be cleaner to just have gen_matrix() return the malloced address and assign it to a in main():
int **gen_matrix(int rm, int cm) {
int ** array;
array = malloc(sizeof(*array) * rm);
for (int r = 0; r < rm; ++r) {
array[r] = malloc(sizeof(*(array[r])) * cm);
for (int c = 0; c < cm; ++c) {
array[r][c] = 1;
} // c
} // r
return array;
}// gen_matrix
int main() {
int **a;
a = gen_matrix(2, 2);
printf("%d", a[0][0]);
return 0;
}
Also, it's not a good idea to cast the return from malloc() and it is preferable to dereference the pointer the memory is being assigned to to get the proper size for sizeof().
And you should of course free() the memory before exiting.
When you call your function the parameter int ** array is the "array itself". What you need is a reference to it, either with one more level of pointer indirection or a C++-style reference. So, what you do is you modify the function to accept a triple-pointer:
void gen_matrix(int ** * array, int rm, int cm) {
and when you call it you also get the address of the "pointer to the matrix":
gen_matrix(&a, 2, 2);
of course you have to modify the code in the function to take care of that extra indirection:
*array = (int **) malloc(sizeof(int *) * rm);
and in the other two places as well.

changing adress of pointer created using malloc

I am trying to understand how malloc and pointer works.
#include <stdio.h>
#include <stdlib.h>
int main() {
int *p;
int b = 15;
p = (int *)malloc(sizeof(int) * 10);
for (int i = 0; i < 5; i++) {
p + i = &b;
}
}
The above code gives error
expression is not assignable
p + i = &b;
As far as I understand, malloc gives the starting address of the memory allocated in heap which I typecast to hold the address of integers. So technically, p + i should be able to hold any integer address, but the code throws an error. Can you please explain why this is wrong.
Thanks
The line of code p = (int *)malloc(sizeof(int) * 10); means that the pointer p is assigned the address of the first element of the dynamically allocated array with malloc(),which has allocated an int array consisting of 10 elements.
If you want to assign 5 of these elements the value of b then you write:
for (int i = 0; i < 5; i++) {
p[i] = b;
}
If however you want an array of 10 integer pointers and want to assign 5 of them the address of b,then you write:
int **pointer = (int **)malloc(sizeof(int *) * 10);
for (int i = 0; i < 5; i++) {
pointer[i] = &b;
}
Don't forget to free dynamically allocated memory when you finish.
p + i is pointing to an address on your memory, the same as &(p[i]). You can't change the address of the memory, so that's why the compiler is saying the expression is not assignable.
If you want to save an int on that address you need to use *(p+i) = b.
But if you want to save the address of an int you need an array which holds int*, so you need to declare p as an int** and allocate its memory with the sizeof(int*). That way your code would look like this:
#include <stdio.h>
#include <stdlib.h>
int main() {
int **p;
int b = 15;
p = (int**)malloc(sizeof(int*) * 10);
for (int i = 0; i < 5; i++) {
*(p + i) = &b;
}
}

C qsort() with dynamic n by 2 multi-dimensional array

First, I defined a dynamic array with 2 columns and 10 row. The integer number is set to 10 here just for example.
int** array;
int number = 10;
array = malloc(number * sizeof(int*));
for (i = 0; i < number; i++)
array[i] = malloc(2 * sizeof(int));
Then I try to use qsort() on it.
qsort( array, number, sizeof array[0], compare );
This is my compare function. It sorts by the integer values in the first column, then sorts by the second column while preserving the order in the first column. E.g. "0 2, 1 7, 0 1" will become "0 1, 0 2, 1 7".
int compare ( const void *pa, const void *pb ) {
int (*a)[1] = pa;
int (*b)[1] = pb;
if ( (a[0][0] < b[0][0]) || (a[0][0] == b[0][0])&&(a[1][0] < b[1][0]) ) return -1;
if ( (a[0][0] > b[0][0]) || (a[0][0] == b[0][0])&&(a[1][0] > b[1][0]) ) return +1;
return 0;
}
Question
This worked with a static array. I know it doesn't work now because I have a dynamic array, which is an array of pointers.
How can I adapt this code to work with the dynamically created multi-dimensional array?
sample code
#include <stdio.h>
#include <stdlib.h>
int compare ( const void *pa, const void *pb ) {
const int *a = *(const int **)pa;
const int *b = *(const int **)pb;
if(a[0] == b[0])
return a[1] - b[1];
else
return a[0] - b[0];
}
/*
#define NUMCMP(x,y) (((x) < (y)) ? -1 : ((x) > (y)) ? 1 : 0)
int compare ( const void *pa, const void *pb ) {
const int (*a)[2] = *(const int (**)[2])pa;
const int (*b)[2] = *(const int (**)[2])pb;
int tmp;
if((tmp=NUMCMP((*a)[0], (*b)[0]))==0)
return NUMCMP((*a)[1], (*b)[1]);
else
return tmp;
}
*/
int main(void){
int **array;
int number = 10;
int i;
array = malloc(number * sizeof(int*));
for (i = 0; i < number; i++){
array[i] = malloc(2 * sizeof(int));
array[i][0] = rand()%20;
array[i][1] = rand()%20;
}
for(i = 0;i < number;++i)
printf("%2d, %2d\n", array[i][0], array[i][1]);
printf("\n");
qsort(array, number, sizeof array[0], compare);
for(i = 0;i < number;++i)
printf("%2d, %2d\n", array[i][0], array[i][1]);
return 0;
}
what *(const int **)pa
array = {(int *), (int *), (int *), ... , (int *) }
qsort need each element address for element (for swap, etc. Because the size and number and start address of the element since only the given information).
E.g &(int *), &(int *)
so (int **) pass to function compare.
call compare(int **, int **) &(int*) meant at arg int**
compare function prototypeis cmp(const void*, const void*)
cast (const int**)pa is cast to passed original pointer.
*((const int **)pa) is dereference original element pointer(int*)
Since you now have an array of pointers, the arguments to your comparison function are going to be pointers to pointers. Use them like this:
int *const *a = pa;
int *const *b = pb;
Now you have a and b as two pointers into the array you're sorting. Each one points to a single element that the sort function is asking you to examine. You can access these elements as *a and *b or a[0] and b[0] but should not ever use a[1] or b[1]. If the sort function asks you to compare the first element in the array (*a) and the fifth element in the array (*b), a[1] and b[1] are the second and sixth elements of the array - completely irrelevant to the comparison you're supposed to be doing.
After the first level of dereferencing, you're allowed to do whatever you need to do to examine the elements being compared. Since your array elements are themselves pointers to arrays (of 2 int each), the ints can be accessed as a[0][0] a[0][1] b[0][0] b[0][1]. Notice this is the opposite order from your a[1][0] and b[1][0].
Writing them as (*a)[0] would provide a reminder that the first level of indirection is a "single-element-access-only" pointer. I'm undecided on whether this makes the whole thing clearer.
I came across this thread in search of a ditto problem of mine, and I lastly end-up doing the below thing.
static int compareMatrixElements(const void *p1, const void *p2)
{
return ((*(int const *) p1) - (*(int const *) p2));
}
void sortMatrix(int** matrix, int r, int c)
{
int sort_matrix[r][c];
for(int i = 0; i < r; i++) {
memcpy(sort_matrix[i], matrix[i], c * sizeof(int));
}
qsort(sort_matrix, r*c, sizeof(int), compareMatrixElements);
for(int i = 0; i < r; i++) {
memcpy(matrix[i], sort_matrix[i], c * sizeof(int));
}
}
In the above code of mine I used qsort API directly, one can use this api or any other sort algo on a contiguous memory, but what If you are having a matrix whose rows are pointer to the memory of its columns (like in my case as well as described in the question of this thread). Hence I copied such matrix into a contiguous memory, ran sort on that contiguous memory and copied back the sorted elements to the matrix.
The above solution worked for me, I thought it might be helpful others so I posted it, suggest any improvement for the same.
const int *a = *(const int **)pa;
const int *b = *(const int **)pb;
#BLUEPIXY, this is not correct.
Just enough
const int *a = pa;
const int *b = pb;
becouse pa is const void * (array[0]) and it very well cast to const int *
const int (*a)[2] = *(const int (**)[2])pa;
const int (*b)[2] = *(const int (**)[2])pb;
#BLUEPIXY, this is not correct. Just enough
const int (*a)[2] = (int(*)[])pa;
const int (*b)[2] = (int(*)[])pb;
sizeof array[0] will be "2 * sizeof(int)", for this static array.
int array[10][2];
sizeof array[0] will be "sizeof(int*)", for this pointer-to-pointer.
sizeof array[0][0] will be "sizeof(int)", for this pointer-to-pointer.
int **array;
So, First thing is you cannot use "qsort( array, number, sizeof array[0], compare );" in case of pointer-to-pointer implementation.

Resources