free() in dynamic memory - c

Do I use correctly free() in the code below? Is it a memory leak? Is it a problem use free() in the main part and not in the function? If yes there is a method to free in the function and not in main?
This code copy an array in another one.
int *copy(const int *arr,int n);
int main(){
int *p_arr1,*p_arr2;
int n,i;
printf("Insert size of array: ");
scanf("%d",&n);
p_arr1 = calloc(n,sizeof(int));
for(i=0;i<n;i++){
printf("Insert element %d of the array: ",i+1);
scanf("%d",p_arr1+i);
}
p_arr2 = copy(p_arr1,n);
for(i=0;i<n;i++){
printf("%d ",*p_arr2);
p_arr2++;
}
free(p_arr1);
free(p_arr2);
return 0;
}
int *copy(const int *arr,int n){
int i;
int *new;
new = calloc(n, sizeof(int));
for(i=0;i<n;i++){
new[i] += arr[i];
}
return new;
}

As long as you have the pointer returned by malloc (or in your case calloc) you can pass it to free when and wherever you want, it doesn't have to be in the same function.
However, after the loop where you print the contents of p_arr2, you no longer have the pointer returned by calloc inside the function, because you modify the pointer in the loop.
You need to use a temporary pointer variable for the loop:
int *p_arr2_tmp = p_arr2;
for (size_t i = 0; i < n; ++i)
{
printf("%d ", *p_arr2_tmp);
++p_arr2_tmp;
}
// Now we can free the memory pointed to by the original p_arr2 pointer
free(p_arr2);
Or you could use simple array indexing instead:
for (size_t i = 0; i < n; ++i)
{
printf("%d ", p_arr2[i]);
}
// The pointer p_arr2 wasn't modified, so it can be passed to free
free(p_arr2);

In this loop
for(i=0;i<n;i++){
printf("%d ",*p_arr2);
p_arr2++;
}
the value of the pointer p_arr2 is being changed, So using the changed pointer in a call of free results in undefined behavior.
You should write
for(i=0;i<n;i++){
printf("%d ", p_arr2[i] );
}
Also it is unclear why you are using the compound operator += in the function instead of the operator =.
new[i] += arr[i];
The function can be defined the following way
int * copy( const int *arr, size_t n )
{
int *new_arr = malloc( n * sizeof( int ) );
if ( new_arr != NULL )
{
memcpy( new_arr, arr, n * sizeof( int ) );
}
return new_arr;
}
If you want to use a pointer in the loop that outputs the newly created array then it can look the following way
for ( const int *p = p_arr2; p != p_arr2 + n; ++p )
{
printf( "%d ",*p );
}
putchar( '\n' );
If the aim is to write a program that uses only pointers and excludes using of the subscript operator and indices then your program can look the following way
#include <stdio.h>
#include <stdlib.h>
int * copy( const int *arr, size_t n )
{
int *new_arr = malloc( n * sizeof( int ) );
if ( new_arr != NULL )
{
for ( int *p = new_arr; p != new_arr + n; ++p )
{
*p = *arr++;
}
}
return new_arr;
}
int main(void)
{
size_t n;
printf( "Insert size of array: " );
scanf( "%zu", &n );
int *p_arr1 = calloc( n, sizeof( int ) );
for ( int *p = p_arr1; p != p_arr1 + n; ++p )
{
printf( "Insert element %d of the array: ", ( int )( p - p_arr1 + 1 ) );
scanf( "%d", p );
}
int *p_arr2 = copy( p_arr1, n );
if ( p_arr2 != NULL )
{
for ( const int *p = p_arr2; p != p_arr2 + n; ++p )
{
printf( "%d ",*p );
}
putchar( '\n' );
}
free( p_arr2 );
free( p_arr1 );
return 0;
}
The program output might look like
Insert size of array: 10
Insert element 1 of the array: 0
Insert element 2 of the array: 1
Insert element 3 of the array: 2
Insert element 4 of the array: 3
Insert element 5 of the array: 4
Insert element 6 of the array: 5
Insert element 7 of the array: 6
Insert element 8 of the array: 7
Insert element 9 of the array: 8
Insert element 10 of the array: 9
0 1 2 3 4 5 6 7 8 9

Related

C: copying array in function by using pointers gave unusual result, why did it half work?

So I don't want to make a function for every data type, I would like to be able to just use pointers to fix the problem. Tried the idea with a function for copying an array. I didn't get the result i expected or wanted, even if it had just gone entirely wrong with the new_arr not changing at all i would be ok this isn't it. but it gave me hope.
void *copy_array(const void *arr[], const void *new_arr[], size_t arr_len, size_t type_size) {
for (int i = 0; i < arr_len ; ++i) {
*(new_arr + (i * type_size)) = *(arr + (i * type_size));
}
}
void print_int_array(int * array, int length) {
for (int i = 0; i < length; ++i) {
printf("\nelement %d = %d", i, array[i]);
}
}
int main() {
int arr[ARRAY_LENGTH] = {12, 3,4};
int new_arr[ARRAY_LENGTH] = {0, 0, 0};
print_int_array(arr, ARRAY_LENGTH);
print_int_array(new_arr, ARRAY_LENGTH);
copy_array(&arr, &new_arr, ARRAY_LENGTH, sizeof(new_arr[0]));
print_int_array(arr, ARRAY_LENGTH);
print_int_array(new_arr, ARRAY_LENGTH);
return 0;
}
Console returns this for some reason, it gets the 12 and the 3 by why not the 4?
element 0 = 12
element 1 = 3
element 2 = 4
element 0 = 0
element 1 = 0
element 2 = 0
element 0 = 12
element 1 = 3
element 2 = 4
element 0 = 12
element 1 = 3
element 2 = 0
You declared a function
void *copy_array(const void *arr[], const void *new_arr[], size_t arr_len, size_t type_size) {
where the both first parameters have the qualifier const. So the function declaration is incorrect.
Instead it would be better to declare the first parameter of the function print_int_array with the qualifier const and the second parameter as having the type size_t
void print_int_array( const int * array, size_t length) {
On the other hand, the expressions
*(new_arr + (i * type_size))
and
*(arr + (i * type_size))
have pointer types. Their sizes can be greater than the size of an object of the type int. For example sizeof( void * ) can be equal to 8 while sizeof( int ) can be equal to 4.
Thus the function can invoke undefined behavior.
Apart from that the function has a non-void return type but returns nothing.
Also there is no great sense to call the function passing pointers to arrays like
copy_array(&arr, &new_arr, ARRAY_LENGTH, sizeof(new_arr[0]));
where each expression has the type int( * )[3].
The function can be defined the following way as shown in the demonstration program below.
#include <stdio.h>
#include <string.h>
void copy_array( void *new_arr, const void *arr, size_t arr_len, size_t type_size )
{
for (size_t i = 0; i < arr_len; i++)
{
memcpy( new_arr, arr, type_size );
new_arr = ( char * )new_arr + type_size;
arr = ( const char * )arr + type_size;
}
}
int main( void )
{
enum { ARRAY_LENGTH = 3 };
int arr[ARRAY_LENGTH] = { 12, 3,4 };
int new_arr[ARRAY_LENGTH] = { 0, 0, 0 };
printf( "arr : " );
for (size_t i = 0; i < ARRAY_LENGTH; i++)
{
printf( "%d ", arr[i] );
}
putchar( '\n' );
printf( "new_arr: " );
for (size_t i = 0; i < ARRAY_LENGTH; i++)
{
printf( "%d ", new_arr[i] );
}
putchar( '\n' );
putchar( '\n' );
copy_array( new_arr, arr, ARRAY_LENGTH, sizeof( int ) );
printf( "arr : " );
for (size_t i = 0; i < ARRAY_LENGTH; i++)
{
printf( "%d ", arr[i] );
}
putchar( '\n' );
printf( "new_arr: " );
for (size_t i = 0; i < ARRAY_LENGTH; i++)
{
printf( "%d ", new_arr[i] );
}
putchar( '\n' );
}
The program output is
arr : 12 3 4
new_arr: 0 0 0
arr : 12 3 4
new_arr: 12 3 4
So this is what i wanted to do which is basicly memcpy. The arrays get converted to char arrays which is only 1 byte, so every byte gets copied from the size of the original array.
void copy_array(void *arr, void *new_arr, size_t arr_size) {
char *char_new_arr = (char *) new_arr;
char *char_arr = (char *) arr;
for (int i = 0; i < arr_size; ++i) {
char_new_arr[i] = char_arr[i];
}
}

Weird issue when making an array of random ints in C

I am currently learning C and I need to write a function to create an array of random integers. I've hit a problem where after creating I try to print and it the first 8 numbers correctly but the rest don't.
int* create(int n) {
int* array = malloc(n);
if (!array) return NULL;
srand(time(NULL));
for (int i = 0; i < n; i++) {
array[i] = rand() % 100 + 1;
printf("num: %i\n", array[i]);
}
for (int i = 0; i < n; i++) {
printf("%i\n", array[i]);
}
return array;
}
Here is my output for this:
num: 39
num: 2
num: 15
num: 74
num: 80
num: 29
num: 14
num: 16
num: 8
num: 11
num: 2
39
2
15
74
80
29
14
16
973747761
909588276
2614
This memory allocation
int* array = malloc(n);
allocates not enough memory for an array with n elements of the type int, You have to write
int* array = malloc( n * sizeof( int ) );
Also the parameter should have unsigned integer type. Otherwise the user can pass a negative integer that will result in undefined behavior.
It is better to declare the parameter as having the type size_t. It is the type of the parameter of the function malloc.
And the function should do one thing: allocate and initialize an array. It is the caller of the function that will decide whether to output the array provided that the function did not return a null pointer.
So the function can look like
int * create( size_t n )
{
const int MAX_VALUE = 100;
int *array = malloc( n * sizeof( int ) );
if ( array != NULL )
{
srand( ( unsigned int )time( NULL ) );
for ( size_t i = 0; i < n; i++ )
{
array[i] = rand() % MAX_VALUE + 1;
}
}
return array;
}
Here is a demonstrative program.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int * create( size_t n )
{
const int MAX_VALUE = 100;
int *array = malloc( n * sizeof( int ) );
if ( array != NULL )
{
srand( ( unsigned int )time( NULL ) );
for ( size_t i = 0; i < n; i++ )
{
array[i] = rand() % MAX_VALUE + 1;
}
}
return array;
}
int main(void)
{
size_t n = 0;
printf( "Enter the size of an array: " );
scanf( "%zu", &n );
int *array = create( n );
if ( array != NULL )
{
for ( size_t i = 0; i < n; i++ )
{
printf( "%d ", array[i] );
}
putchar( '\n' );
}
free( array );
return 0;
}
Its output might look like
Enter the size of an array: 10
75 36 30 75 53 49 42 52 61 9
Though it is better to declare the function such a way that the user can determine the maximum value himself. That is the function can look like
int * create( size_t n, int max_value )
{
int *array = malloc( n * sizeof( int ) );
if ( array != NULL )
{
srand( ( unsigned int )time( NULL ) );
for ( size_t i = 0; i < n; i++ )
{
array[i] = rand() % max_value + 1;
}
}
return array;
}
Issues with your code:
malloc expects a size_t, you are directly giving an int. So you should technically do:
int *array = malloc(sizeof(int) * n);
This basically says that allocate n blocks of sizeof(int) bytes each.
What you are doing is allocating n bytes of data. The program is not guaranteed to run always and you are running out of bounds. If you were lucky you would get a Segmentation Fault in one of the runs.
You aren't allocating enough space. malloc(n) allocates n bytes. You need space for n ints! Use malloc(n * sizeof(int)), or more preferably: malloc(n * sizeof(*array)) (so you don't need to repeat the type) instead.

swapping last element problem in sorting C array

I am trying to write a sorting algorithm using a function that finds the adress of the minimum element in the array:
#include <stdio.h>
int * findMin(int * start,int * end) ///function to return the adress of the smallest array element
{
int *min = start;
int x;
int size = (end - start);
for(x=0; x<size; x++)
{
if (*(start+x)<*min)
min = (start+x);
}
return min;
}
But here in my sort algorithm, since the last element has nothing more to compare itself with, is mistakenly left as it is
void sort(int * start, int * end) ///funtion to sort the array in ascending order
{
int x,temp;
int size = (end - start);
for (x = 0; x <size; x++)
{
if ( *(start+x) > *findMin(start,end))
{
temp = *findMin(start+x,end);
*findMin(start+x,end) = *(start+x);
*(start+x) = temp;
}
}
}
int main()
{
int arr[10]={5,11,3,12,17,25,1,9,14,2};
sort(arr,&arr[9]);
for(int i=0;i<10;i++)
printf("%d ",arr[i]);
printf("\n");
}
How can I correct this?
The expression in this declaration
int size = (end - start);
does not give the exact size of the array. At least you should write
int size = end - start + 1;
However it is not a good idea to pass the pointer to the last element of the array instead of the pointer to the memory after the last element of the array. In this case you can specify an empty range as start is equal to end.
Also if the function accepts two pointers then there is no need to introduce intermediate variables used as indices in loops.
And this code snippet
temp = *findMin(start+x,end);
*findMin(start+x,end) = *(start+x);
*(start+x) = temp;
is very inefficient.
Here is a demonstrative program that shows how the functions can be implemented.
#include <stdio.h>
int * findMin( const int * start, const int * end ) ///function to return the adress of the smallest array element
{
const int *min = start;
if ( start != end )
{
while ( ++start != end )
{
if ( *start < *min ) min = start;
}
}
return ( int * )min;
}
void selection_sort( int *start, int *end ) ///funtion to sort the array in ascending order
{
for ( ; start != end; ++start )
{
int *min = findMin( start, end );
if ( min != start )
{
int tmp = *start;
*start = *min;
*min = tmp;
}
}
}
int main(void)
{
int arr[] = { 5, 11, 3, 12, 17, 25, 1, 9, 14, 2 };
const size_t N = sizeof( arr ) / sizeof( *arr );
for ( const int *p = arr; p != arr + N; ++p )
{
printf( "%d ", *p );
}
putchar( '\n' );
selection_sort( arr, arr + N );
for ( const int *p = arr; p != arr + N; ++p )
{
printf( "%d ", *p );
}
putchar( '\n' );
return 0;
}
The program output is
5 11 3 12 17 25 1 9 14 2
1 2 3 5 9 11 12 14 17 25
But here in my sort algorithm, since the last element has nothing more to compare itself with, is mistakenly left as it is
No, that's at best a misleading characterization. Your findMin() does not specifically compare array elements to their immediate successors, so the fact that *end has no successor is irrelevant. The problem is (in part) simply that you have an off-by-one error, resulting in never comparing *end with *min. That mistake would be harder to make and easier to recognize if you relied more directly on pointer arithmetic and comparisons:
int *findMin(int *start, int *end) {
int *min = start;
// The original code is equivalent to this variant:
// for (int *x = start; x < end; x++) {
// but this is what you need for an inclusive upper bound:
// for (int *x = start; x <= end; x++) {
// or, since initially min == start, this would be even better:
for (int *x = start + 1; x <= end; x++) {
if (*x < *min) {
min = x;
}
}
return min;
}

Error while printing 2D array using pointers

I want to print 2D array using pointers but in the printf statement it is showing invalid type argument: (See error in image below:)
#include<stdio.h>
void main()
{
int a[3][3]={1,2,3,4,5,6,7,8,9};
int i,j;
int *p;
p=&a;
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
printf("%d",*(p+i)+j);
printf("\n");
}
}
please help me out with this error.
For starters according to the C Standard the function main without parameters shall be declared like
int main( void )
This initializer of the pointer p is incorrect.
int *p;
p = &a;
because the pointer and its initializer have different pointer types and there is no implicit conversion between the types.
This expression
*( *( p + i ) + j)
is also invalid. The expression *( p + i ) yields an object of the type int not of a pointer type.
You can use the following approaches
#include <stdio.h>
int main(void)
{
enum { N = 3 };
int a[N][N] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
int *p = ( int * )a;
for ( size_t i = 0; i < N; i++ )
{
for ( size_t j = 0; j < N; j++ )
{
printf( "%d ", *( p + i * N + j ) );
}
putchar( '\n' );
}
putchar( '\n' );
for ( int ( *p )[N] = a; p != a + N; ++p )
{
for ( int *q = *p; q != *p + N; ++q )
{
printf( "%d ", *q );
}
putchar( '\n' );
}
putchar( '\n' );
return 0;
}
The program output is:
1 2 3
4 5 6
7 8 9
1 2 3
4 5 6
7 8 9
a is a pointer to a pointer but you're assigning it to a pointer. If you fix that, rest should work fine

Remove even numbers from array in c

Hello i'm trying for about 2 hours to create a program which will remove even numbers from a dinamyc allocated array(with malloc)in c.Can somebody help me with some tips or create the code.
p.s. this is my first topic here, so feel free to give me some tips about how to correctly post a qustion.
Let's assume that you already allocated dynamically an array of n elements and initialized it.
In this case the function that removes elements with even values can look the following way
size_t remove_even( int *a, size_t n )
{
size_t m = 0;
for ( size_t i = 0; i < n; i++ )
{
if ( a[i] % 2 != 0 )
{
if ( i != m ) a[m] = a[i];
++m;
}
}
return m;
}
It can be called the following way
size_t m = remove_even( p, n );
for ( size_t i = 0; i < m; i++ ) printf( "%d ", a[i] );
printf( "\n" );
where p is the pointer to your dynamically allocated array of n elements.
The function actually removes nothing. It simply moves odd elements to the beginning of the array.
You can then use standard C function realloc to delete physically the removed elements.
For example
int *tmp = realloc( p, m * sizeof( int ) );
if ( tmp != NULL ) p = tmp;
Here is a demonstrative program
#include <stdlib.h>
#include <stdio.h>
size_t remove_even( int a[], size_t n )
{
size_t m = 0;
for ( size_t i = 0; i < n; i++ )
{
if ( a[i] % 2 != 0 )
{
if ( i != m ) a[m] = a[i];
++m;
}
}
return m;
}
#define N 10
int main( void )
{
int *a = malloc( N * sizeof( int ) );
for ( size_t i = 0; i < N; i++ ) a[i] = i;
for ( size_t i = 0; i < N; i++ ) printf( "%d ", a[i] );
printf( "\n" );
size_t m = remove_even( a, N );
int *tmp = realloc( a, m * sizeof( int ) );
if ( tmp != NULL ) a = tmp;
for ( size_t i = 0; i < m; i++ ) printf( "%d ", a[i] );
printf( "\n" );
free( a );
}
Its output is
0 1 2 3 4 5 6 7 8 9
1 3 5 7 9
There are some things which you need to check before you try to code something, but I see that there is no code which you showed use.
SO is not a tutorial site, so this means that you should show us some code which actually does compile and ask here if there are some problems with that code.
Any way until than, this code should give you an Idea about how to check if a Number is odd or even:
#include<stdio.h>
#include<stdlib.h>
int main(void){
int n;
printf("Enter an integer:> ");
if((scanf("%d", &n)) != 1){
printf("Error, Fix it!\n");
exit(1);
}
if (n%2 == 0){
printf("Even\n");
}else{
printf("Odd\n");
}
return 0;
}
The whole story here is not about checking if Numbers inside an Array are odd or even, is about to find a way to check if a number is odd or even and only then you should check if inside that array there are odd or even numbers. I hope you understand my point.
One easy way to remove even numbers from an array in C is to create a new array of all odd elements starting from 1 to the maximum element present in the original array and then compare the original array and odd elements array (and do intersection) and put it in another array with same elements present in both arrays.
Here is the program:
#include<stdio.h>
int main(){
int a[20],n,i,max,j,k=0,l=0;
printf("enter limit of array ");
scanf("%d",&n);
printf("enter the elements ");
for (i=0;i<n;i++){
scanf("%d",&a[i]);
}
max=a[0];
for (i=0;i<n;i++){
if (a[i]>max){
max=a[i];
}
}
int b[max],c[n],count=0;
for (j=2;j<=max;j=j+2){
c[k++]=j;
count++;
}
for (i=0;i<n;i++){
for (j=0;j<count;j++){
if (a[i]==c[j])
b[l++]=a[i];
}
}
for (i=0;i<count;i++){
printf("%d ",b[i]);
}
return 0;
}

Resources