Segmentation fault while passing array as parameter in c - c

As an assignment I have to implement mergesort. I am getting segmentation faults as I am passing array as an argument. Everything appears to be correct. I am attaching the code.
arr is int arr[1000], I am passing it to mergesort as
mergesort(arr, 0, n);
Remaining code is as follows.
void merge(int a[], int l, int m, int r)
{
int temp[r -l];
int templ = l;
int tempm = m;
register int k;
for(k=0; k<(r-l); k++)
{
if((tempm >= r)||(templ < m)&&(a[templ] <= a[tempm]))
{ /*if number from left subarray is smaller*/
temp[k] = a[templ];
templ++;
}
else
{ /*number from right subarray is smaller*/
temp[k] = a[tempm];
tempm++;
}
}
for(k= l; k< r; k++)
{ /*copy results back to the array to be returned*/
a[k] = temp[k - l];
}
}
void mergesort(int ar[], int left, int right)
{
int mid;
if(left < right)
{
mid= (left + right)/2;
mergesort(&ar[0], left, mid - 1);
mergesort(&ar[0], mid, right);
merge(&ar[0], left, mid, right);
}
}

Once you have left == 0 and right == 1 in mergesort, you are going to have an infinite recursion:
void mergesort(int ar[], int left, int right) // IF LEFT IS 0 AND RIGHT IS 1 HERE...
{
int mid;
if(left < right) // ...THEN LEFT IS LESS THAN RIGHT AND...
{
mid= (left + right)/2;
mergesort(&ar[0], left, mid - 1);
mergesort(&ar[0], mid, right); // ...HERE WE HAVE A CALL THAT IS
// IDENTICAL TO THE ONE THAT GOT US HERE, INFINITE RECURSION

Related

What's wrong with this quicksort program that I adapted?

edit: added main function
int main(int argc, char *argv[]) {
int arr[] = {3, 2, 1};
int n = sizeof(arr)/sizeof(arr[0]);
quicksort(arr, 0, n-1);
for (int i=0; i<n; i++) {
printf("%3d", arr[i]);
}
return 0;
}
void quicksort(int arr[], int left, int right) {
if (left<right) {
int pivot = partition(arr, left, right);
quicksort(arr, left, pivot-1);
quicksort(arr, pivot+1, right);
}
}
int partition(int arr[], int left, int right) {
/* left to i = smaller than pivot
i+1 = pivot
i+2 to right = bigger than pivot */
int pivot = right, i = left-1;
for (int j=left; j<right-1; j++) { // right-1 because the last num is the pivot
if (arr[j] < arr[pivot]) {
/* j scans the array for values that need to be swapped into the
right side of the partition */
i++;
swap(&arr[j], &arr[i]);
}
// swap pivot into the middle
swap(&arr[i+1], &arr[right]);
}
return i+1; // index of pivot
}
void swap(int *x, int *y)
{
int tmp = *x;
*x = *y;
*y = tmp;
}
I was following a tutorial and tried to translate pseudocode into C but I'm not sure what's wrong with my code
I'm using the input 3,2,1 but its outputting 2 1 3
int partition(int arr[], int left, int right) {
int pivot = right;
int i = left; // <-- set I to left not left -1
for (int j=left; j<right; j++) { // <-- no need for -1 (you already use less and not less or equal operator
if (arr[j] < arr[pivot]) {
swap(&arr[j], &arr[i]); // <-- do the swap first, then increment
i++;
}
}
// swap pivot into the middle
swap(&arr[i], &arr[right]); // <-- this needs to be outside the loop
return i; // <-- return I not I + 1
}

merge_sort works and not works in some condition(input number)

I have this c code for merge sort.
The code works well when N<=4 but does not when N>4.
If I put in 4 for N and enter 4 numbers, the result shows as it should.
However, when I put in 6 and enter 6 numbers, the program stops for few seconds and puts out nothing as result.
What can I do to make this code work for all occasions(N
#include <stdio.h>
#include <stdlib.h>
#define MAX 100000
void Merge(int* arr, int p, int q, int r);
void MergeSort(int *arr,int p, int r);
int main(void)
{
int N, i;
int *arr ;
scanf("%d", &N);
if ((N>MAX) || (N<1))
return -1;
arr = (int*)malloc(sizeof(int)*N);
for (i = 0; i<N; i++)
scanf("%d", &arr[i]);
MergeSort(arr, 0, N - 1);
for (i = 0; i<N; i++)
printf("%d\n", arr[i]);
free(arr);
}
void Merge(int *arr, int left, int mid, int right)
{
int i,i1,i2;
int b[right-left+1];
for(i=left, i1=left, i2=mid+1;i<=right && i1<=mid && i2<=right;i++ ){
if(arr[i1]>arr[i2])
b[i]=arr[i1++];
else
b[i]=arr[i2++];
}
for(i; i<=right;i++){
if(i1<=mid)
b[i]=arr[i1++];
if(i2<=right)
b[i]=arr[i2++];
}
for(i=left;i<=right;i++)
arr[i] = b[i];
}
void MergeSort(int *arr, int left, int right)
{
int mid;
if (left<right){
mid = (left + right) / 2;
MergeSort(arr, left, mid);
MergeSort(arr, mid + 1, right);
Merge(arr, left, mid, right);
}
else
return;
}

The pointers array returned from the function to the main is NULL

I was asked to create a function in C that gets an array of int's, its size and a character representing if the sort needs to be ascending or descending (0 for ascending, any other char if descending), and returns a pointers array. If the sort is ascending, the pointers will be sorted from minimum to maximum of the values in the int's array.
Like that
Everything works well until the pointers array is being returned to the main with a value of NULL. I mean, before the function ends and the array is being returned, there are values in the array (and they're also sorted well), but the moment the main gets the address from the function, it's null. Is anyone familiar with the problem?
Thank you!
#include <stdio.h>
#define SIZE 100
// Functions declaration
int** pointerSort(int* arr, unsigned int size, char ascend_flag);
void sortMerge (int** sortedArr, int left, int right, char ascend_flag);
void mergeSortAscend (int** arr, int left, int middle, int right);
void mergeSortDescend (int** arr, int left, int middle, int right);
void copyAddress(int** addressArray, int* arr, unsigned int size);
int main()
{
int** sortedArr;
int arr[5] = {8,1,7,2,4};
int size = 5;
sortedArr = pointerSort(arr, size, '1');
return 0;
}
// The pointerSort function gets an array, its size and a flag representing "sort by" (ascending, descending)
int** pointerSort(int* arr, unsigned int size, char ascend_flag)
{
// Variables declaration
int* sortedArr[size];
// Copying the addresses of each value in arr to an addresses array
copyAddress(sortedArr, arr, size);
// Sending the array of addresses, its start and end and the ascend_flag to the sortMerge function
sortMerge(sortedArr, 0, size - 1, ascend_flag);
return (sortedArr);
}
void sortMerge (int** sortedArr, int left, int right, char ascend_flag)
{
// Variables declaration
int middle = (left + right) / 2;
// Checking if there are more than one cell
if (left < right)
{
// Splitting the array into two
sortMerge(sortedArr, left, middle, ascend_flag);
sortMerge(sortedArr, middle + 1, right, ascend_flag);
// Checking if the sort requested is ascending or descending
if (ascend_flag != '0')
{
mergeSortAscend(sortedArr, left, middle, right);
}
else
{
mergeSortDescend(sortedArr, left, middle, right);
}
}
}
void mergeSortAscend (int** arr, int left, int middle, int right)
{
int l = left, m = middle + 1, r = right, i = left;
int* temp[SIZE];
while ((l <= middle) && (m <= right))
{
if (*(arr[l]) > *(arr[m]))
{
temp[i] = arr[m];
m++;
}
else
{
temp[i] = arr[l];
l++;
}
i++;
}
if (l <= middle)
{
while (l <= middle)
{
temp[i] = arr[l];
l++;
i++;
}
}
if (m <= right)
{
while (m <= right)
{
temp[i] = arr[m];
m++;
i++;
}
}
for (int k = left; k <= right; k++)
{
arr[k] = temp[k];
}
}
void copyAddress(int** addressArray, int* arr, unsigned int size)
{
int i;
for (i = 0; i < size; i++)
{
addressArray[i] = &(arr[i]);
}
}
void mergeSortDescend (int** arr, int left, int middle, int right)
{
int l = left, m = middle + 1, r = right, i = left;
int* temp[SIZE];
while ((l <= middle) && (m <= right))
{
if (*(arr[l]) <= *(arr[m]))
{
temp[i] = arr[m];
m++;
}
else
{
temp[i] = arr[l];
l++;
}
i++;
}
if (l <= middle)
{
while (l <= middle)
{
temp[i] = arr[l];
l++;
i++;
}
}
if (m <= right)
{
while (m <= right)
{
temp[i] = arr[m];
m++;
i++;
}
}
for (int k = left; k <= right; k++)
{
arr[k] = temp[k];
}
}
The int* sortedArr[size]; in int** pointerSort(int* arr, unsigned int size, char ascend_flag) becomes invalid as soon your function returns since it is an automatic variable allocated of the stack.
You need a permanent storage. For example allocate memory for sortedArr on the heap by the malloc function and return it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 100
// Functions declaration
int** pointerSort(int* arr, unsigned int size, char ascend_flag);
void sortMerge (int** sortedArr, int left, int right, char ascend_flag);
void mergeSortAscend (int** arr, int left, int middle, int right);
void mergeSortDescend (int** arr, int left, int middle, int right);
void copyAddress(int** addressArray, int* arr, unsigned int size);
int main(void)
{
int** sortedArr;
int arr[5] = {8,1,7,2,4};
int size = 5;
int i =0;
sortedArr = pointerSort(arr, size, '1');
if(sortedArr) // memory was allocated
for(i=0; i<5; i++){
printf("%d ", *sortedArr[i]);
}
free(sortedArr);
return 0;
}
// The pointerSort function gets an array, its size and a flag representing "sort by" (ascending, descending)
int** pointerSort(int* arr, unsigned int size, char ascend_flag)
{
// Variables declaration
//int* sortedArr[size];
int ** sortedArr = malloc( sizeof(int *) * size);
if(sortedArr == NULL) return NULL; // no memory
// Copying the addresses of each value in arr to an addresses array
copyAddress(sortedArr, arr, size);
// Sending the array of addresses, its start and end and the ascend_flag to the sortMerge function
sortMerge(sortedArr, 0, size - 1, ascend_flag);
return (sortedArr);
}
void sortMerge (int** sortedArr, int left, int right, char ascend_flag)
{
// Variables declaration
int middle = (left + right) / 2;
// Checking if there are more than one cell
if (left < right)
{
// Splitting the array into two
sortMerge(sortedArr, left, middle, ascend_flag);
sortMerge(sortedArr, middle + 1, right, ascend_flag);
// Checking if the sort requested is ascending or descending
if (ascend_flag != '0')
{
mergeSortAscend(sortedArr, left, middle, right);
}
else
{
mergeSortDescend(sortedArr, left, middle, right);
}
}
}
void mergeSortAscend (int** arr, int left, int middle, int right)
{
int l = left, m = middle + 1, r = right, i = left;
int* temp[SIZE];
while ((l <= middle) && (m <= right))
{
if (*(arr[l]) > *(arr[m]))
{
temp[i] = arr[m];
m++;
}
else
{
temp[i] = arr[l];
l++;
}
i++;
}
if (l <= middle)
{
while (l <= middle)
{
temp[i] = arr[l];
l++;
i++;
}
}
if (m <= right)
{
while (m <= right)
{
temp[i] = arr[m];
m++;
i++;
}
}
for (int k = left; k <= right; k++)
{
arr[k] = temp[k];
}
}
void copyAddress(int** addressArray, int* arr, unsigned int size)
{
int i;
for (i = 0; i < size; i++)
{
addressArray[i] = &(arr[i]);
}
}
void mergeSortDescend (int** arr, int left, int middle, int right)
{
int l = left, m = middle + 1, r = right, i = left;
int* temp[SIZE];
while ((l <= middle) && (m <= right))
{
if (*(arr[l]) <= *(arr[m]))
{
temp[i] = arr[m];
m++;
}
else
{
temp[i] = arr[l];
l++;
}
i++;
}
if (l <= middle)
{
while (l <= middle)
{
temp[i] = arr[l];
l++;
i++;
}
}
if (m <= right)
{
while (m <= right)
{
temp[i] = arr[m];
m++;
i++;
}
}
for (int k = left; k <= right; k++)
{
arr[k] = temp[k];
}
}
Test:
1 2 4 7 8

Implementation of the quick select algorithm to find kth smallest number

I'm currently working on a program to find the kth smallest number of an array using the quick select algorithm. I've finished it and it works but does not give the correct result every time.
Here's my code (I didn't include my partition or swap algorithm, I'm fairly sure they're correct):
/*
inputs...
*A: pointer to array
n: size of array
k: the item in question
*/
int ksmallest(int *A, int n, int k){
int left = 0;
int right = n - 1;
int next = 1;
return quickselect(A, left, right, k);
}
int quickselect(int *A, int left, int right, int k){
//p is position of pivot in the partitioned array
int p = partition(A, left, right);
//k equals pivot got lucky
if (p - 1 == k - 1){
return A[p];
}
//k less than pivot
else if (k - 1 < p - 1){
return quickselect(A, left, p - 1, k);
}
//k greater than pivot
else{
return quickselect(A, p + 1, right, k);
}
}
Everything compiles fine. I then tried to use the program on the following array: [1,3,8,2,4,9,7]
These were my results:
> kthsm 2
4
> kthsm 1
1
> kthsm 3
2
As you can see, it worked correctly on the 1th smallest item, but failed on the others. What could be the problem? I guessed than my indexing was off but I'm not exactly sure.
EDIT: Added my partition and swap code below, as requested:
int partition(int *A, int left, int right){
int pivot = A[right], i = left, x;
for (x = left; x < right - 1; x++){
if (A[x] <= pivot){
swap(&A[i], &A[x]);
i++;
}
}
swap(&A[i], &A[right]);
return i;
}
//Swaps
void swap(int *a, int *b){
int temp = *a;
*a = *b;
*b = temp;
}
In your partition function the loop condition should be x < right, not x < right - 1.
Also, in the if statements in quickselect, you should switch both uses of p-1 to p. p is already an index and by decreasing k by 1 you turn it into an index(rather than an order) as well. There is no need to decrease p by one again.
int partition(int *A, int left, int right){
int pivot = A[right], i = left, x;
for (x = left; x < right; x++){
if (A[x] < pivot){
swap(&A[i], &A[x]);
i++;
}
}
swap(&A[i], &A[right]);
return i;
}
int quickselect(int *A, int left, int right, int k){
//p is position of pivot in the partitioned array
int p = partition(A, left, right);
//k equals pivot got lucky
if (p == k-1){
return A[p];
}
//k less than pivot
else if (k - 1 < p){
return quickselect(A, left, p - 1, k);
}
//k greater than pivot
else{
return quickselect(A, p + 1, right, k);
}
}
Here's a working example. http://ideone.com/Bkaglb

Writing merge sort in C without pointers

I am trying to write code for homework in C that will take 10 integers from user input into an array and sort it using a recursive merge sort. We have not gone over pointers yet so I wanted to avoid using that in my code (many online examples use pointers).
Here is my code:
/* This code will take input for 10 integers given by the user
into an array, sort them with a recursive merge function
and print the updated array in ascending order. */
#include <stdio.h>
#define ARRSIZE 10
void merge_sort (int arr[], int temp[], int left, int right);
void merge (int arr[], int temp[], int left, int mid, int right);
int main (void){
int arr[ARRSIZE], temp[ARRSIZE], left, right, i;
printf("Enter 10 integers for an array:");
for(i=0;i<ARRSIZE;i++){
printf("\narray value %d:", i+1);
scanf("%d", &arr[i]);
}
left = 0;
right = ARRSIZE-1;
merge_sort(arr, temp, left, right);
printf("\nHere is your updated array:");
printf("\n{");
for(i=0;i<ARRSIZE;i++){
printf("%d,", arr[i]);
}
printf("}");
return 0;
}
void merge_sort (int arr[], int temp[], int left, int right){
if(left<right){
int mid = (right-left)/2;
merge_sort(arr, temp, left, mid);
merge_sort(arr, temp, mid+1, right);
merge(arr, temp, left, mid, right);
}
}
void merge (int arr[], int temp[], int left, int mid, int right){
int i, j, tempi = 0;
for(i=left, j=mid+1; i<=mid && j<=right ;){
// mid+1 is the start of the right array
if(arr[i]<arr[j] && i<=mid){
temp[tempi] = arr[i];
tempi++;
i++;
}
else if(arr[i]>arr[j] && j<=right){
temp[tempi] = arr[j];
tempi++;
j++;
}
}
for(i=0,j=right; i<=j; i++){
arr[i] = temp[i];
}
}
I keep getting a segmentation fault when I run this in my linux shell. Any suggestions?
Well, I've found one subtle bug already: int mid = (right-left)/2; should be int mid = (left+right)/2;
Also, what flows I've found:
You should use tempi = left for simplicity. Simply copy incoming part of array to corresponding part of temporary array.
In your merge cycle, you can place incrementing tempi inside for definition:
for( ...; ...; ++tempi)
Inside that loop you check boundaries AFTER you have read values from that place. This is very bad. VERY. Although, You haven't encounter any problems here just because you are checking boundaries inside for definition :) simply remove them:
for (i = left, j = 1 + mid; i <= mid && j <= right; ++tempi)
{
if (arr[i] < arr[j]) temp[tempi] = arr[i++];
else /* arr[j] <= arr[i] */ temp[tempi] = arr[j++];
}
Cause this loop exits when either subarray has reached end, you have to copy rest of items from another subarray to temp[]:
if (i > mid) i = j; /* if we need to copy right subarray */
for (; tempi <= right; ++tempi, ++i) temp[tempi] = arr[i];
So, your copying back from temporary array will look like
for (i = left; i <= right; ++i) arr[i] = temp[i];

Resources