[转贴] 再说scanf与printf
再说scanf与printf(来源链接: http://brooks.wang.blog.)2010-01-27 13:56:56| 分类: 计算技术
scanf和printf函数家族用于格式化输入和输出,功能非常强大,但是也非常容易出错。尤其是scanf后果更为严重,动不动就是内存访问错误。
由于在C中,整型默认为int,浮点型默认为double。所以用scanf读入short和long需要分别用%hd和%ld,而浮点数又有些特别,%f对应的是float,而不是%hf,相反double对应的%lf,而long double对应的是%Lf。其实我觉得,如果采用%hf--float,%f--double, %lf--long double更为合理,与整型处理更一致,真不知道scanf的设计和实现者是如何考虑的。
由于编译器不扫描scanf和printf的格式字符串,所以无从知晓是否对应正确。scanf应该不会对参数进行任何处理,short指针就是short指针,float指针就是float指针。而printf就不一样了,精度低于int的参数如short会提升为int,精度低于double的类型如float会提升为double。
scanf不管传入的指针具体类型,只是根据格式字符串的指示,把特定参数当作某种类型指针使用,比如%d对应的是一个4字节的整型指针,如果传入的是一个short指针,那么scanf还是会把它当作整型指针使用,结果多修改了两个字节。此外还有%d、%hd等对应到char *,%f、%lf或%Lf对应到int *等都会导致严重后果。%n对应的是一个整型指针,返回已经扫描过的字符数。%hn对应short *,%ld对应long *,这和%d是一致的。%n不会扫描输入流,这是它别的格式码最大的区别。
printf相对来说要稍微安全一点,因为大部分情况下它只对参数读,%n是一个例外。但是对应错误会导致输出结果不正确。比如比较经典的是:
printf( "%d\n", 3.14 );
输出结果不是3而是令人奇怪的1374389535,原因其实很简单,3.14是一个8字节的double值,但printf把它的低4字节当作int处理,于是得到这么奇怪的结果。printf不知道如何处理3.14,只知道它是一个double值,于是就当double处理。如果放一个字符变量,那么会导致多读取堆栈上额外的三个字节,也可能导致内存访问错误。