Segmentation error but I don't know why - c

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define MAX_SIZE 100
I am trying to quicksort an array of 2D points based upon their distance from the origin but my code hits a Seg fault after the first scanf.
typedef struct point{
double x;
double y;
double dist;
} point;
void sortpoints(point arr[], int low, int high);
void printpoints(point arr[], int n);
Sortpoints is just a manipulation of a quicksort in ordering an array of Point structs depending on the value of Point.dist
void sortpoints(point arr[], int low, int high){
int piv, i, j;
piv = low;
i = low;
j = high;
point box;
if(low < high){
while(i<j){
while((arr[i].dist)<=(arr[piv].dist) && i<= high)
i++;
}
while((arr[j].dist) > (arr[piv].dist) && j>= low)
j--;
}
if(i<j){
box = arr[i];
arr[i] = arr[j];
arr[j] = box;
}
box = arr[j];
arr[j] = arr[piv];
arr[piv] = box;
sortpoints(arr, low, j-1);
sortpoints(arr, j+1, high);
}
Printpoints just prints the points in order of their distances from the origin
void printpoints(point arr[], int n){
int i; for(i = 0; i <= n; i++){
printf("(%.2lf, %.2lf)\n", arr[i].x, arr[i].y);
}
}
The user enters the number of points and value of the points in the form (point.x, point.y)
int main(){
point pointa;
point pointarray[MAX_SIZE];
int n=0;
printf("how many points would you like to enter?\n");
scanf("%d", &n);
if(n<MAX_SIZE){
int i;
for(i=0; i<n ; i++){
scanf("(%lf,%lf)", &pointa.x, &pointa.y);
pointa.dist = sqrt(pointa.x*pointa.x + pointa.y*pointa.y);
pointarray[i] = pointa;
}
sortpoints(pointarray, 0, n-1);
printpoints(pointarray, n);}
else{
printf("sorry, not a valid array size\n");
}
return 0;
}

I've got stack overflow.
Your program calls function sortpoints, and calls itself too (sortpoints calls sortpoints). But i cant see where sortpoints must stop!
As a result, j-1 goes under null, and arr[j] is not valid at all.

When I changed this line:
scanf("(%lf,%lf)", &pointa.x, &pointa.y);
To this:
scanf("%lf,%lf", &pointa.x, &pointa.y);
The point values were actually being read in, with the parens there nothing gets read in, I don't see anything in the documentation on scanf about this though, is anyone familiar with this?
You sorting code seems to go into infinite recursion and cause a stack overflow however.

Your issue is with your braces. I have reformatted your sortpoints function slightly so it is clearer where each basic block actually is.
void sortpoints(point arr[], int low, int high){
int piv, i, j;
piv = low;
i = low;
j = high;
point box;
if(low < high){
while(i<j){
while((arr[i].dist)<=(arr[piv].dist) && i<= high)
i++;
}
while((arr[j].dist) > (arr[piv].dist) && j>= low)
j--;
}
if(i<j){
box = arr[i];
arr[i] = arr[j];
arr[j] = box;
}
box = arr[j];
arr[j] = arr[piv];
arr[piv] = box;
sortpoints(arr, low, j-1);
sortpoints(arr, j+1, high);
}
It should be evident now that your segfault is the result of accidental infinite recursion. This is a good argument for using { } for your loops, even with a single statement.

Related

Merge sort not printing sorted array

My code here gets terminated after printing the unsorted array and also gives runtime error on ideone , i am unable to find the error in it . code works fine until the first mergesort in function but gets terminated afterwards without executing merge function . I have tried changing array size but nothing has worked so far . Any help would be appreciated.
#include<stdio.h>
#include<math.h>
void Merge(int arr[],int,int,int,int);
void printArray(int *arr,int n)
{
for (int i = 0; i < n; i++)
{
printf("%d",arr[i]);
printf(" ");
}
printf("\n");
}
void MergeSort(int arr[],int low,int high)
{
int mid;
if(low<high)
{
mid = ceil((low+high)/2);
MergeSort(arr,low,mid-1);
MergeSort(arr,mid,high);
Merge(arr,low,mid-1,mid,high);
}
}
void Merge(int arr[],int low,int mid1,int mid2, int high)
{
int i,c,j;
c = low;
i = low;
j = mid2;
int Temp[high-low+1];
while(i <= mid1 && j<= high)
{
if(arr[i]<arr[j])
{
Temp[c] = arr[i];
i++;
c++;
}
else
{
Temp[c] = arr[j];
j++;
c++;
}
}
while(i<=mid1)
{
Temp[c] = arr[i];
i++;
c++;
}
while(j<=high)
{
Temp[c] = arr[j];
j++;
c++;
}
for(int k=0;k<=high;k++)
{
arr[k] = Temp[k];
}
}
int main(void)
{
int arr[] = {3,5,2,13,12,3,2,13,45};
int n = sizeof(arr)/sizeof(arr[0]);
printf("unsorted array: \n");
printArray(arr,n);
MergeSort(arr,0,n-1);
printf("sorted array: \n");
printArray(arr,n);
return 0;
}
There are several issues:
ceil is not useful as / will perform an integer division and so has already rounded down
Related to this, you should not use mid-1 and mid as arguments in the next recursive calls, but mid and mid+1. The same should be done with the arguments to Merge.
The way you access Temp is wrong. You allocate entries from 0 to high-low, but start your access with a value of c that is low. You should instead start at index 0.
In the very last loop k runs from 0 to high, but that are too many iterations. It should start from low, and then the index access to Temp should again be adapted by using k-low as index.
Here is the corrected code:
void MergeSort(int arr[],int low,int high)
{
int mid;
if(low<high)
{
mid = (low+high)/2; // <--
MergeSort(arr,low,mid); // <--
MergeSort(arr,mid+1,high); // <--
Merge(arr,low,mid,mid+1,high); // <--
}
}
void Merge(int arr[],int low,int mid1,int mid2, int high)
{
int i,c,j;
c = 0; // <--
i = low;
j = mid2;
int Temp[high-low+1];
while(i <= mid1 && j<= high)
{
if(arr[i]<arr[j])
{
Temp[c] = arr[i];
i++;
c++;
}
else
{
Temp[c] = arr[j];
j++;
c++;
}
}
while(i<=mid1)
{
Temp[c] = arr[i];
i++;
c++;
}
while(j<=high)
{
Temp[c] = arr[j];
j++;
c++;
}
for(int k=low;k<=high;k++) // <--
{
arr[k] = Temp[k-low]; // <--
}
}
Important note: I debugged the code for you, but this is something you can do yourself. Inspect the variables as you step through the code with a debugger, and spot where things are unexpected. It takes some time, but it is a skill a coder needs to learn.

My quicksort implementation gives wrong result

today I've been working on Quicksort algorithm implementation in C.
I thought that I've fully understood the issue, but after few attempts, the results weren't the same as I expected. I ask you for help in finding problem, because I can't find it on myself, I've even tried to look at another implementations in internet, and rewriting my functions, but nothing worked.
My code:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void swap(int *x, int *y)
{
int temp = *y;
*x = *y;
*y = temp;
}
void printArray(int arr[], int size)
{
for(int i = 0; i < size; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
int partition(int arr[], int low, int high)
{
int pivot = arr[high];
int i = (low - 1);
for(int j = low; j <= high-1; j++)
{
if(arr[j] <= pivot)
{
i++;
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i+1], &arr[high]);
return(i+1);
}
void quickSort(int arr[], int low, int high)
{
if(low < high)
{
int pi = partition(arr, low, high);
quickSort(arr, low, pi-1);
quickSort(arr, pi + 1, high);
}
}
int main()
{
srand(time(NULL));
int arr[10];
for(int i = 0; i < 10; i++)
{
arr[i] = rand()%200 - 100;
}
printArray(arr, 10);
quickSort(arr, 0, 9);
printArray(arr, 10);
return 0;
}
Examplatory results:
-57 4 -30 -23 25 -67 83 26 -51 14
-67 -67 -51 -67 -51 -51 14 -51 14 14
The only problem with your quick-sort is that the swap function is not implemented correctly.
The correct implementation should be something like:
void swap(int *x, int *y) {
int temp = *x;
*x = *y;
*y = temp;
}
You may be interested in looking at some other quick-sort variant, for that see this.
A humble suggestion: Use Randomized Quick sort: It would also be better if you don't always select the last element as your pivot (what you can do here is just before starting to sort select any random element and then swap it with the last element of your array. Using this strategy you don't have to make much changes in your existing code) This selection of random element as pivot is much better. See this link for more details.

Quick sort recursive function in C - doesn't work with big number of elements

Has this function been written correctly?
It seems that something is wrong when I try to run the function with a large number of elements in the array (eg 1000).
Then its appears to stop.
int quick_sort(int n, int tablica[],int b, int a)
{
if(a==n-1 || n==0) return;
if(b==n-1)
{
b=0;
a++;
}
if(tablica[b]>tablica[b+1])
{
bufor=tablica[b];
tablica[b]=tablica[b+1];
tablica[b+1]=bufor;
}
b++;
return quick_sort(n,tablica,b,a);
}
Above code will not work even for a small array, unless the small array is unsorted in a particular way. It compares one element with the next element. If the array is say {4,3,8,7,1} the sort will fail, because it has no mechanism to push 1 to the start of the array.
For larger arrays there are too many recursion and the program hits the stack limit and simply fails.
You can use recursion in quicksort but the number of recursions has to be kept in check. For example for array of size 1000 you don't want to have to more than 1000 recursion. Example:
void swap(int* a, int* b)
{
int t = *a;
*a = *b;
*b = t;
}
void quicksort(int arr[], int low, int high)
{
if(low < high)
{
int pivot = arr[high];
int i = (low - 1);
for(int j = low; j <= high - 1; j++)
{
if(arr[j] <= pivot)
{
i++;
swap(&arr[i], &arr[j]);
}
}
swap(&arr[i + 1], &arr[high]);
int pi = i + 1;
quicksort(arr, low, pi - 1);
quicksort(arr, pi + 1, high);
}
}
int main()
{
int arr[] = { 7,3,6,1,4,8,9,2 };
int arrsize = sizeof(arr) / sizeof(*arr);
quicksort(arr, 0, arrsize - 1);
for(int i = 0; i < arrsize; i++)
printf("%d\n", arr[i]);
return 0;
}

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];

QuickSort doesn't work for large inputs

Can anyone spot a problem with my quick sort implementation below? It seems to fail on arrays with more than 10 or so elements.
void swap(int *p1, int *p2)
{
int temp = *p1;
*p1 = *p2;
*p2 = temp;
}
void generateRandom(int arr[], int size)
{
srand(time(NULL));
int i;
for (i = 0; i < size; i++)
{
arr[i] = rand() % 100;
}
}
int partition(int arr[], int start, int end)
{
int i = start, j = end;
int pivot = arr[start];
for (;;)
{
for (; arr[i] < pivot; i++);
for (; arr[j] > pivot; j--);
if (i < j)
{
swap(&arr[i], &arr[j]);
}
else
{
return j;
}
}
}
void quickSort(int arr[], int start, int end)
{
int part;
if (start < end)
{
part = partition(arr, start, end);
quickSort(arr, start, part);
quickSort(arr, part + 1, end);
}
}
int main()
{
generateRandom(arr, 100);
for (i = 0; i < 100; i++)
{
printf("%d ", arr[i]);
}
printf("\n\n");
quickSort(arr, 0, 99);
for (i = 0; i < 100; i++)
{
printf("%d ", arr[i]);
}
printf("\n\n");
return 0;
}
First, you code doesn't compile. When I made the corrections to make it compile (adding stdio.h, and definitions for arr and i in main) it infinite looped, which it will do if the partition starts and ends with the pivot. You need to increment and decrement before the comparisons rather than after. You can do that by starting with i = start-1 and j = end+1 and changing your inner loops to increment or decrement first, or you can leave them as is and just do an i++ and j-- after the swap -- I did that and the sort works.
Note that your pivot choice is poor for already sorted arrays; you really should be picking the median of 3 or even 9 values.
P.S. Other desirable optimizations: 1) Switch to an insertion sort for small partitions -- the optimal cutoff point is machine-dependent. Another approach is to not sort partitions below a certain size, and then do an insertion sort on the whole array after quicksort is done. It's also possible to use heapsort instead of insertion sort if done carefully; google introsort. 2) quicksort does two recursive calls; eliminate the second one by setting start = part + 1 and looping. 3) Avoid the possibility of stack overflow by quicksorting the larger partition first. 4) Eliminate the first recursive call by using an explicit stack. 5) Inline swap() and partition(). 6) Don't bother with any of that and just call the qsort library routine. :-)
I had the same problem,
but I changed my while loop to do..while and it worked.
This is my new code now.
int partition(int a[], int lo, int hi) {
int v = a[lo], i = lo, j = hi;
do {
do {
i++;
} while(a[i] < v) ;
do {
j--;
}while(a[j] > v) ;
if(i < j) interchange(&a[i], &a[j]);
}while(i < j);
interchange(&a[lo], &a[j]);
return j;
}

Resources