【问题标题】:break a FOR loop with keyboard in C在 C 中用键盘打破 FOR 循环
【发布时间】:2014-09-20 07:27:26
【问题描述】:

我有一个程序在开始 for (;;) 循环之前运行了几个步骤。

我希望能够打破;这个for 循环使用按键(例如,'e' 用于退出)

我尝试过scanf_s,但我认为我没有正确使用它们。如果我尝试将scanf_s 写入其中,则循环不会启动。

我对 C 编程不是很熟悉,所以我有点挣扎。

有人能解释一下吗?

额外信息:

操作系统是Win 8.1。

Program 是一个 TCP 服务器程序。它创建一个套接字并开始监听。然后它开始在for 循环中接受客户端连接。然后开始另一个for 循环以接收来自客户端的消息。

编辑:使用this 我设法用s 停止了第二个for 循环。添加了对简化代码的更改(如下所示)。

添加:

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

这里是一些简化的代码:

#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;
}

感谢所有提供链接和有用答案的人。事实证明,外循环的问题比仅仅打破它更复杂。但是,如果任何未来的访问者想知道如何通过键盘按下来打破循环,那么这已经实现了。请参阅正确答案或我的简化代码。

【问题讨论】:

  • 你能用你的程序启发我们吗,否则很难说出哪里出了问题,而且中断是一个强词(在这种情况下是错误的)你可以使用“break”
  • C 不为我认为您要求做的事情提供任何本机支持。你的操作系统是什么?
  • 没有标准的 C 函数可以检查击键。您需要为此使用特定于实现的 API。由于您似乎在 Windows 上,请查看 heresecond 答案)。
  • 你需要使用SetConsoleCtrlHandler和朋友。 Handle CTRL+C on Win32 的可能重复项。
  • 如果您有其他问题,请提出单独的问题。很难理解您修改后的问题是什么。如果你想跳出外循环,问一个关于跳出外循环的问题。请注意,它与检查键盘敲击无关,因为您已经知道要中断。

标签: c for-loop


【解决方案1】:

您可以尝试使用kbhitgetchar 来检查击键并相应地处理操作。 查看此帖子:Return pressed key without enter for confirmation

当按下e 时,此代码会中断while 循环: [代码更新了一个额外的 while 循环]

#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;
}

使用 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;
}

【讨论】:

  • 你好,你好。我设法停止了我的第二个循环(请参阅我的帖子编辑)。使用 _kbhit 和 getch。但我没有成功阻止第一个。有任何想法吗?谢谢@crazy_Fish
  • @jonsnowed。初始化ch = 0,然后在外部循环和内部循环中测试它。最好用 while(ch != 'e' 替换您的 for(;;) - 与内部外观类似 - 在循环测试中激发通常比 break 更可取。
  • @Clifford 如果我将外部或内部循环更改为while (ch != 'e') 我应该将if (kbhit()) ch = getch(); 部分放在哪里?
  • 虽然这可行,但它不能跨编译器移植。 conio.h 是 Microsoft 特有的,Borland 编译器中存在同名的库,但具有不同的 API(尽管此处使用的函数相同)。在 Visual Studio 中,除非您使用 _kbhit()_getch(),否则会发出警告。使用Windows console API 将确保至少在 Windows 编译器之间的可移植性 - 但远没有那么简单。
  • @jonsnowed : cmets 部分不适合详细回答。我会发布一个答案。
【解决方案2】:

只需在 for 循环中输入这些行。当用户输入“e”字符时,这将退出。

    if(kbhit()){              
  ch = getch();          
  if(ch == 'e')          
    break;             
    }`

【讨论】:

  • 嗨 @user3256675 这适用于内部 recv() 循环,但不适用于外部 accept() 循环。请参阅我的简化代码示例。如何让它为外循环工作?谢谢:)
  • @jonsnowed :如果accept() 在阻塞套接字上,它将等待传入连接,并且不会读取键盘。这与您在这里的问题不同 - 如果这是问题,那么您可能应该发布一个关于如何使 accept() 非阻塞的新问题。
  • @Clifford 你是对的。我确实相信这是外部循环中包含 accept() 的根本问题。
【解决方案3】:

假设微软的编译器,最简单的方法是使用它的conio库。我建议将细节包装到一个函数中,以允许重用。例如,您可能需要在进入第二个循环之前测试键盘。

#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;
}

正如我所建议的,在某些情况下,如果请求退出,您可能不希望内部循环运行,在这种情况下:

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

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

【讨论】:

  • 将此标记为正确,因为在另一个不涉及 accept() 和阻塞套接字的代码中对其进行测试。感谢@Clifford 关于非阻塞accept() 的提示。
  • @jonsnowed :注意非阻塞循环 - 如果您的进程从不阻塞,它将消耗它可以获得的所有 CPU 周期并影响整个系统的响应能力。多核处理器有帮助,但它并不是“玩得很好”。至少应该插入一个Sleep() 调用(以accept() 返回无连接为条件)调用一段时间,不会导致明显的键盘响应延迟。
  • 我认为 @crazy_Fish 值得称赞 - 我或多或少偷了他的答案!
【解决方案4】:

您可以尝试使用用户定义的中断

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-13
    相关资源
    最近更新 更多