So I have been tasked from school with writing a function that gets an int size parameter, an array of integers and an int flag, and returns an array of pointers, that holds pointers to the cells of the original int array in a sorted manner (ascending if flag==1, else descending).
I wrote it basically on the principle of merge sort, but for some reason I am getting a runtime error that occurs when the program tries to execute line 123 (free a temp int** array)
any idea why it happens and if its fixable?
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#define SIZE 100
int **pointerSort(int *arr, unsigned int size, int ascend_flag);
void ptrMerge(int arr[], int start, int mid, int end, int *ptrArr[], int flag);
void pmergeSort(int arr[], int start, int end, int *ptrArr[], int flag);
void main() {
unsigned int size, i;
int arr[SIZE];
int **pointers;
int ascend_flag;
printf("Please enter the number of items:\n");
scanf("%u", &size);
for (i = 0; i < size; i++)
scanf("%d", &arr[i]);
scanf("%d", &ascend_flag);
pointers = pointerSort(arr, size, ascend_flag);
printf("The sorted array:\n"); //Print the sorted array
//printPointers(pointers, size);
for (i = 0; i < size; i++)
printf("d%\t%d", *pointers[i], pointers[i]);
free(pointers);
}
int **pointerSort(int *arr, unsigned int size, int ascend_flag) {
int **sortedArr;
sortedArr = (int**)malloc(size * sizeof(int*));
pmergeSort(arr, 0, size - 1, sortedArr, ascend_flag);
return sortedArr;
}
void pmergeSort(int arr[], int start, int end, int *ptrArr[], int flag) {
if (start < end) {
int mid = (start + end) / 2;
pmergeSort(arr, start, mid, ptrArr, flag);
pmergeSort(arr, mid + 1, end, ptrArr, flag);
ptrMerge(arr, start, mid, end, ptrArr, flag);
}
}
void ptrMerge(int arr[], int start, int mid, int end, int *ptrArr[], int flag) {
int i, k = 0;
int p = start, q = mid + 1;
int **tempArr;
tempArr = (int**)malloc((end - start + 1) * sizeof(int*));
for (i = start; i <= end; i++) {
if (arr[p] < arr[q]) {
tempArr[k] = &arr[p];
k++;
p++;
} else { //(arr[p] > arr[q])
tempArr[k] = &arr[q];
k++;
q++;
}
}
while (p <= mid) {
tempArr[k] = &arr[p];
k++;
p++;
}
while (q <= end) {
tempArr[k] = &arr[q];
k++;
p++;
}
if (flag == 1) {
for (i = 0; i < k; i++)
ptrArr[start] = tempArr[i];
start++;
}
} else {
for (i = k - 1; i >= start; i--) {
ptrArr[start] = tempArr[i];
start++;
}
}
for (i = 0; i < k; i++)
printf("%x\t%d\n", ptrArr[i], *ptrArr[i]);
printf("\n");
free(tempArr);
}
You get a segmentation fault because the ptrMerge function corrupts the memory by writing past the end of the tempArr allocated array.
The first loop iterates end - start + 1 times, potentially accessing arr beyond the end of the slices.
The loop continues until p >= mid and q >= end, writing to tempArr[k] with k greater or equal to the number of elements allocated with malloc().
The logic is flawed: you compare the elements of arr at offsets p and q instead of indirecting through the array ptrArr.
Here is a modified version:
int **pointerSort(int *arr, int size, int ascend_flag) {
int **sortedArr = (int**)malloc(size * sizeof(int*));
for (int i = 0; i < size; i++) {
sortedArr[i] = &arr[i];
}
pmergeSort(sortedArr, 0, size - 1, ascend_flag);
return sortedArr;
}
void pmergeSort(int *ptrArr[], int start, int end, int flag) {
if (start < end) {
int mid = start + (end - start) / 2;
pmergeSort(ptrArr, start, mid, flag);
pmergeSort(ptrArr, mid + 1, end, flag);
ptrMerge(ptrArr, start, mid, end, flag);
}
}
void ptrMerge(int *ptrArr[], int start, int mid, int end, int flag) {
int i, k, n = end - start + 1;
int p = start, q = mid + 1;
int **tempArr = (int**)malloc(n * sizeof(int*));
for (k = 0; k < n; k++) {
if (p <= mid && (q >= end || *ptrArr[p] <= *ptrArr[q])) {
tempArr[k] = ptrArr[p++];
} else {
tempArr[k] = ptrArr[q++];
}
}
if (flag == 1) {
for (k = 0; k < n; k++)
ptrArr[start + k] = tempArr[k];
}
} else {
for (k = 0; k < n; k++) {
ptrArr[end - k] = tempArr[k];
}
}
free(tempArr);
}
Also note that main() must be defined with a return type int and the loop that prints the values is broken. It should read:
for (i = 0; i < size; i++)
printf("%d\t", *pointers[i]);
printf("\n");
So you should use :
int main(void)
In this while q is never updated so i guess infinite loop?
while (q <= end)
{
tempArr[k] = &arr[q];
k++;
p++;
}
Can you provide me your inputs and output you want?
I have tried your code and i'm not getting your error.
Related
Hi i wanted to tranform this code into a recursive function:
int a3(int* a, int length) {
if(a == 0 || length <= 0) return 0;
int sum = 0;
for(int i = 0; i < length; i++) {
for(int j = i; j < length; j++) {
sum += a[j];
}
}
return sum;
}
My approach is :
int rec_help(int*a, int length);
int a3(int* a, int length) {
if(a == 0 || length <= 0) return 0;
else{
return rec_help(a,length) + rec_help(a+1,length-1) ;
}
}
int rec_help(int*a, int length){
if(a == 0 || length <= 0) return 0;
else{
int tmp = a[0];
return tmp + a3(a+1,length-1);
}
}
But i'm not getting it right.
With a3() i wanted to simulate the first for loop, and i think there is my problem :D
And with rec_help() the second loop and the body, but im mixing things here.
I would appreciate any kind of help :)
Because you have 2 loop, if you want your function to be recursive, you will need 2 recursive functions, one which will do the job of the first loop and a second to do the job of your second loop...
Something like that should work :
int a3_rec(int *a, int length)
{
if (length == 0)
return (0);
return (*a + a3_rec(a + 1, length - 1));
}
int a3_rec_hat(int *a, int length)
{
if (a == 0 || length == 0)
return (0);
return (a3_rec(a, length) + a3_rec_hat(a + 1, length - 1));
}
I hope I've helped you :)
As a general rule, when you transform loops into recursion, every loop becomes a function and any non-local variables it uses become arguments.
Your original code is
int a3(int* a, int length) {
if(a == 0 || length <= 0) return 0;
int sum = 0;
for(int i = 0; i < length; i++) {
for(int j = i; j < length; j++) {
sum += a[j];
}
}
return sum;
}
Let's start with the innermost loop. It uses j, i, length, sum, and a from the surrounding scope.
void a3_loop0(int *pj, int length, int *psum, int *a) {
if (*pj < length) {
*psum += a[*pjj];
(*pj)++;
a3_loop0(pj, length, psum, a);
}
}
int a3(int* a, int length) {
if(a == 0 || length <= 0) return 0;
int sum = 0;
for(int i = 0; i < length; i++) {
int j = i;
a3_loop0(&j, length, &sum, a);
}
return sum;
}
This is a very literal and mechanical translation. Every mutable variable has become a pointer (in C++ you'd use references for this), which leads to somewhat ugly and non-functional code (well, code that doesn't use idiomatic functional style). But it works, and we can proceed to the next loop in the same way:
void a3_loop0(int *pj, int length, int *psum, int *a) {
if (*pj < length) {
*psum += a[*pj];
(*pj)++;
a3_loop0(pj, length, psum, a);
}
}
void a3_loop1(int *pi, int length, int *psum, int *a) {
if (*pi < length) {
int j = *pi;
a3_loop0(&j, length, psum, a);
(*pi)++;
a3_loop1(pi, length, psum, a);
}
}
int a3(int* a, int length) {
if(a == 0 || length <= 0) return 0;
int sum = 0;
int i = 0;
a3_loop1(&i, length, &sum, a);
return sum;
}
Technically we're done now, but there's a number of things we can clean up.
The first thing I'd do is to change the type of a to const int * because a3 never modifies any of its elements.
The second thing I'd do is to hoist the loop variables *pi / *pj into their functions; they don't really need to be pointers to mutable objects elsewhere.
void a3_loop0(int j, int length, int *psum, const int *a) {
if (j < length) {
*psum += a[j];
a3_loop0(j + 1, length, psum, a);
}
}
void a3_loop1(int i, int length, int *psum, const int *a) {
if (i < length) {
a3_loop0(i, length, psum, a);
a3_loop1(i + 1, length, psum, a);
}
}
int a3(const int *a, int length) {
if (a == 0 || length <= 0) return 0;
int sum = 0;
a3_loop1(0, length, &sum, a);
return sum;
}
This already simplifies and shortens the code a bit.
The next step is to actually return something from these helper functions. Currently they use *psum as an accumulator and return void. We can keep the use of an accumulator but return the result directly (instead of through an output parameter) as follows:
void a3_loop0(int j, int length, int sum, const int *a) {
if (j < length) {
return a3_loop0(j + 1, length, sum + a[j], a);
}
return sum; // this was implicit before; "return sum unchanged"
}
void a3_loop1(int i, int length, int sum, const int *a) {
if (i < length) {
return a3_loop1(i + 1, length, a3_loop0(i, length, sum, a), a);
}
return sum; // ditto
}
int a3(const int *a, int length) {
if (a == 0 || length <= 0) return 0;
return a3_loop1(0, length, 0, a);
}
This version of the code is "purely functional" in that it never modifies any variables; it only passes and returns values to and from functions, respectively.
If we wanted to, we could get rid of all if statements and write everything as expressions:
void a3_loop0(int j, int length, int sum, const int *a) {
return j < length
? a3_loop0(j + 1, length, sum + a[j], a)
: sum;
}
void a3_loop1(int i, int length, int sum, const int *a) {
return i < length
? a3_loop1(i + 1, length, a3_loop0(i, length, sum, a), a)
: sum;
}
int a3(const int *a, int length) {
return a == 0 || length <= 0
? 0
: a3_loop1(0, length, 0, a);
}
I'll post this because I see the other answers use 1 function per loop which isn't necessary.
You can have just 1 recursive function:
int a3_impl(int* a, int length, int i, int j)
{
if (i >= length)
return 0;
if (j >= length)
return a3_impl(a, length, i + 1, i + 1);
return a[j] + a3_impl(a, length, i, j + 1);
}
int a3(int* a, int length)
{
if(a == 0 || length <= 0)
return 0;
return a3_impl(a, length, 0, 0);
}
While trying to write a code to find the intersection of two arrays,I came across a problem. I can't seem to modify a pointer inside a function.
Inside my find_intersection I get the error while doing the realloc function,compiler states that "counter" has no arithmetic value.
Any explanation on what went wrong here?
#include <stdio.h>
#include <stdlib.h>
int quick_sort(int*, int, int);
void swap(int*, int*);
int partition(int *, int, int);
int input_array_dyn(int*n);
int *find_intersection(int*, int*, int*, int, int,int *);
main()
{
int size1, size2, *counter, i=0;
int *arr1 = input_array_dyn(&size1);
int *arr2 = input_array_dyn(&size2);
quick_sort(arr1, 0, size1 - 1);
quick_sort(arr2, 0, size2 - 1);
int *arr3 = (int*)calloc(size2, sizeof(int));
arr3= find_intersection(arr1, arr2, arr3, size1, size2, &counter);
printf("The size of the new array is:%d\n", counter);
while (i < counter)
{
printf("%d\n", arr3[i]);
i++;
}
free(arr1);
free(arr2);
free(arr3);
}
int *find_intersection(int *arr1, int *arr2, int *arr3, int SA, int SB, int *counter)
{
int i = 0, j = 0, n = 0;
*counter = 0;
while (i < SA &&j < SB)
{
if (arr1[i] < arr2[j])
i++;
else if (arr2[j] < arr1[i])
j++;
else
{
arr3[n] = arr1[i];
i++;
n++;
j++;
}
}
counter = n;
arr3 = (int*)realloc(arr3, counter*sizeof(int));/*error here*/
return arr3;
}
int input_array_dyn(int*n)
{
int i;
int *a;
printf("Enter the size of the array:\n");
scanf("%d", n);
a = (int*)calloc(*n, sizeof(double));
assert(a);
printf("Enter the array elements:%d.\n", *n);
for (i = 0; i < *n; i++)
scanf("%d", a + i);
return a;
}
void swap(int* a, int* b)
{
int t = *a;
*a = *b;
*b = t;
}
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);
}
int quick_sort(int *arr, int low, int high)
{
if (low < high)
{
int pi = partition(arr, low, high);
quick_sort(arr, low, pi - 1);
quick_sort(arr, pi + 1, high);
}
}
In find_intersection() counter is a pointer to an int. To change it's value you need to use *counter instead of counter.
return arr3; attempts to return a pointer to int while function is declared to return just int. counter is a pointer to an int while you are using it as an regular int setting to 0 and so on.
I'm junior in C language and algorithms.
I try to use recursion for binary search and I can't understand how to check if number doesn't exist in array.
Here my code:
#include <stdio.h>
#define SIZE 15
#define midpoint(start, end) (start + end) / 2
void fill_array(int array[]);
int find(int target, int array[], int start, int end);
int main() {
int array[SIZE];
fill_array(array);
return find(2, array, 0, SIZE);
}
void fill_array(int array[]) { //here I just fill array
for (int i = 0, number = 0; i <= SIZE; ++i) {
array[i] = number++;
number++;
}
}
int find(int target, int array[], int start, int end) {
int mid;
mid = midpoint(start, end);
if (target > array[mid]) {
find(target, array, mid + 1, end);
}
if (target < array[mid]) {
find(target, array, start, mid - 1);
}
if (target == array[mid]) {
printf("%d\n", mid);
}
}
I want to return (-1) if number doesn't exist in array.
There are multiple issues in your code:
Defining midpoint() as a macro is error prone. Your definition is not properly parenthesized, it should read:
#define midpoint(start, end) (((start) + (end)) / 2)
Written as half the sum, it actually would invoke undefined behavior for large values of start and end, a much safer version would be start + (end - start) / 2, but should not be used in a macro as it evaluates start twice. Just write the code in the function directly.
Your initialization function iterates one step too far, the loop should read:
for (int i = 0, number = 0; i < SIZE; i++) {
array[i] = number;
number += 2;
}
find() should indeed return the index of the value found or -1 if not found. You do not return anything. make it return -1 upon failure and the value of the recursive call when recursing.
the arguments to find are start, the starting index of the range, included in the search, and end the upper bound, excluded from the search. You should not pass mid - 1 when recursing on the left part.
Here is a corrected version:
#include <stdio.h>
#define SIZE 15
void fill_array(int array[], int size) {
// here I just fill array with even numbers
for (int i = 0, number = 0; i < SIZE; i++) {
array[i] = number;
number += 2;
}
}
int find(int target, const int array[], int start, int end) {
if (start >= end) {
// empty range: not found
return -1;
}
int mid = start + (end - start) / 2;
if (target == array[mid]) {
return mid;
}
if (target > array[mid]) {
return find(target, array, mid + 1, end);
} else {
return find(target, array, start, mid);
}
}
void locate(int value, const int array[], int size) {
int res = find(value, array, 0, size);
if (res < 0) {
printf("%d was not found in the array\n", value);
} else {
printf("%d was found at offset %d\n", value, res);
}
}
int main(void) {
int array[SIZE];
fill_array(array, SIZE);
locate(1, array, SIZE);
locate(2, array, SIZE);
return 0;
}
Output:
1 was not found in the array
2 was found at offset 1
Note that find() can be implemented as a loop with less code:
int find(int target, const int array[], int start, int end) {
while (start < end) {
int mid = start + (end - start) / 2;
if (target == array[mid]) {
return mid;
}
if (target > array[mid]) {
start = mid + 1;
} else {
end = mid;
}
}
return -1;
}
I have written a BinarySearch C code for you to inspect and see where is your problem.
This part: int BinarySearch is doing BinarySearch via loops,
This part: int BinarySearchRec is doing BinarySearch via recursion.
#include <stdio.h>
#include <stdlib.h>
int BinarySearch(int*,int,int);
int BinarySearchRec(int*,int,int,int);
int main(void){
int length;
int searchElement;
int* list;
printf("Enter the length of the list\n");
scanf("%d",&length);
list = malloc(length*sizeof(int));
printf("Enter the search element for this list");
scanf("%d",&searchElement);
printf("Enter the elements for this list\n");
for(int i=0;i<length;i++){
scanf("%d",list+i);
}
int result1 = BinarySearch(list,length,searchElement);
int result2 = BinarySearchRec(list,0,length-1,searchElement);
printf("Result from loopy BinarySearch : %d\n",result1);
printf("Result from recursive BinarySearch: %d\n",result2);
return 0;
}
int BinarySearch(int* list, int length, int searchElement){
int found=0;
int min = 0;
int max = length-1;
int mid=0;
while(found != 1 && max > min){
mid = (max+min)/2;
if(searchElement == list[mid]){
found = 1;
}else if(searchElement > list[mid]){
min = mid+1;
}else if(searchElement < list[mid]){
max = mid;
}
}
if(max > min){
return mid;
} else{
return -1;
}
}
int BinarySearchRec(int* list,int min,int max,int searchElement){
int mid = (min+max)/2;
if(max > min){
if(searchElement == list[mid]){
return mid;
}else{
if(searchElement < list[mid]){
return BinarySearchRec(list,min,mid,searchElement);
}else if(searchElement > list[mid]){
min = mid+1;
return BinarySearchRec(list,mid+1,max,searchElement);
}
}
}else{
return -1;
}
}
I have been taking a class at Coursera and we had an assignment which was to count the number of comparisons QuickSort does on a 10,000 size array a numbers.
#include <stdio.h>
#define SIZE 10000
int ComparsionCount = 0;
void swap(int a[], int i, int j) {
int temp = a[j];
a[j] = a[i];
a[i] = temp;
}
int partition(int a[], int l, int r){
int p = a[l];
int i = l + 1;
int j;
for (j = l + 1; j <= r; j++) {
if (a[j] < p) {
swap(a, j, i);
i++;
}
}
swap(a, l, i - 1);
return (i - 1);
}
void add(int i) {
ComparsionCount += i;
}
int QuickSort(int a[], int l, int r){
int pivot;
if (r > 1) {
add(r - 1);
pivot = partition(a, l, r);
QuickSort(a, l, pivot - 1);
QuickSort(a, pivot + 1, r);
}
return pivot;
}
int main() {
FILE *fr;
int arr[SIZE];
int i = 0;
int elapsed_seconds;
char line[80];
fr = fopen("QuickSort.txt", "r");
while (fgets(line, 80, fr) != NULL)
{
/* get a line, up to 80 chars from fr. done if NULL */
sscanf (line, "%ld", &elapsed_seconds);
/* convert the string to a int */
arr[i] = atoi(line);
i++;
}
fclose(fr); /* close the file prior to exiting the routine */
printf("%d\n",QuickSort(arr,0,SIZE-1));
}
I am getting an segmentation error. I have identified that the problem lies in two recursive calls of QuickSort.
I have no idea of how to solve this problem,your help would be appreciated a lot
Thanks in advance.
I think you should add the code in the partition function like this:
for (j = l + 1; j <= r; j++) {
count++;
if (a[j] < p) {
...
}
Note: count is a global variable initialized to 0.
I try to write in c the quick sort with pivot the middle element of array.
But my program doesn't appear always the right results.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define SIZE 10 /*max size of array*/
void QuickSort(int [], int, int);
int Partition(int [], int, int);
void Swap(int *,int *);
int main()
{
srand(time(NULL));
clock_t begin,end;
double time_spend;
begin = clock();
int A[SIZE];
int i;
for(i = 0; i < SIZE; i++) /*full array with numbers 1...100*/
A[i] = rand() % (100 - 1 + 1) + 1;
printf("[");
for(i = 0; i < SIZE; i++) /*print original array*/
printf("%d,",A[i]);
printf("\b]\n");
QuickSort(A,0,SIZE - 1); /*start sorting array*/
printf("\n------After Quick Sorting-----\n");
printf("\n[");
for(i = 0; i < SIZE; i++) /*print sorted array*/
printf("%d,",A[i]);
printf("\b]\n");
end = clock();
time_spend = (double)(end - begin) / CLOCKS_PER_SEC;
printf("Elapsed: %f second\n",time_spend);
return 0;
}
/*recursive function sorting array*/
void QuickSort(int A[], int start, int end)
{
int i,q;
if(start < end)
{
q = Partition(A,start,end); /*partition array*/
QuickSort(A,start,q - 1); /*recursive first half of array*/
QuickSort(A,q + 1,end); /*recursive second half of array*/
}
}
/*function partition with pivot the middle element*/
int Partition(int A[],int start,int end)
{
int x,i,j;
x = A[(end + start) / 2];
j = start;
i = end;
while(j < i)
{
while(A[j] < x)
j++;
while(A[i] > x)
i--;
if(j < i)
{
Swap(&A[j],&A[i]);
j++;
i--;
}
}
return i;
}
/*function exchange elements*/
void Swap(int* a,int* b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
I have try to change in function partition the epuals, but i can't fix the problem.
In your partition function, you need to consider the case where a[j]==x and the case where a[i]==x. In this case you can't just swap them and carry on as normal. Go through it on paper and you'll see the error. An example where this happens - consider the array: 1 3 4 5 2