【C语言篇】☞ 2. 常量、变量、scanf函数和printf 函数
常量
C语言有丰富的数据类型,在开发中,一般用常量或者变量来表示这些数据
"量"表示数据。常量,则表示一些固定的数据,也就是不能改变的数据。
10.1;// 双精度double 5.2f; //单精度float 'a'; // 字符型常量 'ab'; // 错误 '李'; // 错误写法, 因为一个汉字占3个字节 '\n';//字符型常量(转义字符,表示单个字符) |
定义常量的方法:
const int a=100;
变量
变量:代表了内存的一个空间,用来存放经常变化的数据。(变量名就是空间的名称,变量的类型决定着变量占用多大的内存空间)
变量名:是我们操作数据(存放数据)的依据。
初始化:就是清空(赋初值,0/NULL)的意思,清理一些垃圾数据。
变量的使用:存值和取值。
int a; //定义一个变量,未初始化。
a的值的可能性:1) 系统的数据; 2) 上一个程序遗留的数据; 3) 垃圾数。
变量的作用域:(变量的使用范围)
局部变量(内部变量):在函数的内部或者代码块的内部定义的变量。
※ 作用域:从局部变量定义的位置开始,到它所在的代码块或函数体的“}”为止。
※ 注意:在代码块的内部可以定义和块外部同名的变量,块内部的会暂时屏蔽(外部的不起作用)块外部的变量的作用域。
#include <stdio.h>
int main() { int age=20; //代码块代表一个空间,与age的空间并列 {//代码块开始 int a=5; printf("a=%d\n", a); //a=5 int age=25; //在代码块内部可以定义和代码块外部同名的变量 printf("age=%d\n",age); //age=25; }//代码块结束(此时代码块内部所有的空间会释放) printf("age=%d\n", age);//age=20; return 0; } |
变量的命名:命名需要符合标识符语法要求。
- 必须以字母或下划线开头
- 包含字母、下划线或数字
- 大小写敏感的
- 不能与关键字冲突
- 标识符理论上讲,长度无限制,但太长了会被编译器截断
变量的声明(定义):在相同的作用域内变量不可重复定义!
语法格式:变量类型 变量名;
如: int age;
float result;
double x,y,z;
变量类型:表示我所定义的这个变量可以存放什么样类型的常量
变量名称:它一个标示符,来标识我们在内存中开辟这块存储区域,方便我们以后使用
变量的作用域:从定义那一行开始直到其所在大括号结束为止
//1.定义变量(即在内存中开辟一块空间,空间的大小跟定义的类型有关,空间的名字就是变量名)
int age;//这一行代码就在内存中开辟一块4个字节的存储区域,它名字叫age;这块存储区域是用来存放int类型的数据的
//2.初始化:变量第一次赋值称为初始化。
age=22; //这行代码是把22,放到名字为age的这块存储区域中
- 未经声明的变量不能使用;变量在使用之前要声明,且只声明一次。
- 变量用来保存程序执行过程产生的临时值,可以多次赋值,但只会保存最后一次的值。
变量的存储
- 变量所占的存储空间(字节数):跟变量的类型和编译器环境有关。
- 变量存储单元的第一个字节的地址就是该变量的地址(详细地址/首地址)
- 任何变量在内存中都是以二进制的形式存储:
一个负数的二进制形式,其实就是对它的正数的二进制形式进行取反再加1。
1. 不同的数据类型占用不同的存储空间:
2. 不同数据类型表示的范围:
变量在内存中怎么储存?(变量为什么要有类型)
- 只要定义变量,系统就会开辟一块存储空间给我们的变量存储数据
- 越先定义的变量,内存地址越大(从字节地址最大的开始找)
- 内存寻址是从大到小,高位放在高字节上,低位放在低字节上
- 变量的地址就是变量所占的存储空间最小的字节地址(即首地址:&变量名称)
计算机中最小储存单元是字节,每个字节都有一个地址。
// 扩展:获取每个字节中存储的数据 char *p = &value; for (int i = 0; i < sizeof(value); i++) { printf("%i\n", *(p + i));// 取出每个字节中存储的数据(88 2 0 0) } |
注意:在这里,地址(int型指针)+1 相当于 char型指针+4
// 当定义变量的时候,这个变量里面究竟有什么东西是不确定的
int score;//垃圾值
// printf函数打印 % 字符要用 %% 才能打印
printf("5%%2=%d\n",5%2);//结果为:5%2=1
交换整型变量a、b的值:
比如:a=10、b=11;交换后:a=11,b=10。用两种方式实现:
- 使用第三方变量
int temp;
temp = a;
a = b;
b = temp;
- 不使用第三方变量
a = b - a;
b = b - a;
a = b + a;
printf 函数:
printf函数称为格式输出函数,其关键字最末一个字母f即为“格式”(format)之意
printf函数调用的一般形式为:(其中格式控制字符串用于指定输出格式)
printf(“格式控制字符串”, 输出表列);
格式字符串的一般形式为:(其中方括号[]中的项为可选项)
%[标志][输出最小宽度][.精度][长度]类型。
//利用printf函数可以计算字符串的长度 int length = printf("iOS开发\n"); printf("共占%i个字节\n", length);// 10 (1+1+1+3+3+1) |
1. 类型(格式控制符)
2. 标志
标志字符为 -、+、# 和空格四种,其意义下表所示:
- 指定位宽:
- %0nd:在%与d之间,0n,n表示输出的数字的宽度,如果不够就用0补齐左边(重点)
- %nd:在%与d之间n,n表示输出的数字的宽度,如果不够就用空格补齐左边
- %-nd:在%与d之间 -n,n表示输出的数字的宽度,如果不够就用空格补齐右边
- 指定位数:
%m.nf:在%与f之间,可以有m.n,m表示输出数字所占的宽度,m表示小数点后面的位数,如果不够会用空格补齐左边
#include <stdio.h>
int main() { float m=3.141592f; printf("m=%8.4f\n", m);//默认空格补在左边 // %-m.nf 输出共占m位,其中小数占n位,如果数值宽小于m右端补空格 printf("m=%-8.4f\n", m);//-号表示空格补右边 // %*.*特殊用法: printf("m=%*.*f\n",6,2,m);//m= 3.14 printf("%.*s\n",4,"abcdkkkkkkk");//abcd return 0; } |
%g:自动选f格式或e格式中较短的一种输出,且不输出无意义的零。
%p:输出地址(指针)
/** * %f默认会保留6位小数 * 指定保留多少位小数: %.nf, 其中n就是需要保留多少位小数, f用于输出实型 */ float value = 3.14; printf("%f\n", value);//3.140000 printf("%.2f\n", value);//3.14 |
/** * float和double的有效位数: * float最多表示7位有效数据。double最多表示16位有效数据。 * * float类型要点: * 1.小数末尾要加f/F,指定为float类型 * 2.默认情况保留6位小数 * 3.精度为7位有效数字(左边第一个不为零的数开始,除小数点外前7位数字有效,超出7位的是垃圾数据) * 1bit(符号位) 8bits(指数位) 23bits(尾数位) 精度是由尾数的位数来决定的 float:2^23 = 8388608,一共七位,这意味着最多能有7位有效数字, 但绝对能保证的为6位,也即float的精度为6~7位有效数字; */ float value = 3.1415926525; printf("%f\n", value);//3.141593 (默认情况保留6位) //float有效数字是7位,多余位数则会显示垃圾数据(不准确) printf("%.10f\n", value); //3.1415927410
// 如何想完整的输出那么必须将数据保存为double类型, 因为double类型的有效位是15位 double value = 3.1415926525; printf("%.10lf\n", value);
//如何提高逼格(保留几位小数不确定时) //指定保留多少位小数时,可以通过*号占位,以后赋值具体保留的小数位 float value = 3.1415926; printf("%.*f\n", 5, value); |
&是C语言中的一个地址运算符,可以用来获取变量的地址
&可以获取变量的地址,例如:&num
*可以根据地址数据找到变量,例如:*(&num)
scanf 函数
scanf函数是一个阻塞式函数
程序会停在scanf函数出现的地方,直到接收到数据才会执行后面的代码
// 使用scanf接收用户从键盘上输入
scanf("%d", &a);//注意: 必须告诉scanf函数变量的详细地址, 才能存储用户输入的数据
// %与d之间可以有数字n,这个n表示接受数据的宽度
scanf("%2d",&a);
scanf 函数要点:
- 键盘输入的数据与格式化字符串中的要匹配, 不匹配时scanf函数就会自动终止。
- scanf接收多个数据时,为了防止出错一般加一个分隔符(例如:,)
(空格、回车、Tab可以做%c除外的分隔符,因为空格、回车、Tab是字符)
- 不能在scanf的格式化字符串末尾写上\n
// \n代表换行 // 如何告诉scanf函数我们输入完毕? 回车(\n) // 因为回车是scanf的结束符, 所以不能在scanf的格式化字符串末尾写上\n。(如果加在末尾,会永远结束不了输入,即scanf函数不会终止) // 如果不小心把\n放到了scanf格式化字符串的末尾,也可以破,原样输入(输 \n)或输入一个不匹配的类型(如:输 a) scanf("%i%i\n", &num1, &num2); |
scanf函数实现原理
scanf函数的运行原理:
系统会将用户输入的内容放入输入缓冲区
scanf函数会从输入缓冲区中逐个取出内容赋值给格式符,如果类型不一致不会修改原有数据。
scanf录入数据的时候,录入格式必须与格式化字符串中格式一致
- scanf("%d-%d-%d", &a, &b, &c);
注意:scanf占位符中间分割符可以是任意的,不一定要用中划线-,可以是逗号、空格、星号*、井号#等等,甚至是英文字母
- scanf("%d %d %d", &a, &b, &c);
3个%d之间是用空格隔开的,我们在每输入一个整数后必须输入一个分隔符,分隔符可以是空格、tab、回车
scanf格式字符串最后面不要加\n,比如scanf("%d\n", &a);这将导致scanf函数无法结束。
面试题
int a;
请问a里面有值吗,是多少? 垃圾值
//判断一个年份是否是闰年 //能被4整除,但(并且)不能被100整除,或者能被400整除 int year;//保存年份 printf("请输入一个年份:"); scanf("%d", &year); if((year%4==0 && year%100!=0) || year % 400 == 0){ printf("是闰年\n"); }else{ printf("不是闰年"); } |
※ 变量分析题:(注意变量的作用域)