-1

Yesterday I was solving a problem called At The Gates in code chef. I wrote some code in C with no errors in syntax, as the code got compiled with zero warnings and errors.

The code runs fine for the first test case, but gives an segmentation fault error for the second test.

when I debug it, it shows the segmentation fault is due to the code line

if(a[N-1]=='H');

Debugger output:

Program received signal SIGSEGV, Segmentation fault. 0x00000000004006d4 in main ( ) at main.c: 15

Please help me rectify and correct the code.

#include<stdio.h>
void main(){
    int T;

    scanf("%d",&T);
    while(T!=0){
        int N=0,K,count=0,i;
        scanf("%d%d",&N,&K);
        char a[200];
        for(i=0;i<N;i++){
            scanf("%c",&a[i]);
        }

        while(K--){
            if(a[N-1]=='H'){
                N--;
                for(i=0;i<N;i++){
                    if(a[i]=='H'){
                        a[i]=='T';
                    }
                    if(a[i]=='T'){
                        a[i]=='H';
                    }
                }
            }
            else{
                N--;
            }

        }

        for(i=0;i<N;i++){
            if(a[i]=='H'){
                count=count+1;
            }
        }
        printf("%d\n",count);
        T=T-1;
}

}

2 Answers2

1

Along with other suggestions mentioned in the comments like -

  1. Changing main signature to return int
  2. Update a[i]=='T'; and a[i]=='H'; to remove double equals warning inside if blocks (simply replacing == by = would be logically incorrect, see @CiaPan's answer below)

you also have to update scanf statement - scanf("%c",&a[i]); to scanf(" %c",&a[i]); (note the extra space at the beginning before %c)

This should solve the segmentation fault issue.

See this and this for details -

%d automatically eats whitespaces and special characters since whitespaces and special characters are characters, not numbers! However, %c has to interpret whitespaces and special characters as inputs, because %c reads characters.

Explanation -

On adding few printf statements in the program like below to check the input received, we can see what happens -

        int N=0,K,count=0,i; // N initialized to 0, but not K
        printf("Before scan N=%d, K=%d\n", N, K);
        i=scanf("%d%d",&N,&K);
        char a[200];
        printf("After scan-\n N=%d, K=%d, Scanf return value=%d\n", N, K, i);
        for(i=0;i<N;i++){
            scanf("%c",&a[i]);
        }
        for(i=0;i<N;i++){
            printf("%d=>'%c', ",i, a[i]);
        }
        printf("\n");

with input -

3
5 3
H T T H T
7 4
H H T T T H H
6 1
T H T H T T

The output of whole program looks something like this -

Before scan N=0, K=1362879360
After scan-
 N=5, K=3, Scanf return value=2   <------ 2 VALUES SUCCESSFULLY READ
0=>'
', 1=>'H', 2=>' ', 3=>'T', 4=>' ',
Program output - 1
Before scan N=0, K=-1
After scan-
 N=0, K=-1, Scanf return value=0 <------ 0 VALUES SUCCESSFULLY READ (problem)

exited, segmentation fault

As mentioned by @CiaPan in the comment, %c consumes each character, even spaces and newlines in the array, but leaving part of the input line H T T H T in the input buffer. Since N and K are positive and N greater than K in the first loop, the second while loop terminates.

During second iteration of main loop (test case), N is initialized to 0 and K has value -1 from the first loop iteration. Since leftover data from input buffer cannot be assigned correctly to N and K, they continue with this value.

Now for second while loop (test case), K starts negative, so the condition while(K--) stays correct for unexpected long time (until K is zero after wrapping at integer boundary), and N keeps decreasing as well. Eventually for some large negative value of N, the program tries to access inaccessible memory (with a[N-1]), leading to segmentation fault.

This issue can be avoided by ensuring that N and K are properly initialized and have intended values throughout the program. The space before %c in scanf would consume the extra whitespace/newline from the input buffer properly to supply correct values to array and thereby leading to N,K variables being assigned from input as expected. Input issues like this can be caught by checking the return values of scanf function. Additional checks/assertions like K>0 can be helpful for debugging purposes.

  • Please mark it as answer. In future, include the input of the program in the question itself, and make sure that you remove other warnings/ issues from the program while posting. – stackoverflowusrone Mar 01 '20 at 15:23
  • Hi, @stackoverflowusrone Can we explain how the additional space fixes the SegFault? I understand that not purging the end of line from the input buffer causes reading wrong data into `a[]`, but it does not affect the `N` value, which was read before. However, unsynchronizing the input of the first testcase causes a problem with reading the next testcase. Then probably `N` and `K` can not be read at all – but the result of `scanf("%d%d",&N,&K);` is not checked – and the program proceeds with uninitialized variables, which leads to UB, in this case ending with addressing error. – CiaPan Mar 01 '20 at 16:43
0

This piece of code certainly does not do what you want:

                if(a[i]=='H'){
                    a[i]=='T';
                }
                if(a[i]=='T'){
                    a[i]=='H';
                }

The instruction

                    a[i]=='T';

just compares the array item a[i] to the constant 'T' but then it does nothing with the result of the comparison – wheter a[i] was equal 'T' or not does not affect further execution of the program in any way.

And if you change the comparison operator == to an assignment =...

                if(a[i]=='H'){
                    a[i] = 'T';
                }
                if(a[i]=='T'){
                    a[i] = 'H';
                }

then every execution of that loop will leave the a[] array filled with 'H'. Can you see why?

CiaPan
  • 9,188
  • 2
  • 19
  • 32