Program in C randomly crashes when I use free() - c

This program is supposed to allow the user to type in as many variables as they would like (which is stored in an array). Once the user types in "-999", the program will stop filling the array, find the largest number in the array and end. However, when I input some test numbers into the program, it will successfully end at times, but other times it will just decide to crash.
For example, I could type in:
100 (return) 200 (return) 300 (return) 400 (return) -999 (return)
and it will crash.
Then I'll type in:
10 (return) 20 (return) 30 (return) 40 (return) -999 (return)
and it will run successfully. Then if I type what I typed originally it will work and won't crash. And I'll even repeat this test and it won't replicate the same results.
I'm totally confused and lost, any help would be appreciated.
#include <stdio.h>
void fillArray(int *a);
int largestElement(int *a);
int i = 0;
int main()
{
int *array = (int *)malloc(sizeof(int));
fillArray(array);
printf("The largest element in 'array' is: %d\n", largestElement(array));
//Program randomly crashes right here sometimes, not sure why.
printf("Right before free function...\n");
free(array);
printf("Successfully freed!\n");
return 0;
}
void fillArray (int *a)
{
int userInput = 0;
printf("Type in a list of numbers terminated by a -999:\n");
while(userInput != -999)
{
//*a = realloc(a, (i+1) * sizeof(int));
scanf("%d", &userInput);
a[i] = userInput;
i++;
}
}
int largestElement(int *a)
{
int j;
int largest = a[0];
for(j = 0; j < i; j++){
if(a[j] > largest){
largest = a[j];
}
}
return largest;
}

The reason for the crash on free is because you only allocate space for a single int, but you copy values into a as if it's an array with multiple values. Writing past the end of allocated memory like that invokes undefined behavior.
The call to realloc you have commented out isn't quite doing what you want:
*a = realloc(a, (i+1) * sizeof(int));
The expression *a is of type int, do it doesn't make sense to assign a pointer back to it. Because realloc can move the memory that was originally allocated, you need to pass the address of array in main so that it can be modified in the calling function.
So change fillArray to take a pointer-to-pointer:
void fillArray (int **a)
{
int userInput = 0;
printf("Type in a list of numbers terminated by a -999:\n");
while(userInput != -999)
{
*a = realloc(*a, (i+1) * sizeof(int));
scanf("%d", &userInput);
(*a)[i] = userInput;
i++;
}
}
And call it like this:
fillArray(&array);

Related

C function stops after few iterations

The program should do this: write a doubleArray() function, which takes in input an array of int and its size (as a pointer to int). In the main(): ask the user to input an integer n between 1 and 4, then dynamically create an array of size n. Then start filling the array with 2048 randomly generated int: each time the array is full, call the doubleArray function; each time the function doubleArray is called, print the content of the array.
My code works until the size of array n reach a number around 250, then stops inside the for loop.
#include<stdlib.h>
#include<stdio.h>
#include<time.h>
void doubleArray(int vect[], int *dim)
{
int n = *dim *2;
*dim = n;
vect = (int*)realloc(vect, n*sizeof(int));
}
void stampaArray(int vect[], int dim)
{
for (int i=0;i<dim;i++)
{
printf("%d ",vect[i]);
}
printf("\n");
}
int main()
{
printf("Insert a number between 1 and 4: ");
int n;
scanf("%d",&n);
if ((n<1)||(n>4))
{
printf("Number not valid, try again: '");
scanf("%d",&n);
}
int *arr = (int*) malloc (n*sizeof(int));
srand(time(NULL));
int num;
for (int i=0;i<220;i++)
{
num = rand();
if (i==n)
{
doubleArray(arr, &n);
stampaArray(arr, n);
}
arr[i]=num;
}
stampaArray(arr,n);
return 0;
}
Firstly, Change this
if ((n<1)||(n>4)) { } /* use && instead of || to scan if n if both condition are true*/
to
//scanf("%d",&n); /*remove this, use only once, in below loop */
while(1) {
scanf("%d",&n);
if ((n>=1) && (n<=4)) {
break;
}
else {
printf("Number not valid, try again: '");
}
}
And allocate memory equal to n bytes. for e.g
int *arr = malloc (n * sizeof(*arr)); /* typecasting is not required */
Also here
for (int i=0;i<220;i++) { /* some code */ }
what is the rationale behind rotating loop 220 times, doesn't it should be n times ?
As you were said in comment, your main error is that realloc is allowed to change the pointer value. If it happens, the new value is only assigned to the local copy inside the doubleArray function, but the caller still keeps the previous value which is now a dangling pointer (pointing to non allocated memory). Using it invokes Undefined Behaviour (and crashes are to be expected...)
The correct way is to return the new pointer value:
int * doubleArray(int vect[], int *dim)
{
int n = *dim *2;
*dim = n;
return realloc(vect, n*sizeof(int));
}
That is not all. best practices recommend to test allocation. In a stressed environment, the system could be unable to allocate enough memory and realloc could return NULL. Proceeding would then also involve Undefined Behaviour.
Let us go on. Controlling input is nice, but a user can type twice an error, so you should loop until you get a correct value:
int n;
for (;;) {
printf("Insert a number between 1 and 4: ");
scanf("%d",&n);
if ((n >= 1) && (n <= 4)) break;
printf("Number not valid, try again: '");
}
And please, please do not cast malloc in C language. It is useless and can hide hard to find indirection level errors.
Finally, I cannot understand why you have a loop up to 220... From your requirements it should be up to 2048.
Last point (but this one is only my opinion, not a problem): I would only display the initialized content of the array, so up to i instead of n. That way you would see the array grow while always keeping the same (initialized) values:
int *arr = malloc (n*sizeof(int));
srand(time(NULL));
int num;
for (int i=0;i<2048;i++)
{
num = rand();
if (i==n)
{
arr = doubleArray(arr, &n);
if (arr == NULL) {
perror("allocation error");
return 1;
}
stampaArray(arr, i);
printf("\n");
}
arr[i]=num;
}
stampaArray(arr,2048);
free(arr); // not required immediately before a return but good practice

Segmentation fault when trying to add elements of an array

I'm trying to create a function that returns as its result the sum of the elements in the array. When I try to run the program, I get a segmentation fault. Could someone please point me in the right direction? Thank you!
int arraySum (int array[], int numberOfElements) {
int result = 0;
for (int i = 0; i < numberOfElements; i++)
{
result += array[i];
}
return result;
}
int main (void) {
int numberOfElements;
int *array = NULL;
printf("How many elements would you like in your array: ");
scanf("%i", &numberOfElements);
printf("\nPlease list the values of the elements in the array: ");
for (int i = 0; i < numberOfElements; i++)
{
scanf("%i", &array[i]);
}
int result = arraySum(array, numberOfElements);
return result;
}
The problem you have is, that in C you need to manually allocate the memory if you are using a pointer instead of say a fixed-size array.
This is usually done by calling malloc, which will return a void-pointer (void*), which you need to cast to the desired type (in your case (int*)) before assigning it.
It is also important to note, that, when using malloc, you need to specify the amount of Bytes you want to allocate. This means that you can't just call it with the number of integers you want to store inside, but rather have to multiply that number with the amount of Bytes that one integer occupies (which depends on the Hardware and Operating System you use, hence you should use sizeof(int) for that purpose, which evaluates to that size at compile time).
I modified your code with a working example of how it could be done:
#include <stdio.h>
#include <stdlib.h>
int arraySum (int array[], int numberOfElements) {
int result = 0;
int i;
for (i = 0; i < numberOfElements; i++) {
result += array[i];
}
return result;
}
int main(int argc, char **argv) {
int numberOfElements;
int *array = NULL;
printf("How many elements would you like in your array: ");
scanf("%i", &numberOfElements);
array = (int*) malloc(numberOfElements * sizeof(int));
printf("\nPlease list the values of the elements in the array: ");
int i;
for (i = 0; i < numberOfElements; i++) {
scanf("%i", &array[i]);
}
int result = arraySum(array, numberOfElements);
printf("\n\nThe result is: %d\n", result);
return 0;
}
You are also trying to return the result in your main function, but the return value of main in C is used to signal whether your program terminated without errors (signalled by a return value of 0) or didn't encounter any issues (any value other than 0).
You need to allocate memory. It is not enough to just declare a pointer. You do it like this: array=malloc(numberOfElements*sizeof(*array));
Also, although it is possible to return result from the main function, you should not do that. The return value from main is usually used for error checking. Change the end of your program to
printf("Sum: %d\n", result);
return 0;
Returning 0 usually means that no error occurred.

Segmentation fault using scanf for float ** type

I'm trying to code a function that would ask the user to enter matrix. It prompts the number of lines, the number of columns and then prompts the value for each element of the matrix:
#include <stdio.h>
#include <stdlib.h>
void enterMatrix(float ** matrix, int nbLines, int nbColumns){
for (int i = 0; i < nbLines * nbColumns; i++){
printf("i = %d? ", i);
scanf("%f", matrix[i]);
}
}
int main(void){
int nbLines, nbColumns;
printf("nbLines? "); scanf("%d", &nbLines);
printf("nbColumns? "); scanf("%d", &nbColumns);
float *matrix[nbL * nbCol];
enterMatrix(matrix, nbLines, nbColumns);
}
Everything works fine until I enter a value for i = 0 and then press enter, which leads to a segmentation fault.
Any idea as to what could be wrong?
Your problem is because
float *matrice[nbL * nbCol];
defines an array of uninitialised pointers (i.e. an array of float *), not an array of float. This is then passed to enterMatrix() as a pointer to pointer to float (i.e. a float **). The scanf() calls then read to matrix[i] which is an uninitialised pointer. The result is undefined behaviour.
One fix would be to change the definition of matrice in main() to
float matrice[nbL * nbCol];
and change the function to (I've used comment to highlight changes)
void enterMatrix(float *matrix, int nbLines, int nbColumns) /* note type of matrix */
{
for (int i = 0; i < nbLines * nbColumns; i++)
{
printf("i = %d? ", i);
scanf("%f", &matrix[i]); /* note what the second argument is */
}
}
You need to allocate memory dinamically since you do not know at compile time which values the variables nbLines and nbColumns will hold.
So you need to first declare the pointer to the matrix:
float **matrix;
Then start allocate memory according to user input:
matrix = (float **)malloc(nbLines * sizeof(float *));
for (int i = 0; i < nbLines; i++)
{
matrix[i] = (float *)malloc(nbColums * sizeof(float ));
}
The segmentation fault error happens becouse you are not allocating memory for your matrix, but just a [nbL * nbCol] pointers to float
You don't allocate enough memory for your array, thus you invoke Undefined Behavior, since you go out of bounds, causing a Segmentation fault.
You could declare it like a 2D array, like this:
/* TODO: Check if allocation succeeded. (check for NULL pointer) */
float** matrix;
matrix = malloc(nbLines * sizeof(float*));
for(int i = 0 ; i < N ; i++)
matrix[i] = malloc(nbColumns * sizeof(float));
I have other approaches for allocating a 2D array dynamically here.
Please note: Do I cast the result of malloc? No!
Also do not forget to free().
You could emulate a 2D array with an 1D array, like this:
void enterMatrix(float* matrix, int nbLines, int nbColumns){
for (int i = 0; i < nbLines ; i++) {
for (int j = 0; j < nbColumns; j++) {
scanf("%f", matrix[i + nbColumns * j]);
}
}
float matrix[nbLines * nbColumns];
You're creating a variable length array, and, of pointers.
While other answers are perfectly valid, if you really want a 2D array, you just need to change the declaration:
float matrix[nbLines][nbColumns];
to declare a 2D variable length array of floats.
Now the hard point is to pass this VLA to a function and preserve dimensions.
For that you could use C99 way of passing VLAs (note that dimensions must be located before the VLA itself). Reference: Passing a multidimensional variable length array to a function:
void enterMatrix(int nbLines, int nbColumns, float matrix[][nbColumns] ){
for (int i = 0; i < nbLines; i++){
for (int j = 0; j < nbColumns; j++)
{
scanf("%f", &matrix[i][j]);
}
}
}
call as follows:
enterMatrix(nbLines, nbColumns, matrix);

C: Return even number in array program by using pointers, why does my program crush after printing the result

This is my simple program that generate a array of N integers, print it, and it will call the getevennumber function, and the function will return the pointer addresses of the even numbers in array. and the main program will print the even numbers in the array:
#include <stdio.h>
int* getEvenNumber(int a[]);
int main (){
int N;
printf("Enter N: ");
scanf("%d", &N);
int array[N], i;
int *test[N];
srand(time(NULL));
for(i = 0; i < N; i++)
{
array[i] = (rand() % 100)+1;
printf("%d \n", array[i]);
}
printf("------- \n");
*test = getEvenNumber(array);
for(i = 0; i <= sizeof(test); i++){
printf("%d \n", *test[i] );
}
return 0;
}
int* getEvenNumber(int a[]){
int i,j = 0;
int* ptr[j];
for(i = 0; i <= sizeof(a); i++)
{
if (a[i] % 2 == 0)
{
ptr[j] = &a[i];
printf("%d\n",*ptr[j]);
j++;
}
}
return *ptr;
}
currently the problem is: when I run the program, it will print the desired even numbers, then the program will also print 2 random data address then crushes, here is an example output:
N: 10
66
19
70
54
84
12
35
56
53
19
66
70
54
84
19
1981890690
-1090571325
(program crushed)
Can someone help me identify the problem please, thank you!
In the function getEvenNumber, you're creating a local variable ptr which adress you are returning. You should not do that, because local variables only exist within a function, and never outside of it. Also, you are actually returning the value of the first element of ptr (because you are dereferencing it). This is why *test[i] fails, because you never return the actual array and thus cannot iterate over it with [i].
The best solution would be to declare the array in the main function and pass it like this getEvenNumber(int a[], int *ptr[])
And don't declare your array with size zero... (as you are currently doing with ptr).
for(i = 0; i <= sizeof(test); i++){
printf("%d \n", *test[i] );
}
sizeof(test) isn't the number of elements in the array test, it's sizeof(int*) which is 8 (bytes), assuming you're on a 64-bit system. It's returning the size of a pointer to a memory address, not the actual length of the array. So your loop goes outside the bounds of the array which probably causes your problem.
Also you're returning a local variable, which can cause additional problems.

How to cycle through array without indexes in C?

I need to allocate an N sized array and assign it values, how can I do it without int indexes?
Here is the code I have so far but it doesn't do what I need:
#include <stdlib.h>
#include <stdio.h>
int main() {
int *array;
int n;
printf("Size of array: ");
scanf("%d", &n);
array = (int*) malloc(n*sizeof(int));
if (array == NULL) printf("Memory Fail");
for(; *array; array++)
{
printf("Store:\n");
scanf("%d", &n);
*array = n;
}
for(; *array; array++)
{
printf("Print: %d\n",*array);
}
free(array);
return 0;
}
thanks
for(; *array; array++); you should remove ; at the end
Number of iterations for this loop is undefined and you are going to lose a pointer
You should do something like this:
int *cur;
for(cur = array; cur < array+n; ++cur)
{
*cur = ...;
}
When you allocate the memory, you have no way to determine, in the memory, where it ends (unless you decide a convention and set a value somewhere, but anyway you would use n) .
In your case you have to use n to limit the array coverage (otherwise it is only limited by your computer capacity, and until it reaches an area where it does not have access: program crash). For instance (be careful not to overwrite n !)
int v;
int x = n;
int *ptr = array;
while (x--)
{
printf("Store:\n");
scanf("%d", &v);
*ptr++ = v;
}
x = n;
ptr = array;
while (x--)
{
printf("Print: %d\n",*ptr++);
}
You are using *array as your condition, which means the for loop should continue unless *array evaluates to false, which is only if *array == 0. You are actually invoking undefined behavior because you allocate array with malloc and are trying to dereference the pointer when the underlying data could be anything, since the data block has been uninitialized.
You still need some type of counter to loop with, in this case you allocated n items.
/* I'm using a C99 construct by declaring variables in the for initializer */
for (int i = 0; i < n; ++i)
{
/* In your original code you re-assign your counter 'n', don't do that otherwise you lost the size of your array! */
int temp;
printf("Store: \n");
scanf("%d", &temp)
array[i] = temp;
}
/* This is your second loop which prints the items */
for (int i = 0; i < n; ++i)
{
printf("%d\n", array[i]);
}
Also, do not manipulate the array pointer without keeping a copy of it. You can only do free on the pointer returned by malloc.
Using indexes is the same as manipulating the pointer, your professor is being ridiculous otherwise.
If you have an array int *a; then:
a[0] is equal to *a
a[1] is equal to *(a+1)
a[2] is equal to *(a+2)
So you can go through the array by doing arithmetic on the pointer.

Resources