在printf()中使用时,c中sqrt()的异常beheviour

时间:2015-10-08 19:49:47

标签: c

我是编程新手。我在c中使用sqrt()函数找到了数字的平方根。 `

        scanf("%d", &n);

        printf("%d\n", sqrt(n));
    }

    return 0;
}

当我输入n = 5的值时,我得到了一些负数。有人可以解释一下吗?

4 个答案:

答案 0 :(得分:4)

您通过将错误的类型传递给printf来产生未定义的行为:%d格式需要类型int的匹配参数,但您的参数类型为double }。您需要%f(或%e%g%a)进行打印。此外,可能存在其他问题,例如,如果你省略了#include <math.h>

答案 1 :(得分:1)

正如其他人所指出的,这里的问题是格式说明符是错误的。您需要#include <math.h>才能获得sqrt()的正确返回类型,然后使用格式说明符%f。此外,打开编译器警告,直到它告诉你这里有什么问题。 -Wall -Wextra -pedantic -Wno-system-headers是个不错的选择。

我正在添加一个答案,以提供有关float变量在double参数列表中被提升为printf()的原因的历史背景,而不是scanf(),因为在评论中这让人困惑。

在最初开发C的DEC PDP-10和PDP-11计算机的指令集中,float类型仅存在以节省空间,并且需要转换{{1}的程序} float对其进行任何计算。在早期版本的C中,在ANSI函数原型之前,函数的所有double参数在传递之前自动提升为float(并且double也传递给char)。最初,这在较低级别上运行得更好,并且还具有使用较短类型避免数学上的舍入和溢出错误的优点。该约定还简化了编写函数,这些函数采用了不同类型的不同参数,例如int。调用者可以传递任何内容,编译器会允许它,并且调用函数的工作就是弄清楚参数列表在运行时应该是什么。

当C添加函数原型时,这些旧规则仅用于遗留函数声明(printf()而不是extern double sqrt()或C14通用等价物)以保持向后兼容性。由于基本上没有人以这种方式编写函数,这是一个历史性的好奇心 - 有一个例外。像extern double sqrt(double) 这样的varargs函数不能用C语言编写,并对变量参数进行类型检查。 (使用模板有一种C ++方法可以做到这一点。)标准委员会也不想破坏打印int printf(const char*, ...);的所有现有代码。所以那些仍然按照旧规则进行推广。

float中,这都不适用,因为存储参数是通过引用传递的,而scanf()需要确保它以与保存它的变量相同的类型写入数据。争论促销永远不会发挥作用,因为只有指针才能通过。

答案 2 :(得分:1)

我遇到同样的问题。我想获得int类型的答案。我使用强制类型转换,例如: printf("%d\n", (int)sqrt(n));

答案 3 :(得分:0)

之所以会这样,是因为未指定sqrt()的返回类型和输入类型, 您可以通过以下方式解决此问题:

#include<math.h> 

或通过明确指定返回和输入类型,例如

double sqrt(double);

并且如上所述,请使用正确的格式说明符(例如:%f)。