标签:int C语言 char 操作符 整型 printf 表达式 库函数
C语言库函数说明
前言:
1.任何一个字符存储的时候在内存里存储的是它的ascii码值(整数int类型)。
2.照着文档写函数
3.库函数,自定义函数(有函数名,返回值类型,函数参数)
1.getchar,putchar函数
例子1:
int main()
{
int ch = getchar();
putchar(ch);
return 0;
}
例子2:
int main()
{
int ret = 0;
char password[20] = { 0 };
printf("先输入密码\n");
scanf("%s", password);
printf("请确认(y/n)");
ret = getchar();
if (ret =='y')
{
printf("正确");
}
else
{
printf("错误");
}
return 0;
}
假设一:如果我们输入123456敲回车,就没有getchar函数的执行过程,则结果为:
解释:执行逻辑和我们想要的逻辑有区别:password,getchar都为输入函数,输入函数要先检测输入缓冲区,这个区可能会放一些数据,输入函数在接收数据的时候。先是scanf函数去读输入缓冲区(起始什么都没有,等待输入东西),一旦输入缓冲区有东西,scanf函数拿走一部分,拿走之后scanf函数过去,getchar函数到来, (例如,你输入123456后敲击回车键让scanf函数读取123456,缓冲区保留\n),然后getchar读取\n,没有等待。
解决方案:(解决如何让输入缓冲区里面没有‘\n’)用一个getchar()读取‘\n’
int main()
{
int ret = 0;
char password[20] = { 0 };
printf("先输入密码\n");
scanf("%s", password);
getchar();//读取‘\n’
printf("请确认(y/n)");
ret = getchar();
if (ret =='y')
{
printf("正确");
}
else
{
printf("错误");
}
return 0;
}
假设二:加入getchar()后当我们输入123456 (空格)ABCD,则出现结果为:
分析:输入123456 ABCD,scanf函数读走123456,getchar读走空格,ret=getchar()一句读走了’A’,所以打印错误。
<font color="orae" size="3">解决方案:加入循环,直到读至‘\n’跳出循环。
int main()
{
int ret = 0;
int ch = 0;
char password[20] = { 0 };
printf("先输入密码\n");
scanf("%s", password);
while ((ch = getchar()) != '\n')
{
;
}
printf("请确认(y/n)");
ret = getchar();
if (ret =='y')
{
printf("正确\n");
}
else
{
printf("错误\n");
}
return 0;
}
补充一个问题:
int main()
{
int ch = 0;
while ((ch = getchar()) != EOF)
{
if (ch < '0' || ch > '9')
continue;
putchar(ch);
}
return 9;
}
在这个代码中,if (ch < ‘0’ || ch > ‘9’)从asc码值角度解读
操作符
注释:只要是进行运算,使用的都是内存里的补码,但是这个补码的前提是整数才有原反补的概念,非整数都不是原反补的概念。
分类:
算术,移位,位,赋值,单目,关系,逻辑,条件,逗号(表达式),下标引用,函数调用,结构成员
算术操作符:+,-,*,/,%
1.除法示例:
main()
{
int a = 5 / 2;//商2余1,5/2得到商
printf("a=%d\n", a);
}
为什么a不等于2.5呢?因为除号两端得到的数字一个是5,一个是2,都是整数,执行整数除法,不会得到小数结果。
如果让除号(/)两端的任何一个数为小数,那么执行的就是浮点数的除法,那么这就可以用浮点数来保存(即double,%lf)。
main()
{
double a = 5.0 /2;//商2余1
printf("a=%lf\n", a);
}
2.取模示例
对于取模来说,%两边的数字(操作数与被操作数)必须都是整数。返回的是整除之后的余数。
main()
{
int a = 5 %2;//商2余1
printf("a=%d\n", a);
}
补充:
1.除了%操作符外,其它的几个操作符可以作用于整数和浮点数
2.对于/操作符如果两个操作数都为整数,执行整数除法。.而只要有浮点数执行的就是浮点数的除法。
移位操作符:
<< 左移位操作符
>> 右移位操作符
注:它们的操作数必须是整数,这里的位是二进制位
1.右移操作符
<1>算术右移:右边丢弃,左边补原符号位(原来是正数补一个0,原来是负数,补个1)
<2>逻辑右移:右边丢弃,左边补0.
那么编译器采用哪种移位方式呢?
编译器采用的是算术移位,代码证明:
main()
{
int a = -1;
int b=a >> 1;//右移一位
printf("%d\n", b);
}
提出问题:为啥不是负的2的31次方?
(援引鹏哥)“内存里边儿移动的是补码,正式打印出来是源码呀。”<\font>
具体分析:
1.首先整数的二进制有三种表示:原码、反码、补码。
2.其次就是存到内存里面的是补码,所以a在移位的时候移的是补码(对于正整数来说,原,反,补相同)
3.再次就是a(a=-1,为负数)的原反补。
原:因为是负数,所以最高位写上1
10000000000000000000000000000001
反:(相对原码,符号位不变其它位按位取反)
1111111111111111111111111111111111110
补:(反码+1)
1111111111111111111111111111111111111
2.左移操作符
左边丢弃,右边补0.
补充:
对于移位运算符,不要移动负数位,这个是标准未定义的。例如:
int num=10;
num>>-1//error
位操作符:
& 按位与
| 按位或
^ 按位异或
注:它们的操作数必须是整数。这里的位是二进制位。
按位与:
两个数(a,b)进行二进制转化,同位比较,有一个0就为0,都是1才为1。(简记:一假即假,全真才真)
代码示例:
补充:计算一个数的补码的中有几个一,代码示例:
main()
{
int num,i;
int count=0;
scanf("%d", &num);
for (i = 0; i < 32; i++)
{
if ((num>>i)&1==1)
count++;
}
printf("count=%d\n", count);
}
按位或:
只要有1个为1就是1,两个同时为0才是0。(简记:一真即真,全假才假)
代码示例:
按位异或
两个数(a,b)对应的二进制位如果相同为0,相异为1。
加一道笔试题:不创建临时变量,交换2个int数的值
a=a^b;
b=b^a;
a=b^a;
赋值操作符:
对变量重新赋值(注意赋值操作符是一个=号,判断是否相等是两个=号)
操作符的连续使用
a=x=y+1;把y+1赋给x,把x再赋给a(这叫做赋值操作符的连续使用)
复合赋值符
+=,-=,*=,/=,%=,>>=,<<=,&=,|=,^=(这些操作符可以写成复合的效果,代码示例:)
int x=10;
x=x+10;
x+=10;//复合操作符
//其它运算符一样的道理,这样写更加简洁。
单目操作符:
何谓单目?就是只有一个操作数。那我们有哪些单目操作符呢?
! 逻辑反操作(真变成假,假变成真<固定为1>)
- 负号
+ 正值
& 取地址
* 解引用操作符
sizeof 变量(包括数组)所占内存空间的大小(以字节为单位)
~ 对一个数的二进制按位取反
- - 前置、后置
++ 前置,后置++
(类型) 强制类型转换
sizeof的使用
例子一:
main()
{
int a = 10;
char c = 'r';
char* p = &c;
int arr[10] = { 0 };
printf("%d\n",sizeof a);//整型4字节,a可以省略括号
printf("%d\n",sizeof(int));//算a的大小和算它类型的大小结果是一样的,int不可省略括号
printf("\n");
printf("%d\n",sizeof(c));//字符型
printf("%d\n",sizeof(char));
printf("\n");
printf("%d\n",sizeof(p));//指针大小是4或8
printf("%d\n",sizeof(char*));
printf("\n");
printf("%d\n",sizeof(arr));//数组的大小,数组一共10个元素,每个元素是一个整形,一个整形4个字节,所以4*10=40
printf("%d\n",sizeof(int[10]));//int[10]是数组的类型(数组去掉数组名)
printf("\n");
}
结果:
例子二:
main()
{
short s = 0;
int a = 10;
printf("%d\n", sizeof(s = a + 5));//不管a什么类型,只要放到s那,就只能变成短整型,结果由s说的算,s两个字节
printf("%d\n", s);//s能放下15,之所以输出0;是因为sizeof(s=a+5)中的表达式是不会真实进行计算的,s的值不变
}
结果:
++前后置的使用
例子:
(类型):强制类型转换
例如:
int a =(int)3.14;
关系操作符
>
>=
<
<=
== 用于测试"相等"
!= 用于测试"不相等"
逻辑操作符
&& 逻辑与
|| 逻辑或
区分逻辑与按位
逻辑与,逻辑或关注的是这个数的本身是真还是假
按位与,按位或关注的是这个数的二进制序列
深度解释
逻辑与的特点是如果左边算出的结果为假,那么无论右边是什么我们都不算了。相似的,逻辑或的特点是如果左边为真,右边就不要算了。代码示例如下:
main()
{
int i = 0, a = 0, b = 2, c = 3, d = 4;
i = a++&&++b&&d++;//a++的结果为0,&&的关系是只要一个为0的话,右边不管是什么,都为假,那么后边不执行,++b,d++不执行,a使用之后自增1
printf("a=%d\n b=%d\n c=%d\n d=%d\n", a,b,c,d);
}
结果为:
条件操作符(又名三目操作符)
exp1?exp2:exp3
解释:如果表达式1的结果为真,那么表达式2的结果是整个表达式的结果。如果表达式1的结果为假,那么表达式3的结果是整个表达式的结果。
逗号表达式
由逗号隔开的一段表达式:exp,exp2,exp3…
逗号表达式,从左向右依次执行,整个表达式的结果是最后一个表达式的结果。
下标引用,函数调用和结构成员
1.[ ]下标引用操作符
操作数:一个数组名+一个索引值
2.()函数调用操作符
接受一个或多个操作数,第一个操作数是函数名,剩余的操作数就是传递给函数的参数
3.访问一个结构的成员
. 结构体,成员名
-> 结构体指针->成员名
代码示例:
//创建一个结构体类型-struct Stu
struct stu
{
//成员变量
char name[20];
int age;
char id[20];
};
main()
{
//使用struct Stu这个类型的变量创建了一个学生对象s1,并初始化
struct stu s1 = { "张三", 20, "20210910" };
struct stu* ps = &s1;
//结构体指针->成员名
printf("%s\n", ps->name);//ps是指针,指向了对象
printf("%d\n", ps->age);
printf("%s\n", ps->id);
//结构体变量.成员名
printf("%s\n", s1.name);
printf("%d\n", s1.age);
printf("%s\n", s1.id);
}
表达式求值
表达式求值的顺序一部分是由操作符的优先级和结合性决定。同样,有些表达式的操作数在求值的过程中可能需要转换为其它类型。
隐式类型转换
整型提升
C的整型算术运算总是至少以缺省整型类型的精度来进行的。
为了获得这个精度,表达式中的字符和短整型操作数在使用之前被转换为普通整形,这种转换称为整型提升。
整型提升的意义
示例一:
char a,b,c;
a=b+c;
b和c的值将被提升为普通整形,然后再执行加法运算。
加法运算完成之后,结果可被截断,然后再存储于a中。
main()
{
char a = 3;
//00000000000000000000000000000011
//00000011-a
char b = 3;
//01111111-b
char c = a + b;
//10000010放在c里面,高位为符号位,负数转换原反补(区别正数)
//11111111111111111111111110000010-补码
//11111111111111111111111110000001-反码
//10000000000000000000000001111110-原码
printf("%d\n", c);//-126
}
如何进行整型提升的呢?
整型提升是按照变量的数据类型的符号位来提升的
负数的整型提升
char c1=-1;
变量c1的二进制位(补码)中只有8个比特位:
1111111
因为char是有符号的char
所以整形提升的时候,高位补充符号位,即为1
提升之后的结果为:
11111111111111111111111111111111
正数的整型提升
char c2=1;
变量c2的二进制位(补码)中只有8个比特位:
00000001
因为char是有符号的char
所以整形提升的时候,高位补充符号位,即为0
提升之后的结为:
00000000000000000000000000000001
无符号的整型提升,高位补0
示例二:
main()
{
char c = 1;
printf("%d\n",sizeof(+c));
}
示例二中的c只要参与表达式运算,就会发生整型提升,所以sizeof(+c)是四个字节。表达式的结果为:
算术转换
算术转换也是一种隐式类型转换。如果某个操作符的各个操作数属于不同的类型,那么除非其中一个操作数转换为另一个操作数的类型,否则操作就无法执行。下面的层次体系称为寻常算术转换。
long double
double
float
unsigned long int
long int
unsigned int
int
如果某个操作数的类型在上面这个列表中排名较低(小的类型),那么首先转换成另外一个操作数的类型(大的类型)后执行运算。
操作符的属性
复杂表达式的求值有三个影响的因素。
1.操作符的优先级
2.操作符的结合性
3.是否控制求值顺序
两个相邻的操作符先执行哪个?取决于他们的优先级。如果两者优先级相同,取决于它们的结合性。
操作符的优先级
总结:我们写出的表达式如果不能通过操作符的属性确定唯一的计算路径,那这个表达式就是存在问题的。
标签:int,C语言,char,操作符,整型,printf,表达式,库函数 来源: https://blog.csdn.net/yanghang666666/article/details/120157900
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。