0

I wrote a program in C which takes as an input a value and an ordered Array of integers and performs a ternary search to find the value(if it exists) inside the Array.

I have seen all the possible problems with the usage of scanf and the related topics here in Stackoverflow.

I have noticed that there is a difference if I call the 2 scanf functions in reverse order.

If I use the code as it is below. First read the value and after the array from the user, the program and scanf functions as expected.

printf("Enter the value to be searched in the Array: ");
int k;
scanf("  %d", &k);

printf("Type elements of A(sorted) separated by spaces (type 'end' to stop): ");

i = 0;  
while(scanf("%d", &A[i]) == 1) {
    i++;
}//while

Although if I use the scanf inputs in the reverse order the second scanf never stops to get user input and read values left in the buffer.

printf("Type elements of A(sorted) separated by spaces (type 'end' to stop): ");

i = 0;  
while(scanf("%d", &A[i]) == 1) {
    i++;
}//while

printf("Enter the value to be searched in the Array: ");
int k;
scanf("  %d", &k);

I cannot understand what is the difference in the calling order. I have tried the solutions mentioned in the other threads but none worked.

Just as a reference here is the whole code(working as expected):

#include<stdio.h>
#include<stdlib.h>
#include<string.h>


int ternarySearch(int A[], int l, int r, int k){
int i;
int first,second;

if(l>r){
    return -1;
}

i= (r - l)/3;

if(i==0){
    i++;
}

first = i+l-1;
second = i*2+l-1;

if(A[first]==k){
    return first;
}
else if(A[first]>k){
    ternarySearch(A, l, first-1, k);
}
else
 {
    if(A[second]==k)
      return second;
    else
    if(A[second]>k)
       ternarySearch(A, first+1,second-1, k);
    else
       ternarySearch(A, second+1,r, k);
 }
}


int main(){
const int maxarraylen = 1000;
int i;
int n;
int A[maxarraylen];
char string[250];

printf("Enter the value to be searched in the Array: ");
int k;
scanf("  %d", &k);

printf("Type elements of A(sorted) separated by spaces (type 'end' to stop): ");

i = 0;  
while(scanf("%d", &A[i]) == 1) {
    i++;
}//while
n=i-1;


//We assume the array is sorted otherwise we can use any sorting algorithm e.g. code from task1

scanf("  %d", &k);






int result;
result=ternarySearch(A, 0, n, k);

if(result==-1){
    printf("The value was not found in the Array.\n");
}
else{
    printf("The value was found in position no. %d.\n", result);
}

return 0;
}
vkoukou
  • 140
  • 2
  • 15
  • You should indent your code and make use of decent variable names to aid understanding. – Attie Mar 19 '17 at 21:42
  • Complete code is only used as a reference if anyone wants to run the program. The only 2 important lines relevant to the question is `scanf(" %d", &k);` and `scanf("%d", &A[i]) == 1`. One read only one integer variable and the other reads several integers from the command line. – vkoukou Mar 19 '17 at 21:46
  • So scanf removes the carriage return'\r' and/or new line character'\n'? Is this why the one way works but the other does not? Can you please explain how **%*s** works? – vkoukou Mar 19 '17 at 21:50
  • 1
    For what it's worth, there is no difference between the scanf formats `"%d"`, `" %d"` and `" %d"`. Whitespace in the format string matches zero or more whitespace characters; the `%d` format starts by skipping zero or more whitespace characters. – rici Mar 19 '17 at 22:03
  • xing, rici thank you for the helpful information! – vkoukou Mar 20 '17 at 07:11

1 Answers1

2

Your problem is that you are not 'stepping over' your end input.

We can see this by doing an experiment using the following program:

#include <stdio.h>
#include <stdlib.h>

void main(void) {
    FILE *f;
    long f_pos;
    int ret;
    int i;
    int data[5];
    int data_last;
    int search;

    f = fopen("./input.txt", "r");
    if (f == NULL) {
        perror("fopen()");
        return;
    }

    /* read in the values for the array */
    data_last = -1;
    for (i = 0; i < 5; i++) {
        ret = fscanf(f, "%d", &(data[i]));
        printf("fscanf(data[%d]): ret: %d\n", i, ret);
        f_pos = ftell(f);
        printf("ftell(): %ld\n", f_pos);
        if (ret != 1) {
            break;
        }
        data_last = i;
    }

    /* check that we read in at least one value */
    if (data_last == -1) {
        printf("no input data!\n");
        return;
    }

    /* insert 'fix' here */

    /* pre-load the 'search' with known garbage */
    search = 987;

    /* now read in the search value */
    ret = fscanf(f, "%d", &search);
    printf("fscanf(search): ret: %d\n", ret);
    f_pos = ftell(f);
    printf("ftell(): %ld\n", f_pos);

    /* print out our info */
    for (i = 0; i <= data_last; i++) {
        printf("data[%d]: %d\n", i, data[i]);
    }
    printf("search for: %d\n", search);

    return;
}

With the following data in input.txt:

123
456
end
456

The output is as follows:

fscanf(data[0]): ret: 1
ftell(): 3
fscanf(data[1]): ret: 1
ftell(): 7
fscanf(data[2]): ret: 0
ftell(): 8
fscanf(search): ret: 0
ftell(): 8
data[0]: 123
data[1]: 456
search for: 987

ftell() tells us where the file's cursor is, and in this case we can see that it is at byte 8... the e of the input line end.

It doesn't get past it, and thus the next attempt to read a number (%d) will fail too!

It's also a good idea to check the return values! We can see that the fscanf(&search) call has failed to read a number!


The solution is to insert this snippet just after we check that we recieved array values:

/* this is the 'fix' */
ret = fscanf(f, "end");
printf("fscanf(end): ret: %d\n", ret);
f_pos = ftell(f);
printf("ftell(): %ld\n", f_pos);
Attie
  • 6,690
  • 2
  • 24
  • 34