C语言回顾day3(二)(float和double的详细信息:通过符号常量)

第四章,主要讲输入输出和字符串,简单

字符串

在这里插入图片描述
头文件可提供库函数的原型

#include <stdio.h>
#include <string.h>//提供strlen()函数的原型
int main()
{
    char word[20]; //用数组存储字符串,占用20个连续的内存单元(字节)
    printf("Enter your name:");
    scanf("%s", word);//注意数组不需要&!!!这是因为C中数组名就是地址,就是指针!!
    printf("%s has %d letters.\n", word, strlen(word));
    return 0;
}
Enter your name:mary
mary has 4 letters.

在这里插入图片描述

正如圆括号表明前面的标识符代表一个函数名一样的

数组是同类型数据元素的有序序列

null字符

在这里插入图片描述
不需要自己加空字符,编译器加
在这里插入图片描述

重要工具:C预处理器指令

#define可以定义常量,各种各样的常量,包括数值,字符串

#include <stdio.h>
#include <string.h>
#define PRAISE "you are an extraordinary being."
int main()
{
    char word[20]; //用数组存储字符串,占用20个连续的内存单元(字节)
    printf("Enter your name:");
    scanf("%s", word);//注意数组不需要&!!!这是因为C中数组名就是地址,就是指针!!
    printf("%s has %d letters.\n", word, strlen(word));
    printf("%s, %s", word, PRAISE);
    return 0;
}

一定要注意,scanf遇到空格,换行符,制表符就会停止读取

Enter your name:Mary Green
Mary has 4 letters.
Mary, you are an extraordinary being.

在这里插入图片描述

符号常量(详解float double)

(aka 明示常量 manifest constant)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述
下面代码中被注释的几行都是没有定义的符号常量
UCHAR_MIN, USHRT_MIN, UINT_MIN, ULONG_MIN, ULLONG_MIN都没有定义哦

#include <stdio.h>
#include <limits.h>
#include<float.h>

int main()
{
    printf("limits.h\n");
    printf("CHAR_BIT: %d bits.\n", CHAR_BIT);
    printf("CHAR_MAX: %d.\n", CHAR_MAX);
    printf("CHAR_MIN: %d.\n", CHAR_MIN);
    printf("SCHAR_MAX: %d.\n", SCHAR_MAX);
    printf("SCHAR_MIN: %d.\n", SCHAR_MIN);
    printf("UCHAR_MAX: %d.\n", UCHAR_MAX);
//    printf("UCHAR_MIN: %d.\n", UCHAR_MIN);
    printf("SHRT_MAX: %d.\n", SHRT_MAX);
    printf("SHRT_MIN: %d.\n", SHRT_MIN);
    printf("USHRT_MAX: %d.\n", USHRT_MAX);
   // printf("USHRT_MIN: %d.\n", USHRT_MIN);
    printf("INT_MAX: %d.\n", INT_MAX);
    printf("INT_MIN: %d.\n", INT_MIN);
    printf("UINT_MAX: %u.\n", UINT_MAX);
  //  printf("UINT_MIN: %d.\n", UINT_MIN);
    printf("LONG_MAX: %ld.\n", LONG_MAX);
    printf("LONG_MIN: %ld.\n", LONG_MIN);
    printf("LLONG_MAX: %lld.\n", LLONG_MAX);
    printf("LLONG_MIN: %lld.\n", LLONG_MIN);
    printf("ULONG_MAX: %lu.\n", ULONG_MAX);
//    printf("ULONG_MIN: %u.\n", ULONG_MIN);
    printf("ULLONG_MAX: %llu.\n", ULLONG_MAX);
   // printf("ULLONG_MIN: %u.\n", ULLONG_MIN);

   printf("\n");
   printf("float.h\n");
   printf("FLT_MANT_DIG: %d \n", FLT_MANT_DIG);
   printf("FLT_DIG: %d \n", FLT_DIG);
   printf("FLT_MIN_10_EXP: %d \n", FLT_MIN_10_EXP);
   printf("FLT_MAX_10_EXP: %d \n", FLT_MAX_10_EXP);
   printf("FLT_MIN: %d \n", FLT_MIN);
   printf("FLT_MAX: %u \n", FLT_MAX);
   printf("FLT_EPSILON: %e \n", FLT_EPSILON);
   
   printf("DBL_MANT_DIG: %d \n", DBL_MANT_DIG);
   printf("DBL_DIG: %d \n", DBL_DIG);
   printf("DBL_MAX: %f \n", DBL_MAX);
   printf("DBL_MIN: %f \n", DBL_MIN);
   printf("DBL_MIN_10_EXP: %d \n", DBL_MIN_10_EXP);
   printf("DBL_MAX_10_EXP: %d \n", DBL_MAX_10_EXP);
   printf("DBL_EPSILON: %e \n", DBL_EPSILON);
    return 0;
}

编译器标准C99, C11都可以识别LLONG_MAX和LLONG_MIN,不像书上说的这样

注意long要用%ld, long long 要用%lld做转换说明
在这里插入图片描述

这个epsilon的值用%d和%f做转换说明都是不对的,肯定不会是0呀,必须用%e

limits.h
CHAR_BIT: 8 bits.
CHAR_MAX: 127.
CHAR_MIN: -128.
SCHAR_MAX: 127.
SCHAR_MIN: -128.
UCHAR_MAX: 255.
SHRT_MAX: 32767.
SHRT_MIN: -32768.
USHRT_MAX: 65535.
INT_MAX: 2147483647.
INT_MIN: -2147483648.
UINT_MAX: 4294967295.
LONG_MAX: 2147483647.
LONG_MIN: -2147483648.
LLONG_MAX: 9223372036854775807.
LLONG_MIN: -9223372036854775808.
ULONG_MAX: 4294967295.
ULLONG_MAX: 18446744073709551615.

float.h
FLT_MANT_DIG: 24
FLT_DIG: 6
FLT_MIN_10_EXP: -37
FLT_MAX_10_EXP: 38
FLT_MIN: 0
FLT_MAX: 3758096384
FLT_EPSILON: 1.192093e-007
DBL_MANT_DIG: 53
DBL_DIG: 15
DBL_MAX: 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000
DBL_MIN: 0.000000
DBL_MIN_10_EXP: -307
DBL_MAX_10_EXP: 308
DBL_EPSILON: 2.220446e-016

可见float的尾数占24位,则指数占8位, 有效位数至少是6位,表示范围是 1 0 − 37 − − − − 1 0 38 10^{-37}----10^{38} 10371038
double的尾数占53位,则指数占11位, 有效位数至少是15位,表示范围是 1 0 − 307 − − − − 1 0 308 10^{-307}----10^{308} 1030710308
double的epsilon比float的小很多,说明double的精度确实更高

printf()函数

在这里插入图片描述在这里插入图片描述

#include <stdio.h>
int main()
{
    printf("*%d*\n", 789);
    printf("*%2d*\n", 789); //字段宽度小于实际需求时,	字段宽度会自动扩大以适应需求	
    printf("*%10d*\n", 789); //占10个字段宽度(空格宽度)
    printf("*%-10d*\n", 789); //左对齐
    return 0;
}
*789*
*789*
*       789*
*789       *

printf()的类型不匹配时,可能会出错,
比如:%hd打印int变量

#include <stdio.h>
int main()
{
    int x = 3000000;
    printf("%hu\n", x);
    printf("%d\n", x);
    printf("%d", x%65536);
    return 0;
}
50880
3000000
50880

但也不是一直错,因为错误原因在于int是4字节,short是2字节,当x大于short的表示范围才会出错,出现取模的效果,因为%hd表示int变量就会只取后两个字节的内容,相当于把x对 2 1 6 2^16 216,即65536取模

下面x=300,咩有超过short的范围,所以就没有出错

#include <stdio.h>
int main()
{
    int x = 300;
    printf("%c\n", x);
    printf("%hd\n", x);
    printf("%d\n", ',');
    return 0;
}
,
300
44

float类型的值作为printf()的参数会被自动转换为double类型

在这里插入图片描述

#include <stdio.h>
int main()
{
    float x = 3.2;
    double y = 3.2;
    long z1 = 100000000;
    long z2 = 300000000;
    printf("%e, %.1e, %.2e, %e, %.1e, %.2e\n", x, x, x, y, y, y);//float会被自动转换为double,所以x,y完全一样
    printf("%ld, %ld\n", z1, z2);
    printf("%e, %e\n", z1, z2);//用%e打印long变量会得到错误结果,因为%e使得编译器认为是double类型,于是就要读8字节,可是long早我的系统中是4字节,于是就多读了内存旁边的4字节,自然就得到了意外的结果
    printf("%ld, %ld, %ld, %ld\n", x, y, z1, z2);//printf函数中转换说明不对的地方会影响其他正确的地方,使得大家都错了!!!奇怪的很嘞,不懂底层原理就是这么蒙蔽
    return 0;
}
3.200000e+000, 3.2e+000, 3.20e+000, 3.200000e+000, 3.2e+000, 3.20e+000
100000000, 300000000
1.524723e-222, 3.200000e+000
-1610612736, 1074370969, -1717986918, 1074370969

下面分析一下为啥printf("%ld, %ld, %ld, %ld\n", x, y, z1, z2);中一个错大家都错的奇怪现象,看书发现:这是由于函数的参数传递机制会把这几个参数放到相邻的内存单元。具体地说,printf函数接收到4个参数, x,y z1,z2,于是把他们存入到一个叫做栈stack的地方,x和y由于被编译器转换为double,所以分别占8字节,而z1, z2分别占4字节,编译器看到%ld,就去读取4字节,于是每一个数据都错了。

在这里插入图片描述

好久没接触过栈了!!!

自从大二上了微机原理的课之后就没有接触过,看来果然要系统地看书学习,钻研每一个细节,不图快,才能把底层的东西,原理搞清楚,不然永远都只是在表层动土,没啥长进。

printf()也有返回值!!C函数都有返回值

它的返回值是本次打印的字符总数

#include <stdio.h>
int main()
{
    int returnValue = printf("We are talking about the return value of printf().\n");
    printf("returnValue=%d\n", returnValue);
    return 0;
}
We are talking about the return value of printf().
returnValue=51

注意包括换行符才是51个哈

不可以在双引号之间的某处换行,双引号之间只能用换行符,不可用enter表示换行

在这里插入图片描述像这样

#include <stdio.h>
int main()
{
    int returnValue = printf("We are talking about the return
                             value of printf().\n");
    printf("returnValue=%d\n", returnValue);
    return 0;
}

在这里插入图片描述

下面这样是可以的

#include <stdio.h>
int main()
{
    int returnValue = printf("We are talking about the returnvalue of printf().\n");
    printf("returnValue=%d\n",
           returnValue);
    return 0;
}

解决办法:(如果字符串有点长)

  • 最简单,用多个printf,有点麻烦
  • 加个反斜杠再enter,但是需要再退格使得反斜杠前后的字符不要距离太远
#include <stdio.h>
int main()
{
    int returnValue = printf("We are talking about the \
returnvalue of printf().\n");
    printf("returnValue=%d\n",
           returnValue);
    return 0;
}
  • 字符串连接,再多加一对双引号,最终把所有双引号去除,得到的字符串作为整体
#include <stdio.h>
int main()
{
    int returnValue = printf("We are talking about the "
"returnvalue of printf().\n");
    printf("returnValue=%d\n",
           returnValue);
    return 0;
}

scanf

在这里插入图片描述在这里插入图片描述在这里插入图片描述

总之%s是不可以读取多个单词的
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

在这里插入图片描述

scanf的返回值

在这里插入图片描述

#include <stdio.h>
int main()
{
    int x, y;
    y = scanf("%d", &x);
    printf("y = %d\n", y);
    return 0;
}
34
y = 1

printf和scanf的转换说明中*的作用

说实话,我快被printf 和scanf烦死了!!!!各种转换说明,各种修饰符,还有他们的读取字符的原理,他们可能出错的陷阱,各种各种,没想到简单的两个输入输出函数会有这么多细节,之前只是傻傻的用,······赶紧结束吧

不过这个*还是很有用的

printf中:用于控制输出字段宽度,包括浮点数的精度宽度

#include <stdio.h>
int main()
{
    int width = 6, x = 123, precision = 3;
    float y = 123.4567;
    printf("%*d\n", width, x);
    printf("%*.*f\n", width, precision, y);
    return 0;
}

可以看到输出参数列表需要说明*的宽度和d的数值,浮点数里面则要用两个 ∗ * ,通过这样指定字段宽度还会有四舍五入的效果

   123
123.457

scanf中:用于跳过一些转换说明

#include <stdio.h>
int main()
{
    int x;
    printf("enter 3 numbers:\n");
    scanf("%*d %d %*d", &x);
    printf("The second number is %d\n", x);
    return 0;
}
enter 3 numbers:
1 2 3
The second number is 2

不能在scanf的格式字符串里随意加逗号,格式字符串和参数列表的格式要一致,加了逗号会出错:

#include <stdio.h>
int main()
{
    int x;
    printf("enter 3 numbers:\n");
    scanf("%*d, %d, %*d", &x);
    printf("The second number is %d\n", x);
    return 0;
}
enter 3 numbers:
1 2 3
The second number is 4194432

使用固定字段宽度使得输出更美观整齐

#include <stdio.h>
int main()
{
    printf("%d  %d  %d\n", 1, 23, 345);
    printf("%d  %d  %d\n", 10, 230, 3450);
    printf("%d  %d  %d\n", 100, 2300, 34500);
    
    printf("%9d  %9d  %9d\n", 1, 23, 345);
    printf("%9d  %9d  %9d\n", 10, 230, 3450);
    printf("%9d  %9d  %9d\n", 100, 2300, 34500);
    return 0;
}

在这里插入图片描述

printf和scanf的区别和联系

printf是从各种形式的数据(文本,数值··)到文本
scanf是从文本到数值,文本
在这里插入图片描述

注意scanf的参数是指针!!!虽然数组上没用&,但实际也是指针
在这里插入图片描述在这里插入图片描述在这里插入图片描述

练习

在这里插入图片描述

#include <stdio.h>
#include <float.h>
int main()
{
    float x = 1.0/3.0;
    double y = 1.0/3.0;
    printf("%*.*f, %*.*f\n", 1, 6, x, 1, 6, y);
    printf("%*.*f, %*.*f\n", 1, 12, x, 1, 12, y);
    printf("%*.*f, %*.*f\n", 1, 16, x, 1, 16, y);
    printf("FLT_DIG: %d, DBL_DIG: %d\n", FLT_DIG, DBL_DIG);
    return 0;
}

可以看到float最少精确到了小数点后6位,第7位也是3,说明系统多精确了一位,double精确到小数点后15位,和FLT_DIG, DBL_DIG是一样的

0.333333, 0.333333
0.333333343267, 0.333333333333
0.3333333432674408, 0.3333333333333333
FLT_DIG: 6, DBL_DIG: 15

在这里插入图片描述

#include <stdio.h>
#include <string.h>
int main()
{
    char family[20], given[20];
    int x, y;
    printf("enter your given name:\n");
    scanf("%s", given);
    printf("enter your family name:\n");
    scanf("%s", family);
    x = strlen(given);
    y = strlen(family);
    printf("%s %s\n", given, family);
    printf("%*d %*d\n", x, x, y, y);
    printf("%s %s\n", given, family);
    printf("%-*d %-*d\n", x, x, y, y);
    return 0;
}
enter your given name:
Melissa
enter your family name:
Honeybee
Melissa Honeybee
      7        8
Melissa Honeybee
7       8
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值