Dynamic allocation example in C - c

What is going on with adress and pointer types.
Can we dealocate the momory in the main function.
int *read(int *n) {
int i, *niz;
do {
printf("n=");
scanf("%d", n);
} while (*n < 1);
niz = (int *)malloc(*n * sizeof(int));
for (i = 0; i < *n; i++) {
printf("%d. broj: ", i + 1);
scanf("%d", niz + i);
}
return niz;
}
int main() {
int i, n, *niz;
niz = read(&n);
printf("Niz:");
for (i = 0; i < n; i++)
printf(" %d", niz[i]);
free(niz);
return 0;
}

I don't understand why do we need a function pointer (*read), and why
do we need the pointer in the read function while using n?
To make it clear you may rewrite the function declaration
int *read(int *n) {
the following way
int * ( read(int *n) ){
That is it is a function that has one parameter with the name n of the type int * and the return type int *.
In main the variable n declared like
int i, n, *niz;
is passed to the function read by reference through a pointer to it
niz = read(&n);
because we want that the variable would get a value assigned in the function. So dereferencing the pointer the function will have a direct access to the original variable n declared in main and can change its value.
This value assigned in the function read to the original variable n declared in main through a pointer to it is used in main in this for loop
for (i = 0; i < n; i++)
printf(" %d", niz[i]);
Otherwise if the function would be declared like
int * ( read(int n) ){
and called like
niz = read(n);
then the function would deal with a copy of the value of the variable n declared in main. Changing the copy of the value of the variable n within the function leaves the value of the original variable n declared in main unchanged. It is the copy of the value that would be changed not the original variable itself.
Pay attention to that the returned pointer from the function points to a dynamically allocated memory. So using the pointer in main you can free the allocated memory within the function.

Related

dynamic arrays int printing problem - maybe not a valid memory cell

#include <stdio.h>
#include <stdlib.h>
int find_lenght(int *arrr){
int i = 0;
while(arrr[i] != '\0'){
i++;
}
return i;
}
void init_array(int *arrr){
arrr=(int*)malloc(1*sizeof(int));
printf("New element:");
int lenght = find_lenght(arrr);
scanf("%d", &arrr[lenght]);
printf("Lenght = %d\n",lenght);
printf("Array elements are:\n");
for(int i = 0; i <= lenght; i++) {
printf("%d,", arrr[i]);
}
}
void print_array(int *arrr){
printf("Array elements are:\n");
int lenght = find_lenght(arrr);
for(int i = 0; i == lenght; i++) {
printf("%d,", arrr[i]);
}
}
int main() {
int *arr = NULL;
init_array(arr);
print_array(arr);
}
I don't know what am i missing here.
My point is to fill in and then print dynamic array
Also my taught is it's not filling the way it should, so it hasn't anything to print.
Your arr pointer in main is never assigned because your init_array assign the address of the allocated memory (the return value of malloc) to the input parameter arrr, which is, a local variable.
You have mainly two solutions to properly achieve what you want to do. The first one (the better one in my point of view), by making your init_array returning the allocated memory address to be assigned:
int* init_array()
{
int* retval = (int*)malloc(1*sizeof(int));
// ...
return retval;
}
int main()
{
int *arr = init_array(); //< assign arr with returned value
}
Another way is to make your init_array function taking a pointer to a pointer, so the function can assign this pointer:
void init_array(int** arrr)
{
(*arrr) = (int*)malloc(1*sizeof(int));
// ...
}
int main()
{
int* arr = NULL;
init_array(&arr); //< pass reference to arr
}
You need to pass the pointer to pointer to int to change passed pointer. Your for loop is invalid in print function. You need also to set the sentinel value yourself.
size_t find_length(const int *arrr)
{
size_t i = 0;
if(arrr)
while(arrr[i]) i++;
return i;
}
void add_element(int **arrr, int element)
{
size_t length = find_length(*arrr);
int *tmp = realloc(*arrr, (length + 2) * sizeof(**arrr));
if(tmp)
{
*arrr = tmp;
(*arrr)[length] = element;
(*arrr)[length + 1] = 0;
}
}
void print_array(const int *arrr)
{
printf("Array elements are:\n");
size_t lenght = find_length(arrr);
for(size_t i = 0; i < lenght; i++)
{
printf("arrr[%zu] = %d\n", i, arrr[i]);
}
}
int main(void) {
int *arr = NULL;
add_element(&arr, 5);
add_element(&arr, 15);
add_element(&arr, 25);
add_element(&arr, 35);
print_array(arr);
}
https://godbolt.org/z/drKej3KT5
the array on your main function is still NULL. the better way to do is just call the print_array() function after you initialize it. you just simply put print_array(arrr) inside init_array() and after the for loop statement.
The line
int lenght = find_lenght(arrr);
may invoke undefined behavior, because find_length requires its argument to be a pointer to the first element of a null-terminated int array. However, the content of the memory pointed to by arrr is indeterminate, because it has not been initialized. Therefore, it is not guaranteed to be null-terminated.

Returning a pointer to an array

I have written a function that creates a data table, initializes it's elements to 0 and returns a pointer to the data table. However it doesn't work. Could someone explain it to me so I understand where my problem is.
This is my code:
#include <stdio.h>
// Here I create the data table and initialize it's elements
int* tabinit(int size) {
int tab[size];
for (int i = 0; i < size; i++)
tab[i] = 0;
return tab;
}
int main() {
int* t = tabinit(10);
for (int i = 0; i < 10; i++)
printf("%d ", t[i]);
printf("\n");
return 0;
}
When a function terminates, then all its automatic variables go out of scope.
tab is an automatic variable in this case, and will go out of scope when the function terminates. Now you are returning a pointer to a local array, so when the array goes out of scope, you will find yourself with a dangling pointer.
Didn't your compiler warned you about this? I got, in GCC, this warning:
warning: function returns address of local variable [-Wreturn-local-addr]
return tab;
^~~
First make sure that you really want for practicing to create the array in the function. If not, then you don't need to, you could just create in main, and then pass it to the function.
But, if you want to practice, then you need to dynamically allocate the array, if you really want it to stay alive after the function terminates. In that case, the array will free its memory, only when you tell it to (so never forget to free).
Example:
#include <stdio.h>
#include <stdlib.h>
int* tabinit(int size) {
int *tab = malloc(size * sizeof(int));
for (int i = 0; i < size; i++)
tab[i] = 0;
return tab;
}
int main() {
int* t = tabinit(10);
for (int i = 0; i < 10; i++)
printf("%d ", t[i]);
printf("\n");
// do NOT forget to free
free(t);
return 0;
}
Output:
0 0 0 0 0 0 0 0 0 0
PS: When you get more familiar with malloc(), I suggest you read this: Should I check if malloc() was successful?
You should never return a pointer to a local object. After the function finishes, the local object gets deallocated and you're left with a dangling pointer (pointer that doesn't point to valid memory).
One way to do this would be to create your object in main and pass it into your function for init, like so:
void tabinit(int* tab, int size) {
for (int i = 0; i < size; i++)
tab[i] = 0;
}
int main() {
int t[10];
tabinit(t, 10);
for (int i = 0; i < 10; i++)
printf("%d ", t[i]);
printf("\n");
return 0;
}
Here:
// Here I create the data table and initialize it's elements
int* tabinit(int size) {
int tab[size]; // <------- here
for (int i = 0; i < size; i++)
tab[i] = 0;
return tab; // <------- also here
}
As gsamaras said, the content pointed by tab become out of scope after the function call. You can change this line:
int tab[size];
By:
int *tab;
tab = malloc(size * sizeof(int));
The content will be dynamically allocated, and then will remains after exiting from the function. However, you'll have to free it manually (free(t)) afterwards or it will be reserved until the end of the program (which could occur a memory leak).

Seg faulting when accessing dynamically allocated memory in main (allocated in function), C [duplicate]

This question already has an answer here:
Dynamic memory access only works inside function
(1 answer)
Closed 4 years ago.
So what I'm trying to do is create a two dimensional array as a matrix using pointers. I put a double pointer into my CreateMatrix function, along with rows/cols, and I dynamically allocate the arrays into them. I filled 10 into all of them to test, and it shows they're all allocated. However in main, when I try to access an arbitrary value of the 2D array, I segfault. Regardless of if it occurs in a function, shouldn't dynamically allocated be stored onto the heap, thus it should work?
void CreateMatrix(int ** matrix, int row, int col){
int i, j;
matrix = (int**)malloc(row* sizeof(int*));
for (i = 0; i < row; i++) {
matrix[i] = (int*)malloc(col* sizeof(int));
for (j = 0 ; j < col; j++) {
matrix[i][j] = 10;
printf("i: %d, j: %d\n", i,j);
printf("%d",matrix[i][j]);
}
}
}
In main:
int ** matrix1;
int m1row, m1col = 5;
CreateMatrix(matrix1, m1row, m1col);
fprintf(stdout,"Testing if got out");
fflush(stdout);
printf("This should be 10 : %d",matrix1[0][0]); //definitely segfaults here
Also, a side question; I was told that when passing 'by reference' in C, not only do you need pointers in the function definition, but an ampersand on the variable for the function call. Something like if I want to pass the matrix a by reference : CreateMatrix(&a, b, c); instead of CreateMatrix(a, b, c);. If I use an &, I get an incompatibility error saying the argument is a triple pointer,when I need a double pointer. (Which in theory makes sense, since you're passing the location of the double pointer). Then is & only used for non pointer variables?
matrix in CreateMatrix is a copy of the pointer matrix1. When you assign to matrix in that function, matrix1 in main is unaffected.
int** CreateMatrix(int row, int col){
int i, j;
int **matrix = (int**)malloc(row* sizeof(int*));
for (i = 0; i < row; i++) {
matrix[i] = (int*)malloc(col* sizeof(int));
for (j = 0 ; j < col; j++) {
matrix[i][j] = 10;
printf("i: %d, j: %d\n", i,j);
printf("%d",matrix[i][j]);
}
}
return matrix;
}
int main() {
// ...
int **matrix1 = CreateMatrix(row, col);
// ...
return 0;
}
If you want to keep a void return type, then take a pointer to a int** pointer and pass address of that pointer in main.
void CreateMatrix(int ***matrix, int row, int col){
int i, j;
*matrix = (int**)malloc(row* sizeof(int*));
for (i = 0; i < row; i++) {
(*matrix)[i] = (int*)malloc(col* sizeof(int));
for (j = 0 ; j < col; j++) {
(*matrix)[i][j] = 10;
printf("i: %d, j: %d\n", i,j);
printf("%d", (*matrix)[i][j]);
}
}
}
int main() {
int **matrix1;
CreateMatrix(&matrix1, 10, 10);
printf("This should be 10 : %d",matrix1[0][0]);
return 0;
}
Variables reside in memory. A pointer store the memory address of a variable with a specific type. The ampersand & gives the memory address of a variable.
Here, & returns the address to the int** pointer, matrix1, which is then passed to CreateMatrix. Notice that the argument matrix of CreateMatrix has been changed to be a pointer to a int** pointer.
Dereferencing a pointer gets you the object that the pointer is pointing to. Here, when we assign to *matrix, what we are doing is essentially using the memory address of matrix1 (which was passed via matrix) to get matrix1 in CreateMatrix, and assign the start of the block of memory allocated by malloc to matrix1.
In your original code, matrix in CreateMatrix is a copy of the value of the pointer matrix1 (probably garbage because it is not initialized).
When you assign to matrix, you are not modifying matrix1, you are merely modifying a local variable.
There are few issues with the code you mention. firstly m1row value is not defined, so it may consider some garbage value, so assign the value like
int m1row = 5, m1col = 5;
Secondly, you are passing matrix1 to CreateMatrix() function & creating dynamic array in the CreateMatrix() function but not returning the dynamically allocated address to main() function which causes segmentation fault when accessing
printf("This should be 10 : %d",matrix1[0][0]);
Also casting the malloc() result is not required as pointed here.
Sample Code
int** CreateMatrix(int row, int col){
int i, j;
int **matrix = malloc(row* sizeof(*matrix)); /* no need to cast the malloc result */
for (i = 0; i < row; i++) {
matrix[i] = malloc(col* sizeof(**matrix));
for (j = 0 ; j < col; j++) {
matrix[i][j] = 10;
#if 0
printf("i: %d, j: %d\n", i,j);
printf("%d \n",matrix[i][j]);
#endif
}
}
return matrix; /* return the dynamic array */
}
int main(void){
int m1row = 5, m1col = 5;
int **matrix1 = CreateMatrix(m1row, m1col);
printf("\nThis should be 10 : %d\n",matrix1[0][0]);
return 0;
}
The matrix argument of the CreateMatrix function is allocated on the stack of that function, which means that it is local to it. When you use malloc to allocate memory, the local variable matrix is pointing to that memory. The matrix variable in main does not get updated by that, this is because arguments are by default passed by value.
In order to make it work, you would have to pass the address of the matrix variable (using the & operator) from main to CreateMatrix, i.e. its signature should have int *** matrix. Inside the function you would have to update it by using the * operator. Like so:
*matrix = (int **) malloc (row * sizeof(int *))
Another option is instead to return the allocated memory from the CreateMatrix function.

How to return an array from a function with pointers

i'm trying to figure out how to return an array from a function in the main().
I'm using C language.
Here is my code.
#include <stdio.h>
int *initArray(int n){
int i;
int *array[n];
for(i = 0; i < n; i++){
array[i] = i*2;
}
return array;
}
main(){
int i, n = 5;
int *array[n];
array[n] = initArray(n);
printf("Here is the array: ");
for(i = 0; i < n; i++){
printf("%d ", array[i]);
}
printf("\n\n");
}
And this is the errors the console gives me:
2.c: In function ‘initArray’:
2.c:8:13: warning: assignment makes pointer from integer without a cast [enabled by default]
array[i] = i*2;
^
2.c:11:3: warning: return from incompatible pointer type [enabled by default]
return array;
^
2.c:11:3: warning: function returns address of local variable [-Wreturn-local-addr]
2.c: In function ‘main’:
2.c:23:4: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’ [-Wformat=]
printf("%d ", array[i]);
^
It's impossible!
I hate being a noob :(
If you could help, with explanations, I would appreciate! :D
Edit: iharob's answer is better than mine. Check his answer first.
Edit #2: I'm going to try to explain why your code is wrong
Consider the 2nd line of main() in your question:
int *array[n];
Let's try to read it backwards.
[n]
says we have an array that contains n elements. We don't know what type those elements are and what the name of the array is, but we know we have an array of size n.
array[n]
says your array is called array.
* array[n]
says you have a pointer to an array. The array that is being pointed to is called 'array' and has a size of n.
int * array[n];
says you have a pointer to an integer array called 'array' of size n.
At this point, you're 3/4 way to making a 2d array, since 2d arrays consist of a list of pointers to arrays. You don't want that.
Instead, what you need is:
int * array;
At this point, we need to examine your function, initArray:
int *initArray(int n){
int i;
int *array[n];
for(i = 0; i < n; i++){
array[i] = i*2;
}
return array;
}
The second line of initArray has the same mistake as the second line of main. Make it
int * array;
Now, here comes the part that's harder to explain.
int * array;
doesn't allocate space for an array. At this point, it's a humble pointer. So, how do we allocate space for an array? We use malloc()
int * array = malloc(sizeof(int));
allocates space for only one integer value. At this point, it's more a variable than an array:
[0]
int * array = malloc(sizeof(int) * n);
allocates space for n integer variables, making it an array:
e.g. n = 5:
[0][0][0][0][0]
Note:The values in the real array are probably garbage values, because malloc doesn't zero out the memory, unlike calloc. The 0s are there for simplicity.
However, malloc doesnt always work, which is why you need to check it's return value:
(malloc will make array = NULL if it isn't successful)
if (array == NULL)
return NULL;
You then need to check the value of initArray.
#include <stdio.h>
#include <stdlib.h>
int *initArray(int n){
int i;
int *array = malloc(sizeof(int) * n);
if (array == NULL)
return NULL;
for(i = 0; i < n; i++){
array[i] = i*2;
}
return array;
}
int main(){
int i, n = 5;
int *array = initArray(n);
if (array == NULL)
return 1;
printf("Here is the array: ");
for(i = 0; i < n; i++){
printf("%d ", array[i]);
}
free(array);
printf("\n\n");
return 0;
}
You can't just return an array like that. You need to make a dynamically allocated array in order to do that. Also, why did you use a 2d array anyway?
int array[5];
is basically (not completely) the same as:
int * array = malloc(sizeof(int) * 5);
The latter is a bit more flexible in that you can resize the memory that was allocated with malloc and you can return pointers from functions, like what the code I posted does.
Beware, though, because dynamic memory allocation is something you don't wanna get into if you're not ready for tons of pain and debugging :)
Also, free() anything that has been malloc'd after you're done using it and you should always check the return value for malloc() before using a pointer that has been allocated with it.
Thanks to iharob for reminding me to include this in the answer
Do you want to initialize the array? You can try it like this.
#include <stdio.h>
void initArray(int *p,int n)
{
int i;
for(i = 0; i < n; i++)
{
*(p+i) = i*2;
}
}
void main(void)
{
int i, n = 5;
int array[n];
initArray(array,n);
printf("Here is the array: ");
for(i = 0; i < n; i++)
{
printf("%d ", array[i]);
}
printf("\n\n");
}
If you don't want to get in trouble learning malloc and dynamic memory allocation you can try this
#include <stdio.h>
void initArray(int n, int array[n]) {
int i;
for (i = 0 ; i < n ; i++) {
array[i] = i * 2;
}
}
int main() { /* main should return int */
int i, n = 5;
int array[n];
initArray(n, array);
printf("Here is the array: ");
for(i = 0 ; i < n ; i++) {
printf("%d ", array[i]);
}
printf("\n\n");
return 0;
}
as you see, you don't need to return the array, if you declare it in main(), and pass it to the function you can just modify the values directly in the function.
If you want to use pointers, then
#include <stdio.h>
int *initArray(int n) {
int i;
int *array;
array = malloc(n * sizeof(*array));
if (array == NULL) /* you should always check malloc success */
return NULL;
for (i = 0 ; i < n ; i++) {
array[i] = i * 2;
}
return array;
}
int main() { /* main should return int */
int i, n = 5;
int *array;
array = initArray(n);
if (array == NULL) /* if null is returned, you can't dereference the pointer */
return -1;
printf("Here is the array: ");
for(i = 0 ; i < n ; i++) {
printf("%d ", array[i]);
}
free(array); /* you sould free the malloced pointer or you will have a memory leak */
printf("\n\n");
return 0;
}

Print a square matrix using pointers

I've browsed to previously answered questions regarding pointers and matrices, but in these cases the matrices were seen as pointers to pointers. However, I am trying to create a function which read a matrix using a simple pointer and another function which prints it.
This is my code, the read functions seems to work properly, but the program crashes at the printing part. If I remove the "*" from the printf statement the program works(i.e. it prints numbers from 4 to 4- I suppose this is alright, since an int is stored on 4 bytes).
void readm(int *p,int n)
{
p=(int *)malloc(sizeof(int)*n*n);
for(int i=0;i<n*n;i++)
scanf("%d",p+i);
}
void printm(int *p,int n)
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
printf("%d ",*(p+(i*n)+j));
printf("\n");
}
}
In the readm function you have a problem with this line:
p=(int *)malloc(sizeof(int)*n*n);
Here you assign only to your local copy of the pointer. The variable you use when calling readm will not be changed.
You need to pass the pointer "by reference":
void readm(int **p,int n) /* Note pointer-to-pointer for `p` */
{
*p=malloc(sizeof(int)*n*n); /* Note pointer-dereference of `p` */
for(int i=0;i<n*n;i++)
scanf("%d",*p+i); /* Note pointer-dereference of `p` */
}
You then have to call the function using the address-of operator:
int *p;
readm(&p, X); /* Note use of address-of operator */
A pointer to a 1D array is defined as such:
int *p1dArr;
A pointer to a 2D array is defined as such:
int **p2dArr;
You're using a 1D array as though it's a 2D array. This is probably the source of your troubles. Change you function definitions to the following:
void readm(int **p, int row, int col)
{
p = malloc(row * sizeof(*p));
for(int r = 0; r < row; r++)
p[r] = malloc(col * sizeof(**p))
for(int r = 0; r < row; r++)
for(int c = 0; c < col; c++)
scanf("%d", &p[r][c]);
}
void printm(int **p, int row, int col)
{
for(int r = 0; r < row; r++)
{
for(int c = 0; c < col; c++)
printf("%d ", p[r][c]);
printf("\n");
}
}
The problem is that the calling code that calls function readm doesn't know that inside the function variable p (defined as a parameter of the function) got a new value. p is a local variable of the function and its life ends after exiting the function.
You should define the function the following way
void readm( int **p, int n )
{
*p = (int *)malloc( sizeof(int ) * n * n);
for ( int i=0; i<n*n; i++ ) scanf( "%d", *p+i );
}
and call it as
int *p;
readm( &p, n );
As for function printmthen there is no any need to redeclare it as
void printm( int **p, int n )
because it does not change the pointer. The only thing I would change is adding qualifier const
void printm( const int *p, int n );

Resources