gal
gal

Reputation: 486

C Mergesort Segfault

Situation

I was trying to implement a more interesting mergesort that creates a random length array with random values and then randomizes them, but after debugging and compiling it segfaults. I don't know why it segfaults, but I'm sure it's related to memory allocation.

Question

Why does this code cause a segfault?

Code

#include <stdio.h>
#include <stdlib.h>
#include <time.h>


// Declare some stuff up front

int array_size(int *array);
int print_array(int *array);

//Some decade old main function coming at you

int main() {

    //Concerned with the integrity of my rand
    srand( (unsigned)time( NULL ));

    //A global, random length array between 1 and 100?
    int *array;
    array = malloc(sizeof(*array) * ((rand() % 100) + 1));


    init_array(*array);




    getchar();
    return 0;
}

int init_array(int *array)  {
    //Base case
    array[0] = 1;
    //random values for i in array
    int i;
    for(i = 1; i <= array_size(array); i++)  {
          array[i] = rand() % array_size(array) + 1;
    }
    //randomize the random values in the random length array
    for (i = 0; i < (array_size(array) - 1); i++)
    {
        unsigned int swapA = (rand() % array_size(array)) + 1;
        int a = array[swapA];
        array[swapA] = array[i];
        array[i] = a;
    }
    //output random array, then mergeSort the array
    print_array(array);
    sort_array(array);
    return 0;
}

//Get my array.Length
int array_size(int *array) {
    return sizeof(array)/sizeof(array[0]);
}

//Output array
int print_array(int *array) {
     int i;
     for(i = 0; i < (array_size(array) + 1); i++) {
           printf("%d\n", array[i]);
     }
     return 0;
}
     //merge the array after sorting
void merge_array(int *array, int low, int split, int high)  {
     int sorted[high-low+1];
     int a = 0;
     int b = low;
     int c = split + 1;
     //iterate from beginning to middle and from middle to end in parallel
     while(b <= split && c <= high)
     {
            if(array[b] < array[c])
            {
                sorted[a++] = array[b++];
            }
            else
            {
                sorted[a++] = array[c++];
            }
     }

     while(b <= split) sorted[a++] = array[b++];
     while(c <= high)  sorted[a++] = array[c++];
     int i;
     for(i = 0; i < a; i++) {
           array[i+low] = sorted[i];
     }
     print_array(array);            //Print sorted array
}
     //Sort the array
int sort_array(int *array, int low, int high) {
    int split = ( low + high ) / 2;
    if( low < high ) {
        sort_array(array, low, split);
        sort_array(array, split + 1, high);
        merge_array(array, low, split, high);
    }

}

Upvotes: 1

Views: 184

Answers (3)

Raj
Raj

Reputation: 4452

return sizeof(array)/sizeof(array[0]);

The above statement evaluates to 1 (assuming sizeof(int *) = sizeof(int), as pointed out by H2CO3).

Try something like this,

int main() {

//Concerned with the integrity of my rand
srand( (unsigned)time( NULL ));

//A global, random length array between 1 and 100?
int *array;
int number_of_elements = (rand() % 100) + 1;
array = malloc(sizeof(*array) * num_of_elements);

init_array(*array, num_of_elements);

getchar();
return 0;

}

Pass the number of elements as arguments to init_array instead of calculating it every time.

Upvotes: 2

SecurityMatt
SecurityMatt

Reputation: 6743

  1. What happens when you run your program with /WALL? What warnings are being spat out? Why?
  2. What happens when you step through your program with a debugger attached? What is the value of each variable at each line? Why?

There are several problems with your code:

  1. You don't check the result of malloc to see if it returned NULL.

  2. You are passing the dereference of array to init_array, i.e. you are sending the first int of the array to init_array which then promptly dereferences it. Since malloc returns garbage data, you're dereferencing a random number inside of init_array.

  3. array_size is not magic. If you do not track the size of your arrays in C, you cannot retrospectively find out how big you wanted them to be. You need to remember the size of the array and pass it to init_array.

Upvotes: 0

George P&#238;rlea
George P&#238;rlea

Reputation: 385

This seems to be the problem:

//Get my array.Length
int array_size(int *array) {
    return sizeof(array)/sizeof(array[0]);
}

You essentially return sizeof(int*)/sizeof(int), which is not what you want. This whole thing appears because arrays decay into pointers when passed to functions.

You should read the Arrays and Pointers section in the comp.lang.c FAQ for edification.

Upvotes: 1

Related Questions