无法清除缓冲区

问题描述 投票:0回答:1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

void perimeter(double, double, double, double *, double *);
double square(double, double, double, double);
void heights(double, double, double, double *, double *, double *, double);
void medians(double, double, double, double *, double *, double *);
void bisectors(double, double, double, double *, double *, double *, double);

int main()
{
    char buffer[32];
    double first_side = 0;
    double second_side = 0;
    double third_side = 0;
    
    double per1;
    double per2;
    
    double height_to_firstside;
    double height_to_secondside;
    double height_to_thirdside;
    
    double median_to_firstside;
    double median_to_secondside;
    double median_to_thirdside;
    
    double bisector_to_firstside;
    double bisector_to_secondside;
    double bisector_to_thirdside;
    
    for (int i = 0; i < 3; i++)
    {
        printf("Enter a number for side %d: ", i + 1);
        fgets(buffer, sizeof(buffer), stdin); // Зчитуємо рядок
        
        //Validation
        if (strspn(buffer, "0123456789.") != strlen(buffer) - 1) 
        {
            printf("Invalid input. Please enter other nums.\n");
            return 0;
        }
        
        int dot_count = 0;
        for (int j = 0; j < strlen(buffer); j++)
        {
            if (buffer[0] == '0' && buffer[1] != '.')
            {
                printf("Invalid input. Please enter other nums.\n");
                return 0;
            }
            
            if (buffer[j] == '.')
            {
                dot_count++;
            }
            if (dot_count >= 2)
            {
                printf("Invalid input. Please enter other nums.\n");
                return 0;
            }
        }
        
        double input;
        sscanf(buffer, "%lf", &input);

        if (i == 0) // Зберігаємо значення в відповідній змінній
        {
            first_side = input;
        }
        else if (i == 1)
        {
            second_side = input;
        }
        else if (i == 2)
        {
            third_side = input;
        }
        /*int c;
        while ((c = getchar()) != '\n' && c != EOF) {}
        memset(buffer, 0, sizeof(buffer));*/
    }

    if ((first_side + second_side) < third_side || (second_side + third_side) < first_side || (first_side + third_side) < second_side)
    {
        printf("Unreal triangle, enter other nums\n");
        return 0;
    }

    perimeter(first_side, second_side, third_side, &per1, &per2);
    double area = square(first_side, second_side, third_side, per2);
    heights(first_side, second_side, third_side, &height_to_firstside, &height_to_secondside, &height_to_thirdside, per2);
    medians(first_side, second_side, third_side, &median_to_firstside, &median_to_secondside, &median_to_thirdside);
    bisectors(first_side, second_side, third_side, &bisector_to_firstside, &bisector_to_secondside, &bisector_to_thirdside, per2);

    //results
    printf("Perimeter: %lf\n", per1);
    printf("Semi-perimeter: %lf\n", per2);
    
    printf("Square: %lf\n", area);
    
    printf("Height for the first side: %lf\n", height_to_firstside);
    printf("Height for the second side: %lf\n", height_to_secondside);
    printf("Height for the third side: %lf\n", height_to_thirdside);
    
    printf("Median for the first side: %lf\n", median_to_firstside);
    printf("Median for the second side: %lf\n", median_to_secondside);
    printf("Median for the third side: %lf\n", median_to_thirdside);
    
    printf("Bisector for the first side: %lf\n", bisector_to_firstside);
    printf("Bisector for the second side: %lf\n", bisector_to_secondside);
    printf("Bisector for the third side: %lf\n", bisector_to_thirdside);

    return 0;
}

void perimeter(double first, double second, double third, double *pPer1, double *pPer2)
{
    *pPer1 = first + second + third;
    *pPer2 = *pPer1 / 2;
}

double square(double first, double second, double third, double semi_perimeter)
{
    double square_size;
    square_size = sqrt(semi_perimeter * (semi_perimeter - first) * (semi_perimeter - second) * (semi_perimeter - third));

    return square_size;
}

void heights(double first, double second, double third, double *pHeight_firstside, double *pHeight_secondside, double *pHeight_thirdside, double semi_perimeter)
{
    *pHeight_firstside = 2 * (sqrt(semi_perimeter * (semi_perimeter - first) * (semi_perimeter - second) * (semi_perimeter - third))) / first;
    *pHeight_secondside = 2 * (sqrt(semi_perimeter * (semi_perimeter - first) * (semi_perimeter - second) * (semi_perimeter - third))) / second;
    *pHeight_thirdside = 2 * (sqrt(semi_perimeter * (semi_perimeter - first) * (semi_perimeter - second) * (semi_perimeter - third))) / third;
}

void medians(double first, double second, double third, double *pMedian_firstside, double *pMedian_secondside, double *pMedian_thirdside)
{
    *pMedian_firstside = 0.5 * (sqrt((2 * second * second) + (2 * third * third) - (first * first)));
    *pMedian_secondside = 0.5 * (sqrt((2 * first * first) + (2 * third * third) - (second * second)));
    *pMedian_thirdside = 0.5 * (sqrt((2 * first * first) + (2 * second * second) - (third * third)));
}

void bisectors(double first, double second, double third, double *pBisector_firstside, double *pBisector_secondside, double *pBisector_thirdside, double semi_perimeter)
{
    *pBisector_firstside = (2 / (second + third)) * (sqrt((second * third * semi_perimeter) * (semi_perimeter - first)));
    *pBisector_secondside = (2 / (first + third)) * (sqrt((first * third * semi_perimeter) * (semi_perimeter - second)));
    *pBisector_thirdside = (2 / (first + second)) * (sqrt((first * second * semi_perimeter) * (semi_perimeter - third)));
}


这是我的代码,正如你所看到的,我使用字符数组从用户那里获取值,然后验证它并最终将其转换为双精度,但这都是在循环中完成的,所以我遇到了我无法清除缓冲区的问题,但是当用户输入第一个值时,忽略接下来的两个值,然后第一个值也分配给第二个和第三个值。

我尝试使用

fflush(stdin)
,但它不起作用,我也尝试过这个:

 int c;
 while ((c = getchar()) != '\n' && c != EOF)

但它也不起作用,所以我什至不知道现在应该尝试什么。

c buffer
1个回答
0
投票

您确实可以清除输入缓冲区。或者只是按照预期消耗数据。

fflush
未定义用于输入。它仅为输出而定义,并不意味着
discard
任何东西。示例:您可以让
stdout
的驱动程序等待
\n
打印
tty
上的行,但随后程序结束。无论如何,缓冲区中的字节都会被打印:
OS
最后会刷新输出缓冲区。如果代码中需要立即真正打印数据,那么就有
fflush

一些

C
编译器在输入流上接受
fflush
作为扩展,据我所知,仅供学生使用。

在控制台输入的

Windows
下,您可以调用

BOOL WINAPI FlushConsoleInputBuffer(
  _In_ HANDLE hConsoleInput
);

如文档中所述。在 Linux 上,我认为您可以搜索

ioctl
调用或
termios
来执行相同的操作。

仅消耗所有输入数据

如果您消耗了所有数据,则输入缓冲区不是您的代码所关心的。

我将向您展示一个示例,重新排列您的代码。

使用封装

围绕数据编写代码。只要有机会就使用封装。这不仅仅是一个OOP的花哨词。这是一个强大的东西。

从你的代码:

  • 你的数据是一个三角形
  • 用户输入该方的措施
  • 在确定输入的测量对于三角形可行后,您的代码会计算一些值
  • 显示数值
  • 节目结束。

只有当您有输入三角形时,程序中计算的值才有意义。如果一方的措施发生变化,所有值都将失效。

所以...

考虑这件事:

typedef struct
{
    double   s1;
    double   s2;
    double   s3;
    Measures msrs;
} Triangle;

这是您的数据。至于

msrs
,来自你的代码

typedef struct
{
    double perimeter;
    double semi_perimeter;
    double area;
    double height_to_firstside;
    double height_to_secondside;
    double height_to_thirdside;
    double median_to_firstside;
    double median_to_secondside;
    double median_to_thirdside;
    double bisector_to_firstside;
    double bisector_to_secondside;
    double bisector_to_thirdside;
} Measures;

使用 Triangle 的值

INSIDE
可以轻松强制执行依赖关系。并且还可以在代码中处理任意数字或三角形...

如何创建
Triangle

Triangle* so_create()
{
    Triangle* tri = malloc(sizeof(Triangle));
    if (tri == NULL) return NULL;
    printf(
        "    Triangle:\n\tPlease enter values for the 3 "
        "sides: ");
    int res =
        scanf("%lf %lf %lf", &tri->s1, &tri->s2, &tri->s3);
    if (res != 3)
    {
        free(tri);
        return NULL;
    }
    if (not so_is_triangle(tri))
    {
        free(tri);
        return NULL;
    }
    tri->msrs = so_get_measures(tri);
    return tri;
}

这是程序中

main
中的起始代码。但这里

  • 一次调用
    scanf
    即可读取 3 个测量值
  • 在常见的
    C
    风格中,如果三角形的尺寸合适,则
    so_is_triangle()
    返回
    1
  • 在测量检查中,调用
    so_get_measures()
    计算所有三角形的参数

考虑这些功能:

    Triangle* so_create();
    Triangle* so_destroy(Triangle*);
    int       so_is_triangle(Triangle*);
    Measures  so_get_measures(Triangle*);
    int       so_show_triangle(Triangle*, const char*);

含义明显。

main
进行简单测试

int main(void)
{
    Triangle* one = so_create();
    if (one == NULL)
    {
        fprintf(
            stderr,
            "    Invalid data entered. Please try again\n");
        return -1;
    };
    so_show_triangle(one, "\n\n[First triangle]");
    so_destroy(one);
    return 0;
}

这样更容易阅读。

测试输出

    Triangle:
        Please enter values for the 3 sides: 3 4 5


[First triangle]    Sides: [    3.0000,     4.0000,     5.0000]

    Perimeter:         12.0000
    Semi-perimeter:     6.0000
    Square:             6.0000

    Height for the first side:        4.0000
    Height for the second side:       3.0000
    Height for the third side:        2.4244

    Median for the first side:        4.2720
    Median for the second side:       3.6056
    Median for the third side:        2.5000

    Bisector for the first side:      4.2164
    Bisector for the second side:     3.3541
    Bisector for the third side:      2.4244

关于
so_show_triangle

请注意,一个变量的 12 个 printf 比 12 个变量的单个 printf 慢数百倍。并且更难纠正或对齐...

比较:

    // results
    printf("Perimeter: %lf\n", per1);
    printf("Semi-perimeter: %lf\n", per2);

    printf("Square: %lf\n", area);

    printf(
        "Height for the first side: %lf\n",
        height_to_firstside);
    printf(
        "Height for the second side: %lf\n",
        height_to_secondside);
    printf(
        "Height for the third side: %lf\n",
        height_to_thirdside);

    printf(
        "Median for the first side: %lf\n",
        median_to_firstside);
    printf(
        "Median for the second side: %lf\n",
        median_to_secondside);
    printf(
        "Median for the third side: %lf\n",
        median_to_thirdside);

    printf(
        "Bisector for the first side: %lf\n",
        bisector_to_firstside);
    printf(
        "Bisector for the second side: %lf\n",
        bisector_to_secondside);
    printf(
        "Bisector for the third side: %lf\n",
        bisector_to_thirdside);

    printf(
        "\
    Sides: [%10.4f, %10.4f, %10.4f]\n\
\n\
    Perimeter:      %10.4f\n\
    Semi-perimeter: %10.4f\n\
    Square:         %10.4f\n\
\n\
    Height for the first side:    %10.4f\n\
    Height for the second side:   %10.4f\n\
    Height for the third side:    %10.4f\n\
\n\
    Median for the first side:    %10.4f\n\
    Median for the second side:   %10.4f\n\
    Median for the third side:    %10.4f\n\
\n\
    Bisector for the first side:  %10.4f\n\
    Bisector for the second side: %10.4f\n\
    Bisector for the third side:  %10.4f\n",
        tri->s1, tri->s2, tri->s3,
        tri->msrs.perimeter, tri->msrs.semi_perimeter,
        tri->msrs.area, tri->msrs.height_to_firstside,
        tri->msrs.height_to_secondside,
        tri->msrs.bisector_to_thirdside,
        tri->msrs.median_to_firstside,
        tri->msrs.median_to_secondside,
        tri->msrs.median_to_thirdside,
        tri->msrs.bisector_to_firstside,
        tri->msrs.bisector_to_secondside,
        tri->msrs.bisector_to_thirdside);

在示例中使用。

示例的完整
C
代码

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

typedef struct
{
    double perimeter;
    double semi_perimeter;
    double area;
    double height_to_firstside;
    double height_to_secondside;
    double height_to_thirdside;
    double median_to_firstside;
    double median_to_secondside;
    double median_to_thirdside;
    double bisector_to_firstside;
    double bisector_to_secondside;
    double bisector_to_thirdside;
} Measures;

typedef struct
{
    double   s1;
    double   s2;
    double   s3;
    Measures msrs;
} Triangle;

Triangle* so_create();
Triangle* so_destroy(Triangle*);
int       so_is_triangle(Triangle*);
Measures  so_get_measures(Triangle*);
int       so_show_triangle(Triangle*, const char*);

int main(void)
{
    Triangle* one = so_create();
    if (one == NULL)
    {
        fprintf(
            stderr,
            "    Invalid data entered. Please try again\n");
        return -1;
    };
    so_show_triangle(one, "\n\n[First triangle]");
    so_destroy(one);
    return 0;
}

Triangle* so_create()
{
    Triangle* tri = malloc(sizeof(Triangle));
    if (tri == NULL) return NULL;
    printf(
        "    Triangle:\n\tPlease enter values for the 3 "
        "sides: ");
    int res =
        scanf("%lf %lf %lf", &tri->s1, &tri->s2, &tri->s3);
    if (res != 3)
    {
        free(tri);
        return NULL;
    }
    if (not so_is_triangle(tri))
    {
        free(tri);
        return NULL;
    }
    tri->msrs = so_get_measures(tri);
    return tri;
}

Triangle* so_destroy(Triangle* tri)
{
    if (tri == NULL) return NULL;
    free(tri);
    return NULL;
}

int so_is_triangle(Triangle* tri)
{
    if (tri == NULL) return 0;
    if ((tri->s1 + tri->s2) < tri->s3 ||
        (tri->s2 + tri->s3) < tri->s1 ||
        (tri->s1 + tri->s3) < tri->s2)
        return 0;
    return 1;  // ok it is a triangle
}

Measures so_get_measures(Triangle* tri)
{
    Measures m = {0};
    if (tri == NULL) return m;
    // perimeter
    m.perimeter      = tri->s1 + tri->s2 + tri->s3;
    m.semi_perimeter = m.perimeter / 2;
    // area
    m.area = sqrt(
        m.semi_perimeter * (m.semi_perimeter - tri->s1) *
        (m.semi_perimeter - tri->s2) *
        (m.semi_perimeter - tri->s3));
    // heights
    m.height_to_firstside =
        2 *
        (sqrt(
            m.semi_perimeter *
            (m.semi_perimeter - tri->s1) *
            (m.semi_perimeter - tri->s2) *
            (m.semi_perimeter - tri->s3))) /
        tri->s1;
    m.height_to_secondside =
        2 *
        (sqrt(
            m.semi_perimeter *
            (m.semi_perimeter - tri->s1) *
            (m.semi_perimeter - tri->s2) *
            (m.semi_perimeter - tri->s3))) /
        tri->s2;
    m.height_to_thirdside =
        2 *
        (sqrt(
            m.semi_perimeter *
            (m.semi_perimeter - tri->s1) *
            (m.semi_perimeter - tri->s2) *
            (m.semi_perimeter - tri->s3))) /
        tri->s3;
    // medians
    m.median_to_firstside =
        0.5 *
        (sqrt(
            (2 * tri->s2 * tri->s2) +
            (2 * tri->s3 * tri->s3) - (tri->s1 * tri->s1)));
    m.median_to_secondside =
        0.5 *
        (sqrt(
            (2 * tri->s1 * tri->s1) +
            (2 * tri->s3 * tri->s3) - (tri->s2 * tri->s2)));
    m.median_to_thirdside =
        0.5 *
        (sqrt(
            (2 * tri->s1 * tri->s1) +
            (2 * tri->s2 * tri->s2) - (tri->s3 * tri->s3)));
    // bisectors
    m.bisector_to_firstside =
        (2 / (tri->s2 + tri->s3)) *
        (sqrt(
            (tri->s2 * tri->s3 * m.semi_perimeter) *
            (m.semi_perimeter - tri->s1)));
    m.bisector_to_secondside =
        (2 / (tri->s1 + tri->s3)) *
        (sqrt(
            (tri->s1 * tri->s3 * m.semi_perimeter) *
            (m.semi_perimeter - tri->s2)));
    m.bisector_to_thirdside =
        (2 / (tri->s1 + tri->s2)) *
        (sqrt(
            (tri->s1 * tri->s2 * m.semi_perimeter) *
            (m.semi_perimeter - tri->s3)));
    return m;
}

int so_show_triangle(Triangle* tri, const char* msg)
{
    if (tri == NULL) return -1;
    if (msg != NULL) printf("%s", msg);
    //
    printf(
        "\
    Sides: [%10.4f, %10.4f, %10.4f]\n\
\n\
    Perimeter:      %10.4f\n\
    Semi-perimeter: %10.4f\n\
    Square:         %10.4f\n\
\n\
    Height for the first side:    %10.4f\n\
    Height for the second side:   %10.4f\n\
    Height for the third side:    %10.4f\n\
\n\
    Median for the first side:    %10.4f\n\
    Median for the second side:   %10.4f\n\
    Median for the third side:    %10.4f\n\
\n\
    Bisector for the first side:  %10.4f\n\
    Bisector for the second side: %10.4f\n\
    Bisector for the third side:  %10.4f\n",
        tri->s1, tri->s2, tri->s3,
        tri->msrs.perimeter, tri->msrs.semi_perimeter,
        tri->msrs.area, tri->msrs.height_to_firstside,
        tri->msrs.height_to_secondside,
        tri->msrs.bisector_to_thirdside,
        tri->msrs.median_to_firstside,
        tri->msrs.median_to_secondside,
        tri->msrs.median_to_thirdside,
        tri->msrs.bisector_to_firstside,
        tri->msrs.bisector_to_secondside,
        tri->msrs.bisector_to_thirdside);

    return 0;
}

// https://stackoverflow.com/questions/77216624/impossibility-to-clear-the-buffer
© www.soinside.com 2019 - 2024. All rights reserved.