简体   繁体   中英

How ctrl-d, ctrl-c is handled by C/scanf

Let's take the following program:

# include<stdio.h>
int main(void)
{
    int status, current_number, sum=0;
    printf("Enter a number: ");
    while(status=scanf("%d", &current_number)) {
        sum += current_number;
        printf("Status: %d. The current sum is: %d. Enter another number: ", status, sum);
    }   
}

Enter a number: 2
Status: 1. The current sum is: 2. Enter another number: 3
Status: 1. The current sum is: 5. Enter another number: Status: -1. The current sum is: 8. Enter another number: ^C

It seems that Ctrl D (EOF) is recognized as -1 but Ctrl C jus causes the program to quit. How are these two escape sequences usually handled in C? And why does scanf treat ctrl-c and ctrl-d differently?

The scanf function does not treat these character in any special way, it doesn't even see those characters. What happens is that the terminal driver (at least under UNIX-like systems (a) ) intercepts these keystrokes and translates them to special actions.

For CTRL-d , it closes the standard input file so that any code reading it will get an EOF - that's the -1 you're seeing (indicating an error of some description on read).

For CTRL-c , it raises the SIGINT signal which, if uncaught, will terminate your program.

Keep in mind these are the default key-bindings for those actions, they can be changed with stty to use different ones. The default ones ( intr and eof ) are shown below ( ^C and ^D ):

pax> stty -a
speed 38400 baud; rows 37; columns 145; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z;
rprnt = ^R; werase = ^W; lnext = ^V; discard = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho -extproc

And keep in mind this is probably not what you want:

while(status=scanf("%d", &current_number)) {

The loop will only exit when scanf returns zero, which will happen if an integer cannot be scanned (such as by entering the non-numeric XYZZY ). It will continue for any non-zero value, including the -1 you get back on error/end-of-file.

A better loop would be:

while((status = scanf("%d", &current_number)) == 1) {

In fact, since the loop should only ever run for a status value of 1 , it makes little sense to use it (other for a final decision on what happened). I'd prefer something like:

#include<stdio.h>

int main(void) {
    int stat, curr, sum = 0;

    // Prompt and loop while user enters valid numbers.

    printf("Enter a number: ");
    while ((stat = scanf("%d", &curr)) == 1) {
        // Accumulate number to sum, output details and ask for next.

        sum += curr;
        printf("Entered %d, sum is %d, enter another number: ", curr, sum);
    }

    // Final status -1 if EOF/error, 0 if item couldn't be scanned.

    if (stat == -1) {
        prinf("\nEnd of file or I/O error.\n");
    } else {
        prinf("Non-numeric data.\n");
    }
}

(a) Windows, from memory and by contrast, only recognises CTRL-z at the start of a line (and followed by ENTER ) as the end-of-file indicator.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM