1

I have a program that runs through a few steps before it starts a for (;;) loop.

I want to be able to break; this for loop using a keystroke (such a 'e' for exit, for example)

I've tried scanf_s but I don't think I am using them correctly. the loop just doesn't initiate if I try to write scanf_s in.

I'm not very familiar with C programming so I'm struggling a little bit.

Can someone shed some light on this?

extra info:

Operating system is Win 8.1.

Program is a TCP server program. it creates a socket and begins listening. Then it starts accepting client connections in a for loop. then begins another for loop to receive messages from the client.

Edit: using this I have managed to stop the second for loop with s. added the changes to the simplified code (and just bellow).

added:

if (_kbhit()) {
    key = _getch();
    if (key == 's');
    break;
}

here is some simplified code:

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

int main(void)
{
    // prelim info goes here
    // like SOCKET 
    // and struct sockaddr_in

    // Initialize Winsock
    WSAStartup();

    // Create socket
    mysocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    // server parameters go here 
    // like sin_addr and sin_port

    bind(mysocket);

    // start listening
    listen(mysocket, SOMAXCONN);

    // begin the damn for loops

    for (;;)
        {

        myclient = accept();

         //second for loop
        for (;;)
        {
            receivedata = recv(myclient);

            printf(<data>)

            if (_kbhit()) {
                key = _getch();
                if (key == 's');
                    break;
            }

        }
    }

    // close socket
    closesocket(mysocket);

   // call WSACleanup
   WSACleanup();

   return 0;
}

thanks to everyone who supplied links and the helpful answers. The issue with the outer loop turned out to be a bit more involved than just breaking it. However, if any future visitors are wondering how to break a loop with a keyboard press, this has been achieved. See the correct answer or my simplified code.

Community
  • 1
  • 1
  • Could you enlighten us with your program, it's hard to tell what's wrong otherwise, and also interrupt is a strong word (wrong in this context) you can use "break" – nj-ath Sep 20 '14 at 07:29
  • C doesn't provide any native support for what I think you are asking to do. What is your operating system? – jxh Sep 20 '14 at 07:30
  • `char a; scanf("%c", &a); if (a == 'e') break;` – chouaib Sep 20 '14 at 07:30
  • 2
    There is no standard C function that would check for keystrokes. You need to use an implementation-specific API for that. Since you seem to be on Windows, look [here](http://stackoverflow.com/questions/9740717/return-pressed-key-without-enter-for-confirmation) (the *second* answer). – n. m. could be an AI Sep 20 '14 at 07:37
  • 1
    You need to use [`SetConsoleCtrlHandler`](http://msdn.microsoft.com/en-us/library/windows/desktop/ms686016%28v=vs.85%29.aspx) and friends. Possible duplicate of [Handle CTRL+C on Win32](http://stackoverflow.com/questions/18291284/handle-ctrlc-on-win32). – jww Sep 20 '14 at 07:39
  • It seems you have three loops. listening -> accepting (loop) -> receiving (loop) -> back to listening. Am I right? Which one do you want to break out of? – jxh Sep 20 '14 at 07:40
  • I don't know for sure but I think this question is the same asking as this one - http://stackoverflow.com/questions/421860/c-c-capture-characters-from-standard-input-without-waiting-for-enter-to-be-pr – Brandin Sep 20 '14 at 07:44
  • @jxh nope just two loops. listening is just `listen(TCPListen, SOMAXCONN);` . it accepts client connections in a loop, and within that receives data in a loop with time control (every second). I would like the option to break both seperately. ideally. `e` to break the client connections, `s` to break receiving data? –  Sep 20 '14 at 07:45
  • @n.m.'s suggestion is probably what you want. It might be tricky to do what you asked (separate keys to break the loops independently), but it is possible. But, if you are blocked on `accept()`, the `kbhit()` won't run until after you get a new client connection. Similarly if you are blocked on `recv()`, the `kbhit()` won't run until after the client sends data. – jxh Sep 20 '14 at 07:58
  • @jxh I've added some simplified code. could you maybe indicate where I might add in the kbhit()? I can't see to figure it out without stopping the recv() or it just not accepting keyboard inputs once recv() starts –  Sep 20 '14 at 08:07
  • 1
    If you have a different question, ask a separate question. It is hard to understand what's your amended question is. If you want to break out of the outer loop, ask a question about breaking out of outer loops. Note it has nothing to do with checking for keyboard hits, as you already know you want to break. – n. m. could be an AI Sep 20 '14 at 09:04
  • @n.m another user pointed out an issue with blocking sockets which is why breaking the outer loop is not working. I'll amend my question and simplify for any future viewers wondering about breaking loops. they can use Clifford's answer or any of the helpful links posted. –  Sep 20 '14 at 09:31
  • You managed to introduce a typo to your code by blindly copying anotherone's code. – moooeeeep Apr 17 '15 at 06:43

4 Answers4

2

You can try using kbhit and getchar to check keystroke and handle the action accordingly. Check this post: Return pressed key without enter for confirmation

This code breaks the while loop when e is pressed: [Code updated with one more extra while loop]

#include <stdio.h>
#include <conio.h>

int main(){
    int ch = '1';
    while(ch != 'e'){                        //outer while for accepting connection
        printf("waiting for connection\n");  //do something

        while(ch != 'e'){                    //inner while for checking key press
            if(kbhit())                      //if key is pressed
                ch = getch();                //get the char and set ch to 'e'
        }
    }

    return 0;
}

Old Code using break:

#include <stdio.h>
#include <conio.h>
#include <windows.h>
int main(){
    int ch;
    while(1){
        printf("*");
        if(kbhit()){               //if key is pressed
            ch = getch();          //get the char
            if(ch == 'e')          //if pressed key is 'e'
                break;             //break while loop 
        }
    }

    return 0;
}
Community
  • 1
  • 1
crazy_Fish
  • 78
  • 4
  • hello hi. I've managed to stop my second loop (see my post edit). using _kbhit and getch. but I'm not being successful in stopping the first one. any ideas? thanks @crazy_Fish –  Sep 20 '14 at 08:22
  • @jonsnowed. Initialise `ch = 0`, then test it in the outer loop as well as the inner. Better yet replace your `for(;;)` with `while(ch != 'e'` - similarly for the inner look - eciting at the loop test is usually preferable to a `break`. – Clifford Sep 20 '14 at 08:27
  • @Clifford if I change the outer or inner loop to `while (ch != 'e')` where do I put the `if (kbhit()) ch = getch();` part? –  Sep 20 '14 at 08:33
  • 1
    While this works, it is not portable across compilers. The `conio.h` is specific to Microsoft, a library of the same name exists in Borland compilers, but has a different API (though the functions used here are the same). In Visual Studio, a warning is issued unless you use `_kbhit()` and `_getch()`. Using the [Windows console API](http://msdn.microsoft.com/en-gb/library/windows/desktop/ms682073(v=vs.85).aspx) will ensure portability at least among Windows compilers - but is far less straightforward. – Clifford Sep 20 '14 at 08:37
  • @jonsnowed : The comments section is not suited to answering in detail. I'll post an answer. – Clifford Sep 20 '14 at 08:39
  • @Clifford portability is not really a concern right now. I just need to be able to break both loops. ideally. I can break the inner one but not the outer one. and if I change it to be `while` instead of for, I don't know where to put the `_kbhit` part. –  Sep 20 '14 at 08:42
  • @jonsnowed i am updating the current code according to your program. Using two loops. – crazy_Fish Sep 20 '14 at 08:47
  • Note that _getch() returns an `int`. – Clifford Sep 20 '14 at 09:03
  • Upvoted as small compensation for me using your answer in mine. – Clifford Sep 20 '14 at 10:48
0

just enter these lines in for loop. this will exit when user will enter 'e' char.

    if(kbhit()){              
  ch = getch();          
  if(ch == 'e')          
    break;             
    }`
Ajayattri
  • 1
  • 3
  • hi @user3256675 this works for the inner recv() loop but not for the outer accept() loop. see my simplified code example. how do I get it to work for the outer loop? thanks :) –  Sep 20 '14 at 08:40
  • 1
    @jonsnowed : If the `accept()` is on a blocking socket, it will wait for an incoming connection, and will not read the keyboard. That is a different issue to your question here - if that is the issue, then you should probably post a new question on how to make accept() non-blocking. – Clifford Sep 20 '14 at 09:01
  • @Clifford you're right. I do believe this is the fundamental problem with the outer loop having the accept() in it. –  Sep 20 '14 at 09:28
0

Assuming Microsoft's compiler, the simplest method is to use its conio library. I suggest wrapping the details into a single function, to allow reuse. For example, you may need to test the keyboard before entry to the second loop.

#include <conio.h>

int nonBlockingGetch( void )
{
    int ch = -1 ;
    if( _kbhit() )
    {
        ch = _getch() ;
    }

    return ch ;
}

int main( void )
{
    int ch = -1 ;

    //  Outer loop
    while( ch != 'e' )
    {

        // inner loop
        while( ch != 'e' )
        {
            ch = nonBlockingGetch() ;
        }
    }

    return 0;
}

As I suggested there may be circumstances where you would not want the inner loop to run if an exit were requested, in which case:

//  Outer loop
while( ch != 'e' )
{
    ch = nonBlockingGetch() ;

    // inner loop
    while( ch != 'e' )
    {
        ch = nonBlockingGetch() ;
    }
}
Clifford
  • 88,407
  • 13
  • 85
  • 165
  • marking this as correct because testing it in another code that does not involve the accept() and a blocking socket worked. thanks @Clifford for the hint about the non-blocking accept(). –  Sep 20 '14 at 09:29
  • 1
    @jonsnowed : be careful with non-blocking loops - if your process never blocks it will consume all the CPU cycles it can get and affect the responsiveness of the system as a whole. Multi-core processors help, but it is not "playing nice". At least a `Sleep()` call (conditional on `accept()` returning no connection) call for some short time that would not cause noticeable keyboard response lag should be inserted. – Clifford Sep 20 '14 at 10:43
  • I think @crazy_Fish deserves credit - I more or less stole his answer! – Clifford Sep 20 '14 at 10:47
-1

You can try with user defined Interrupts