如何根据 C 函数中函数的输入退出 while 循环?

Posted

技术标签:

【中文标题】如何根据 C 函数中函数的输入退出 while 循环?【英文标题】:How can I exit a while loop based on input from a function in a function in C? 【发布时间】:2016-03-17 02:56:22 【问题描述】:

我的 main 函数中有一个 while 循环,它调用一个用户定义的函数,该函数调用另一个用户定义的函数,该函数调用 scanf 来读取一对 double 值。我希望我的程序在输入非数字时结束。我的函数返回结构,而不是 0/1。有没有办法一直传递一个错误的scanf return 来打破我的 while 循环?

我可以声明一个全局变量并将其分配给scanf 语句,然后在main 函数中对该变量进行if 语句吗? 或者我是否必须更改我的函数以返回 int (0/1) 并通过引用传递我的结构?

这可能是一个非常糟糕的解释,所以这是我的问题中涉及的部分的代码......该程序旨在读取一个矩形(按左下角和右上角)和一个圆圈,并说出他们的区域重叠。而且我希望在main 函数中的while 循环中中断...

typedef structdouble x,y; point;
typedef structpoint a,b,c,d; rectangle;
typedef structpoint o; double r; circle;

point readPoint()
    point p;
    scanf("%lf%lf", &p.x, &p.y);     //type "quit"
    return p;


rectangle readRectangle()
    rectangle r;
    r.c=readPoint();
    r.b=readPoint();
    r.a.x=r.c.x;
    r.a.y=r.b.y;
    r.d.x=r.b.x;
    r.d.y=r.c.y;
    return r;


int main(void) 
    int a=0;
    rectangle r;
    circle c;

    while(1)
        printf("Enter rectangle:");
        r=readRectangle();            //break loop here if quit is entered
        printf("Enter circle:");
        c=readCircle();
        a=overlap(r, c);
        if (a==1)
            printf("The rectangle and the circle overlap.\n\n");
        else
            printf("The rectangle and the circle do not overlap.\n\n");
    
    printf("Program completed normally.");
    return EXIT_SUCCESS;

【问题讨论】:

您已经列出了一些主要选项。只需继续选择其中一个。我个人不建议使用全局变量,但会使用返回值方法。 除非必要,否则使用全局变量是不好的。 另一个选项在结构中再添加一项。 bansai,你能详细说明一下吗?您的意思是在点结构中添加另一个项目吗?像一个字符串来读取退出?这不会影响我使用该结构的其余时间吗? 我会创建 point *readPoint(point *p),然后检查 scanfif (scanf("%lf%lf", &p->x, &p->y) < 2) return NULL; return p; 的返回值,并继续该逻辑备份链。 【参考方案1】:

重新定义您的readPoint()readRectangle() 函数,更像这样:

#include <stdbool.h>
#include <stdio.h>

typedef struct  double x, y;  point;
typedef struct  point a, b, c, d;  rectangle;   

bool readPoint(point *p)

    if (scanf("%lf%lf", &p->x, &p->y) != 2)
        return false;
    return true;


bool readRectangle(rectangle *r)

    if (!readPoint(&r->c) || !readPoint(&r->b))
        return false;
    r->a.x = r->c.x;
    r->a.y = r->b.y;
    r->d.x = r->b.x;
    r->d.y = r->c.y;
    return true;


int main(void)

    while (1)
    
        rectangle r;
        printf("Enter rectangle: ");
        if (!readRectangle(&r))
            break;   
        …
    
    return 0;

这是您概述的策略之一——它可能是最好的。您可以继续返回结构并通过指针 (point readPoint(int *status)) 传入状态变量 — 虽然它不是传统的方法,但它会起作用。

一个更古怪的技术将使用来自&lt;setjmp.h&gt;setjmp()longjmp();您可以在main() 函数中调用setjmp(),并在您的输入代码检测到问题时调用longjmp()。我不建议这样做——只是概述一个替代方案。

是的,您可以将 readPoint() 缩写为:

bool readPoint(point *p)

    return scanf("%lf%lf", &p->x, &p->y) == 2;

【讨论】:

比处理从readPoint备份的指针要少得多。 r.a.x=r.c.x; r.a.y=r.b.y; r.d.x=r.b.x; r.d.y=r.c.y;编译器没有意识到这些是结构的一部分....它们也必须是指针吗?...指针仍然让我感到困惑 我必须修复我的代码版本以使用r-&gt;a.x 等,因为r 现在是rectangle * 而不是rectangle 结构。不过,我不久前就这样做了。【参考方案2】:

所以这个想法很糟糕,我将提供这个问题的字面答案。是的,你可以这样做。你最好有一个很好的理由这样做,否则其他人会惊恐地尖叫你创建的代码。

#include <stdio.h>
#include <setjmp.h>

typedef structdouble x,y; point;
typedef structpoint a,b,c,d; rectangle;
typedef structpoint o; double r; circle;

point readPoint(jmp_buf jmp)
    point p;
    if (scanf("%lf%lf", &p.x, &p.y) != 2)     /*type "quit"*/
        longjmp(jmp, 1); /* returns to setjmp() call with 1 */
    return p;


rectangle readRectangle(jmp_buf jmp)
    rectangle r;
    r.c=readPoint(jmp);
    r.b=readPoint(jmp);
    r.a.x=r.c.x;
    r.a.y=r.b.y;
    r.d.x=r.b.x;
    r.d.y=r.c.y;
    return r;


int main(void) 
    jmp_buf jmp;
    if (setjmp(jmp) == 0) 
        while(1)
            int a=0;
            rectangle r;
            circle c;
            printf("Enter rectangle:");
            r=readRectangle(jmp);
            printf("Enter circle:");
            c=readCircle(jmp);
            a=overlap(r, c);
            if (a==1)
                printf("The rectangle and the circle overlap.\n\n");
            else
                printf("The rectangle and the circle do not overlap.\n\n");
        
    
    printf("Program completed normally.");
    return EXIT_SUCCESS;

【讨论】:

通过反例学习,无价!【参考方案3】:

我会让您的 readPoint 方法返回 0/1 以指示读取成功或失败,然后通过引用将结果传回。

这可以让您的数据保持干净,而不是在每个结果中都传递一个 isBadData 标志。

【讨论】:

【参考方案4】:

您需要对 readPoint() 进行一些修改。

point readPoint()
int s;
point p;
s=scanf("%lf%lf", &p.x, &p.y);
if(s==0) exit(EXIT_FAILURE);
return p;

如果未输入值或它们不符合格式,则 s=0 因为它是 scanf() 返回的值。欲了解更多信息,请访问http://www.cplusplus.com/reference/cstdio/scanf/

包含 stdlib.h 头文件以使用退出函数。

【讨论】:

单方面退出库函数很少是个好主意。 是的,这不是一个好主意,无论如何它适用于这个程序。

以上是关于如何根据 C 函数中函数的输入退出 while 循环?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用重复、while 循环或其他迭代技术编写一个根据某些规则返回输入向量索引的函数

c语言如何写一个自定义函数,随意输入n个数,求出这n个数中的最大值

测试给定的输入值是不是不会从 while True 循环中中断

自定义输入/输出函数

C语言不定长参数的问题

Python ❀ while循环