Segmentation fault on deleting an element after searching it in a heap - c

The following code deletes an element x from a heap after searching it linearly in the heap
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#define MaxSize 100001
struct minheap {
long int a[MaxSize];
int end;
};
void minHeapify(struct minheap *h, int i) {
int largest;
long int temp;
int l=2*i+1;
int r=2*i+2;
largest=i;
if(l<=(h->end) && (h->a[l])<(h->a[i]))
largest=l;
if(r<=(h->end) && (h->a[r])<(h->a[largest]))
largest=r;
if(largest!=i) {
temp=h->a[i];
h->a[i]=h->a[largest];
h->a[largest]=temp;
minHeapify(h,largest);
}
}
int main() {
long int x,i=0,temp=0;
int N;
int type;
scanf("%d",&N);
struct minheap h;
h.end=-1;
while(N--) {
scanf("%d",&type);
if(type==1) {
scanf("%ld",&x);
h.end=h.end+1;
h.a[h.end]=x;
i=h.end;
while(i>0 && h.a[(i-1)/2]>h.a[i]) { //fix minheap on insertion
temp = h.a[(i-1)/2];
h.a[(i-1)/2]=h.a[i];
h.a[i]=temp;
i=(i-1)/2;
}
}
else if(type==2) {
scanf("%ld",&x);
for(i=0;i<=h.end;i++) {
if(x == h.a[i])
break;
}
h.a[i]=h.a[h.end];
h.end=h.end-1;
if(i!=(h.end+1))
minHeapify(&h,i);
}
else if(type==3) {
printf("%ld\n",h.a[0]);
}
}
return 0;
}
But the following test case gives segmentation fault as:
Program terminated with signal SIGSEGV, Segmentation fault.
#0 main () at solution.c:59
59 if(x == h.a[i])
#0 main () at solution.c:59
The entire test case can be found on this link:
https://hr-testcases-us-east-1.s3.amazonaws.com/15379/input04.txt?AWSAccessKeyId=AKIAJ4WZFDFQTZRGO3QA&Expires=1547134261&Signature=D%2B39%2BHr%2F4lRFV%2BetxFwnGWm1iac%3D&response-content-type=text%2Fplain
Why is this segmentation fault occurring?

Given the error message,
> Program terminated with signal SIGSEGV, Segmentation fault.
> #0 main () at solution.c:59 59 if(x == h.a[i])
> #0 main () at solution.c:59
...the value i in the expression: if(x == h.a[i]) is probably out of bounds. This leads to undefined behavior, which in some cases might seem to work, other might lead to a segmentation fault.
Look at this line for a possible the solution:
for(i=0;i<=h.a[h.end];i++)
What is the value of a.end at the time this expression is called?
There is also a potential for problems here:
while(i>0 && h.a[(i-1)/2]>h.a[i])
Where the expression: (i-1)/2 is integer division, and will skip values.

I see a few problems in your code to delete an item:
for(i=0;i<=h.end;i++) {
if(x == h.a[i])
break;
}
h.a[i]=h.a[h.end];
h.end=h.end-1;
if(i!=(h.end+1))
minHeapify(&h,i);
First, if an item with the value you entered is not found, you're going to have trouble because i > h.end. You'll end up either indexing off the end of the array, or deleting the last item.
More importantly, you're not handling the case where the item you replace it with is smaller than the parent. For example, consider this heap:
1
6 2
7 8 3
If you delete the node with value 7, the value 3 replaces it:
1
6 2
3 8
That's not a valid heap. You have to move the 3 up in the heap to create:
1
3 2
6 8
The key here is that if the item you're replacing is in a different subtree than the last item in the heap, it's possible that the replacement node will be smaller than the parent of the replaced node.
So your code has to do this:
h.a[i] = h.a[h.end];
h.end = h.end-1;
// here you have to:
// if (h.a[i] < parentOf(h.a[i]))
// move it up the heap
// else
// minHeapify(&h, i);

Related

need help to find segmentation fault error

can someone help me to find what cause segmentation fault in my program, I used the gdb but I cannot find which line that cause the error.
Array* Merge(Array *arr1, Array *arr2)
{
int i,j,k;
i=j=k=0;
Array *arr3 = (Array*)malloc(sizeof(Array));
arr3->size = arr1->size + arr2->size;
arr3->length = arr1->length + arr2->length;
while(i<arr1->length && j<arr2->length)
{
if(arr1->A[i] < arr2->A[j])
arr3->A[k++]=arr1->A[i++];
else
arr3->A[k++]=arr2->A[j++];
}
for(;i<arr1->length;i++)
arr3->A[k++]=arr1->A[i];
for(;j<arr2->length;j++)
arr3->A[k++]=arr2->A[j];
return arr3;
}
#include <stdio.h>
#include <stdlib.h>
#include "array1.h"
int main()
{
Array arr,arr1,*arr2;
arr.size=10;
arr.length=5;
arr1.size=10;
arr1.length=5;
arr.A=(int*)malloc(arr.size*sizeof(int));
arr1.A=(int*)malloc(arr.size*sizeof(int));
printf("\n enter elements of arr\n");
for (int i=0;i<arr.length;i++)
scanf("%d",&arr.A[i]);
/**********************************************/
printf("\n enter elements of arr1\n");
for (int i=0;i<arr1.length;i++)
scanf("%d",&arr1.A[i]);
arr2=Merge(&arr, &arr1);
display(*arr2);
return 0;
}
here is the result of the gdb
enter image description here
In Merge you don't allocate any space for arr3's data (probably a member called A looking at the other code)
It would help to see the rest of the code (especially the declaration of Array) but I suspect arr3->A is an uninitialised pointer.

Segmentation fault when calling functions recursively

I'm writing a program that prints infinite numbers.
#define false 0
#define true 1
int test(int idx) {
printf("%d\n",idx);
test(idx+1);
return 0;
}
int main() {
test(0);
return 0;
}
// Segmentation fault: 11
This program ended with a segfault after printing 262045.
I understand it is caused by stack overflow.
Is there any clever trick that can make the recursion go deeper?
Like calling another recursive function when it reaches a certain number and clears the stack?
I tried doing this.
#define false 0
#define true 1
int test2(int idx) {
printf("test2 here\n");
printf("%d\n",idx);
test2(idx+1);
return 0;
}
int test(int idx) {
if (idx == 262000) {
return test2(idx);
}
printf("%d\n",idx);
test(idx+1);
return 0;
}
int main() {
test(0);
return 0;
}
But the stack is not cleared. There is still a segfault after printing 262044.
In the first snippet, you're hitting a stac overflow.
In the second case, it invokes UB because of signed integer overflow.

Count occurences of a subarray in a bigger array using recursion

I have to write a recursive function that counts how many times a short array s2 is present in a bigger array s1 without overlapping. I'm allowed to use more than one function that can help me but they have to be all recursive function. For example:
#define n 10
#define p 2
s1[n]={0,2,3,23,54,1,8,23,54,1}
s2[p]={23,54}
OUTPUT: 2 (we see s2 two times in s1)
I thought about writing a recursive function that tells me if there is at least one occurence then use this function in another recursive function that counts the number of occurences. So this is what I wrote:
//Initially pos1=0 and pos2=0
int find(int *s1,int *s2,int pos1,int pos2){
if(n-pos1<p-pos2)
return 0;
if(*(s1+pos1)==*(s2+pos2)){
if(pos2==p-1)
return pos1;
else{
if(find(s1,s2,pos1+1,pos2+1))
return pos1;
}
}
return find(s1,s2,pos1+1,0);
}
Then I wrote the second recursive function that is supposed to count the number of occurences:
// Initially occ(s1,s2,0);
int occ(int *s1,int *s2,int memo){
if(memo==n){ //end of s1
return 0;
}
else{
if(find(s1+memo,s2,memo,0))
return 1+occ(s1+memo,s2,memo+p);
}
}
The idea behind it is to verify if there is at least one occurence if there is an occurence then count it and redo the verification for the remaining part of s1 until the end.
The problem is that the code of the second function doesn't work at all and I can't find a way to fix it.
So how can I write a second recursive function that COUNTS the number of occurences using the function find() written above?
From the OP's comment
It works if s1[n]={0,0,0,3,4,0,0,0,3,4,0,0,0,3,4,0,0,0,3,4}; and s2[p]={3,4}. Indeed the output is 4. But if s2[p]={0,0} the output is 0 which is not correct.
This is because, when s2={0,0} the find() function returns pos1 = 0 as the subset is present at the very beginning and thus in occ() function if(find(s1+memo,s2,memo,0)) evaluates to be false and terminates the function without returning any value and this invokes undefined behavior
This can be avoided by returning any number other than 0 but it must not be the any valid position value in the array s1.
Since position cannot be negative number, I've chosen -1
See the following code to know how to avoid it :
#include <stdio.h>
#define n 10
#define p 2
int s1[n]={0,2,3,23,54,1,8,23,54,1};
int s2[p]={23,54};
//find function
int find(int* s1,int* s2,int pos) //only used `pos` instead of `pos1`, removed `pos2`
{
if(pos > n-2)
{
return -1; //returns `-1` upon reaching the end of the code
}
if(*(s1+pos) == *(s2+0)) //check at `s1+pos`
{
if(*(s1+(pos+1)) == *(s2+1)) //check next element `s1+pos+1`
{
return pos; //if both true return `pos`
}
else
{
return find(s1,s2,pos+1); //else recursively find in the rest of the array
}
}
return find(s1,s2,pos+1); // recursively find in the rest of the array
}
//occurence function
int occ(int *s1, int *s2,int memo)
{
if(memo == -1) //if end of the array, end adding occurrences by returning 0
{
return 0;
}
else
{
memo = find(s1, s2, memo); //scan position into memo
if(memo != -1) //if not end of the array i.e, `-1` add to occurrence
{
return 1+occ(s1,s2,memo+2);
}
else
{
return 0; //else return 0 and recursion would end in next call as memo is -1
}
}
}
//main function
int main(void)
{
printf("%d",occ(s1,s2,0)); //just to see the output
}
output :
2 //true as {23,54} occur two times
when input is : (compile time)
#define n 20
#define p 2
s1[n]={0,0,0,3,4,0,0,0,3,4,0,0,0,3,4,0,0,0,3,4};
s2[p]={0,0};
output :
4 //true as {0,0} occurs at 0,5,10,16

No Input while sorting a stack

There are 3 stacks - A, B, C
Stacks A and B are sorted (the number on the top of the stack is the biggest). Stack C is Empty Only 5 operation are allowed:
push, pop, top, is_empty, create
We need to write a function that receives the stacks A and B, moves all the numbers in stacks A and B to stack C and stack C must be sorted (biggest Number is on top).
I have the algorithm :
>
Compare top of A with top of B
Pop the least element and push to stack C
Repeat step 2 until any of the stack ( A or B) becomes empty
Move remaining elements from non-empty stack to C. Now you have all the elements in C but in ascending order. (That is least element at top).
Move all the elements from C to A. (Contents in A are in descending order)
Move all the elements from A to B. (Contents in B are in ascending order)
Move all the elements from B to C.
And here is the CODE:
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#define MAX_MEMBERS 4
typedef struct
{
int num;
}ITEM;
typedef struct
{
ITEM a[MAX_MEMBERS];
int top;
} STACK;
void create_stack(STACK *s)
{
s->top=-1;
}
int is_empty(STACK *s)
{
return s->top==-1;
}
int is_full(STACK *s)
{
return s->top==MAX_MEMBERS-1;
}
ITEM pop(STACK *s)
{
return s->a[s->top--];
}
void push(STACK *s,ITEM *item)
{
s->a[++s->top]=*item;
}
ITEM top(STACK *s)
{
return s->a[s->top];
}
void sort (STACK *a,STACK *b,STACK *c)
{
int i;
ITEM y,x;
while(!is_empty(a)||!is_empty(b))
{
y=top(a);
x=top(b);
if(&y>&x)
{
push(c,&x);
pop(b);
}
else
{
push(c,&y);
pop(a);
}
}
if(!is_empty(a))
{
while(!is_empty(a))
x=pop(a);
push(c,&x);
}
else
while(!is_empty(b))
{
x=pop(b);
push(c,&x);
}
while(!is_empty(c))
{
x=pop(c);
push(a,&x);
}
while(!is_empty(a))
{
x=pop(a);
push(b,&x);
}
while(!is_empty(b))
{
x=pop(b);
push(c,&x);
}
for(i=0;i<MAX_MEMBERS-1;i++)
printf("%d",c->a[i]);
}
void main(void)
{
int i;
STACK a,b,c;
ITEM x;
create_stack(&a);
create_stack(&b);
create_stack(&c);
for(i=0;i<4;i++)
{
printf("\nEnter a number to insert for A: ");
scanf("%d",&x.num);
push(&a,&x);
}
for(i=0;i<4;i++)
{
printf("\nEnter a number to insert for B: ");
scanf("%d",&x.num);
push(&b,&x);
}
sort(&a,&b,&c);
}
I debugged the code and saw where is the problem ..
it here : if(&y>&x)
It always give a "true" value for this boolean condition ..
even when x
Because you compare addresses of the variables, not variables itself

Having trouble figuring out this segmentation fault

I'm sure the mistake is obvious, but I sure am having trouble finding it.
Basically I am trying to make a chessboard via 2D array. I am testing its functionality via 8 queens test... it is not functional.
Somehow one of my integer values is getting out of whack, as gdb shows:
....
(gdb) cont
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x080487f8 in diagnols (PARAMETER_ONE=0, PARAMETER_TWO=0) at eq1.c:77
77 if (key->board[abc][bcd] == 1) {
(gdb) print abc
4424 // "SHOULD BE" ONE
(gdb) print bcd
4424 // "SHOULD BE" ONE
(gdb) backtrace
#0 0x080487f8 in diagnols (PARAMETER_ONE=0, PARAMETER_TWO=0) at eq1.c:77
#1 0x08048873 in check (param1=0, param2=0) at eq1.c:91
#2 0x08048510 in recur (DEPTH=0, WIDTH=0) at eq1.c:99
#3 0x08048919 in main () at eq1.c:152
(gdb)
Then here is diagnols(...), which is in:
int recur(struct chessboard* key, int DEPTH, int WIDTH) {
/* other functions above diagnols(...) */
diagnols(...):
int diagnols(int PARAMETER_ONE, int PARAMETER_TWO) { // returns 0 if good
int abc = 0;
int bcd = 0;
int counter = 0; // keeps track of conflicting piece occurrences
// OTHER CHECKS FIRST... DELETED TO SAVE ROOM
// checkign diagnol down and to the left
abc = PARAMETER_ONE+1;
bcd = PARAMETER_TWO-1;
while ( (abc>=0)&&(bcd>=0) ) {
if (key->board[abc][bcd] == 1) {
counter++;
} abc++;
bcd--;
}
// ERROR IN THIS PART
// checking diagnol down and to the right
abc = PARAMETER_ONE+1;
bcd = PARAMETER_TWO+1;
while ( (abc>=0)&&(bcd>=0) ) {
if (key->board[abc][bcd] == 1) { // ERROR
counter++;
} abc++;
bcd++;
}
return counter;
}
And diagnols(...) is invoked in recur(...) in the below function:
int check(int param1, int param2) { // if okay returns 2
// other functions
d = diagnols(param1, param2);
int total = 0;
total = (h + v + d); // if okay, equals 2
return total;
}
For good measure here is my struct:
struct chessboard {
int board[7][7];
};
And main:
int main() {
struct chessboard* master = malloc(sizeof(struct chessboard));
/* i set the board to zero here. used calloc() before */
recur(master, 0, 0);
// stuff
}
And yes, I realize diagnol isn't spelled diagonal ;)
while ( (abc>=0)&&(bcd>=0) ) {
if (key->board[abc][bcd] == 1) { // ERROR
counter++;
} abc++;
bcd++;
}
It seems that the condition is going to always be true since you are increasing both indexes.
Did you mean < some limit instead?

Resources