1、书接上回,运算符的使用
1.1 sizeof运算符
sizeof运算符用来计算数据类型的占用内存空间的大小,单位为字节。
格式:
sizeof(数据类型名);
64位系统:返回long int类型,使用格式化字符-》%ld
32位系统:返回int类型,使用格式化字符-》%d
#include <stdio.h>
int main(int argc, const char *argv[])
{
//#define X86_64
#ifdef X86_64
printf("unsigned char size = %ld\n", sizeof(unsigned char));
printf("unsigned short size = %ld\n", sizeof(unsigned short));
printf("unsigned int size = %ld\n", sizeof(unsigned int));
printf("unsigned long size = %ld\n", sizeof(unsigned long));
printf("unsigned long long size = %ld\n", sizeof(unsigned long long));
printf("float size = %ld\n", sizeof(float));
printf("double size = %ld\n", sizeof(double));
printf("long double size = %ld\n", sizeof(long double));
#else
printf("unsigned char size = %d\n", sizeof(unsigned char));
printf("unsigned short size = %d\n", sizeof(unsigned short));
printf("unsigned int size = %d\n", sizeof(unsigned int));
printf("unsigned long size = %d\n", sizeof(unsigned long));
printf("unsigned long long size = %d\n", sizeof(unsigned long long));
printf("float size = %d\n", sizeof(float));
printf("double size = %d\n", sizeof(double));
printf("long double size = %d\n", sizeof(long double));
#endif
return 0;
}
1.2 逗号运算符
格式:
(表达式1, 表达式2, 表达式3,....);
最后一个表达式的结果被返回。
#include <stdio.h>
int main(int argc, const char *argv[])
{
int a = 10;
int b = 20;
int c = 30;
int d = (a++, ++b, --c); // a = 11 b = 21 c = 29 d = 29
// 逗号运算符里边的所有的表达式都被执行了,
// 只是最后一个表达式的结果被返回。
// 在使用逗号运算符时,必须在最外边添加(),不可以省略
printf("a = %d, b = %d, c = %d, d = %d\n",
a, b, c, d);
// int f = ++a,++b; // 错误
return 0;
}
1.3 运算符的优先级
运算符优先级从高到低: 单算移关与,异或逻条赋,逗号
单 :+(正数) -(负数) ++ -- ~(按位取反) !(非)
算 : + - * / %
移 : << >>
关 : > < >= <= != ==
与 : &(按位与)
异 : ^(按位异或)
或 :|(按位或)
逻 :&& ||
条 : ?:
赋 : = += -= *= /= %= &= |= ^= <<= >>=
逗号 : ,
同级运算符结合的问题:
单条赋:从右到左结合,
比如:a = b = 1; 从右到左结合,先把1赋值给b,再把b赋值给a
剩余的都是从左到右结合
比如:a && b && c; 从左到右结合,先进行a && b,结果在&&c
可以参考《运算符优先级.docx》文档,已经上传有道云笔记中。
2、常用的输入输出函数
学习任何一个函数,都要先掌握函数的功能,参数,返回值。
系统提供的函数都有可以使用man查看对应的帮助手册。
man man ---> 查看man的帮助手册
1 可执行程序或 shell 命令
2 系统调用(内核提供的函数)
3 库调用(程序库中的函数)
4 特殊文件(通常位于 /dev)
5 文件格式和规范,如 /etc/passwd
6 游戏
7 杂项(包括宏包和规范,如 man(7),groff(7))
8 系统管理命令(通常只针对 root 用户)
9 内核例程 [非标准
man 3 库函数的名字,比如 man 3 putchar
2.1 putchar/getchar函数
2.1.1 putchar函数
#include <stdio.h>
int putchar(int c);
| | |---> 函数的形参,调用函数时需要传递一个实参。
| |----> 函数的名字
|---> 函数返回值的类型,可以使用对应类型的变量接收函数的返回值
功能:输出一个字符到终端
参数:
@ c : 要输出的字符
1> 可以是一个字符常量
2> 可以是一个字符类型的变量
3> 可以是一个字符对应的ASCII码值
4> 可以是一个整数,输出整数对应ASCII码表中的字符,
如果超过ascii码表的最大值,输出一个乱码。
5> 可以是一个经过运算的表达式,表达式的结果是一个整数。
返回值:
成功返回写到终端上的字符的对应的整数值,
失败返回错误码EOF(-1);
#include <stdio.h>
int main(int argc, const char *argv[])
{
// 1. 可以传递字符常量
int retVal = putchar('A');
// 有可能失败,因此需要进行出错处理
if (retVal == -1)
{
printf("输出字符失败\n");
return -1;
}
else
{
printf("输出字符成功:%c --- %d\n", retVal, retVal);
}
// 2. 可以传递字符类型的变量
char ch = 'a';
putchar(ch);
putchar('\n'); // 输出一个换行符
// 3. 可以传递一个整数值
putchar(97); // a 的ascii码值为97
putchar(10); // /n 的ascii码值为10
// 4. 可以是一个结果为整型的表达式
putchar('A'+33);
putchar(5+5);
return 0;
}
2.2.2 getchar函数
#include <stdio.h>
int getchar(void);
功能:从终端获取一个字符
参数:
无
返回值:
成功:返回接收字符对应的ascii码值
失败:返回错误码EOF(-1)
#include <stdio.h>
int main(int argc, const char *argv[])
{
char a, b, c;
// 使用getchar连续接收3个字符
a = getchar();
b = getchar();
c = getchar();
printf("a = %c, b = %c, c = %c\n", a, b, c);
return 0;
}
#include <stdio.h>
int main(int argc, const char *argv[])
{
char a, b, c;
// 使用getchar连续接收3个字符
a = getchar();
getchar(); // 处理垃圾字符,只能处理一个垃圾字符
b = getchar();
getchar();
c = getchar();
printf("a = %c, b = %c, c = %c\n", a, b, c);
return 0;
}
2.2 puts/gets函数
2.2.1 puts函数
#include <stdio.h>
int puts(const char *s);
功能:向终端输出一个字符串
参数:
@ s : 输出字符串的首地址
1> 可以是字符串常量
2> 可以是字符数组的名字
3> 可以是指向一个字符串的字符指针
返回值:
成功:返回一个非负的整数, 发送成功的字符串的个数(字符串长度+1)
失败:返回错误码EOF(-1)
注:puts函数在发送字符完成之后,会自动补发一个'\n'换行符
#include <stdio.h>
int main(int argc, const char *argv[])
{
// c语言的字符串的结尾为'\0',输出字符串时遇到'\0'停止输出
// 1. 可以传递一个字符串常量
// 字符串发生结束之后自动补发一个'\n'字符
int retVal = puts("hello world!!!");
// EOF系统提供的错误码,本质就是一个宏定义
// #define EOF -1
if ( retVal != EOF)
{
printf("发生字符串成功:%d\n", retVal);
}
else
{
printf("发生字符串失败\n");
return EOF;
}
puts(""); // 发生一个换行符
// 2. 可以传递一个字符数组
// 数组名就表示字符数组的首地址
char name[20] = "zhangsan";
puts(name);
// 3. 可以传递一个执行字符串的字符指针
char *str_p = "nihao"; // 字符指针指向一个字符串串常量
// str_p中存放的就是字符串常量的首地址
puts(str_p);
// 输出字符串时遇到'\0'结束
puts("hello\0world"); // 输出hello
return 0;
}
2.2.2 gets函数
#include <stdio.h>
char *gets(char *s);
功能:从标准输入获取一个字符串
参数:
@ s : 将接收的字符串存到哪个地址中
返回值:
成功:返回s,及接收字符串的缓冲区的首地址
失败:返回NULL
注:gets可以接收中断所有输入的字符包括空格,当输入回车时,输入结束,
最终会在字符串的结尾补一个'\0'.
即使输入的字符串的长度大于接收字符串缓冲区的长度,也可以接收,
并不会进行越界的检查,但你在此打印字符串时,就会越界访问内存空间,
就会出现段错误。
#include <stdio.h>
int main(int argc, const char *argv[])
{
// 将接收的字符串存放一个字符数组的缓冲区
char buffer[20]; //缓冲区最多接收19个字符,最后存一个'\0'
printf("please input a string, char number < 20 > ");
// 从终端获取字符串,有多少接收多少,并不会进行越界的检查
// 如果越界之后,访问非法空间时,执行程序可能会报段错误
// 一旦出现段错误一般都是访问了非法的内存空间。
// 在实际的开发中一般解bug遇到最多的错误就是段错误,
// 这种错误在程序编译时不会报错,执行时才会报错。
char *retVal = gets(buffer);
if (retVal == NULL)
{
puts("从标准输入获取字符串失败");
return -1;
}
puts(buffer);
return 0;
}
2.3 printf/scanf函数
2.3.1 printf函数
#include <stdio.h>
int printf(const char *format, ...);
功能:向终端输出一个格式化字符串
参数:
@ format : 参数控制格式的字符串
@ ... : 可变参数, 可变参数有几个由format中的格式字符决定,
可变参数会依次替换format中的格式化占位符,
要求参数的类型和格式化字符要一一对应。
返回值:
成功返回正数,失败返回负数
格式化字符:
#include <stdio.h>
int main(int argc, const char *argv[])
{
int x = 0x12345678;
printf("Dct x = %d\n", x);
printf("Dct x = %u\n", x);
printf("Oct x = %o\n", x);
printf("Oct x = %#o\n", x);
printf("Hex x = %x\n", x);
printf("Hex x = %#x\n", x);
printf("char c = %c\n", 'A');
printf("string str = %s\n", "hello world!");
double Pi = 3.141500;
printf("Pi = %lf\n", Pi); // 默认输出小数点后6位
printf("Pi = %le\n", Pi);
printf("Pi= %g\n", Pi); // 3.1415
printf("Pi = %10lf\n", Pi);
// 占10位宽度,默认右对齐, 不足补空格,
// 超过10位宽度原样输出
printf("Pi = %010lf\n", Pi); //
// 占10位宽度, 默认右对齐,不足补0,
// 超过10位宽度原样输出
printf("Pi = %10.3lf\n", Pi);
// 浮点数,.3保留小数的后三位,不足3位补0
printf("Pi = %-10.5lf\n", Pi);
// - : 左对齐
return 0;
}
2.3.2 scanf函数
#include <stdio.h>
int scanf(const char *format, ...);
功能:从终端接收数据
参数:
@ format : 格式控制字符串
@ ... : 可变参数,需要提供的是变量的地址,
只有提供的是地址时,才可以将通过终端读取的数据存到变量对应的空间中。
返回值:
成功返回正数,失败返回负数。
#include <stdio.h>
int main(int argc, const char *argv[])
{
char c;
// 变量名前加&符号,表示对变量取地址
printf("please input char type data > ");
scanf("%c", &c);
printf("c = %c\n", c);
short s;
printf("please input short type data > ");
scanf("%hd", &s);
printf("s = %hd\n", s);
int i;
printf("please input int type data > ");
scanf("%d", &i);
printf("i = %d\n", i);
float f;
printf("please input float type data > ");
scanf("%e", &f);
printf("f = %e\n", f);
char name[20];
printf("please input string type data > ");
scanf("%s", name);
printf("name = %s\n", name);
return 0;
}
#include <stdio.h>
int main(int argc, const char *argv[])
{
#if 0
// 1. 可以同时接收多个参数
int a, b;
printf("please input two number(int,int) > ");
// 当输入多个参数时,多个参数的输入可以以空格,tab键,回车分隔,
// 系统会自动的吃掉空格,tab键和回车符。
scanf("%d%d", &a, &b);
printf("a = %d, b = %d\n", a, b);
#endif
#if 0
// 2. scanf格式化字符串中除了格式化字符以外,
// 还有很多其他的字符,需要按照格式化字符串原样进行输入,
// 否则结果出错
int year,mouth,day;
printf("please input year, mouth, day > ");
scanf("year=%d,mouth=%d,day=%d", &year,&mouth,&day);
printf("%d:%d:%d\n", year,mouth,day);
#endif
#if 0
// 3. scanf默认不可以获取带有空格的字符串,
// 默认遇到一个空格之后,输入结束
char name[20];
// printf("please input your name > ");
// scanf("%s", name);
// printf("name = %s\n", name);
// 方式1:使用gets可以接收带空格的字符串
// printf("please input your name > ");
// gets(name);
// printf("name = %s\n", name);
// 方式2 : 使用[^\n]符号,除了\n以外的所有字符都接收
printf("please input your name > ");
scanf("%[^\n]s", name);
printf("name = %s\n", name);
#endif
#if 0
// 以下几种情况,当输入数据之后,系统无法自动吃掉
// 空格,tab键,回车符,scanf函数处于阻塞无法退出,
// 当按下任意一个字符之后,在回车就会退出。
// 因此在使用scanf函数时,格式化字符串的结果不要有
// 空格, \t \n \r
int a, b, c;
//scanf("%d\n", &a);
scanf("%d\t", &b);
// scanf("%d ", &c);
#endif
#if 0
// 将\n \t \r, 空格写到格式化字符的前边,
// 系统会自动的吃掉\n,\t,\r,空格。
int a, b, c;
//scanf("\n%d", &a);
scanf("\t%d", &b);
// scanf(" %d", &c);
#endif
return 0;
}
scanf接收字符时,处理垃圾字符的问题。
#include <stdio.h>
int main(int argc, const char *argv[])
{
int a, b;
char oper;
printf("请输入一个表达式(l # r) > ");
// 输入三个参数时,三个参数以空格分割,空格也是一个字符
// 被%c接收之后,赋值给oper,对于程序来说,空格就是一个
// 垃圾字符,需要处理垃圾字符
// scanf("%d%c%d", &a, &oper, &b);
// 方式1:使用%*c 吃掉一个垃圾字符
#if 0
// scanf("%d%*c%c%*c%d", &a, &oper, &b);
scanf("%d", &a);
scanf("%*c"); // 吃掉垃圾字符
scanf("%c", &oper);
scanf("%*c");
scanf("%d", &b);
#endif
// 方式2:使用getchar()函数接收一个垃圾字符
scanf("%d", &a);
getchar(); // 吃掉垃圾字符
scanf("%c", &oper);
getchar();
scanf("%d", &b);
// 在接收字符类型的变量时需要思考是否需要吃掉垃圾字符
if (oper == '+')
{
printf("a + b = %d\n", a + b);
}
if (oper == '-')
{
printf("a - b = %d\n", a - b);
}
return 0;
}
3、if...else分支语句
3.1 语法格式
1. if
if (表达式)
{
C语句块;
}
执行过程:“表达式”成立,执行“C语句块”,
“表达式”不成立,跳过“C语句块”,向下继续执行
2. if...else...
if (表达式)
{
C语句块1;
}
else
{
C语句块2;
}
执行过程:“表达式”成立,执行“C语句块1”,
“表达式”不成立,执行“C语句块2”,执行完成之后在向下执行
3. if...else if ... else...
if (表达式1)
{
C语句块1;
}
else if (表达式2)
{
C语句块2;
}
else if (表达式3)
{
C语句块3;
}
...此处省略很多else if...
else /* else 分支可以省略不写*/
{
C语句块n;
}
执行过程:判断表达式1是否成立,如果成立执行C语句块1,
执行完C语句块1之后,后边的所有的判断都不在进行判断,即使成立。
如果表达式1不成立,则判断表达式2,如果成立执行C语句块2,
执行完C语句块2之后,后边的所有的判断都不在进行判断,即使成立。
其他的都是一样的依次类推。
只有前边所有的表达式都不成立时,才会执行else分支对应的C语句块n.
表达式:只要是一个可以表示真假的表达式都可以。
一般为逻辑表达式,判断表达式
3.2 案例
1. 从终端输入一个字符,判断字符为大写字符,小写字符,数字。
#include <stdio.h>
int main(int argc, const char *argv[])
{
char ch;
printf("please input a char > ");
scanf("%c", &ch);
if (ch >= 'a' && ch <= 'z')
{
printf("%c是一个小写字符\n", ch);
}
else if (ch >= 'A' && ch <= 'Z')
{
printf("%c是一个大写字符\n", ch);
}
else if (ch >= '0' && ch <= '9')
{
printf("%c是一个数字\n", ch);
}
else
{
printf("%c既不是大小写字符,也不是数字\n",ch);
}
return 0;
}
-------------------------------------
#include <stdio.h>
int main(int argc, const char *argv[])
{
char ch;
printf("please input a char > ");
scanf("%c", &ch);
if ((ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z') && (ch < '0' || ch > '9'))
{
printf("%c既不是大小写字符,也不是数字\n",ch);
return -1;
}
if (ch >= 'a' && ch <= 'z')
{
printf("%c是一个小写字符\n", ch);
}
else if (ch >= 'A' && ch <= 'Z')
{
printf("%c是一个大写字符\n", ch);
}
else
{
printf("%c是一个数字\n", ch);
}
return 0;
}
从终端输入薪资,选则不同的交通工具。
#include <stdio.h>
int main(int argc, const char *argv[])
{
int salary;
printf("请输入你的薪资 > ");
scanf("%d", &salary);
if (salary < 0)
{
printf("输入的薪资不合理请重新输入\n");
return -1;
}
if (salary <= 10000)
{
printf("地铁\n");
}
else if (salary <= 30000)
{
printf("出租\n");
}
else if (salary <= 50000)
{
printf("自驾\n");
}
else if (salary <= 100000)
{
printf("专职司机\n");
}
else
{
printf("自由选择\n");
}
return 0;
}
练习题1:
在终端输入一个整数,用来表示学生的成绩
输出学生成绩对应的等级
[90,100] A
[80, 90) B
[70, 80) C
[60, 70) D
[0,60) E
#include <stdio.h>
int main(int argc, const char *argv[])
{
int score;
printf("请输入成绩 > ");
scanf("%d", &score);
if ( score < 0 || score > 100)
{
printf("输入成绩不合理请重新输入\n");
return -1;
}
if (score >= 90 && score <=100)
{
printf("等级A\n");
}
else if (score >= 80 && score < 90)
{
printf("等级B\n");
}
else if (score >= 70 && score < 80)
{
printf("等级C\n");
}
else if (score >= 60 && score < 70)
{
printf("等级D\n");
}
else
{
printf("等级E\n");
}
if (score >= 90 /*&& score <=100*/)
{
printf("等级A\n");
}
else if (score >= 80 /* && score < 90 */)
{
printf("等级B\n");
}
else if (score >= 70 /* && score < 80 */ )
{
printf("等级C\n");
}
else if (score >= 60 /* && score < 70 */)
{
printf("等级D\n");
}
else
{
printf("等级E\n");
}
// 如果if...else分支中只有1条c语句,可以省略{}
if (score >= 90)
printf("等级A\n");
else if (score >= 80 && score < 90)
printf("等级B\n");
else if (score >= 70 && score < 80)
printf("等级C\n");
else if (score >= 60 && score < 70)
printf("等级D\n");
else
printf("等级E\n");
return 0;
}
练习题2:
在终端输入一个整数,用来表示年份,输出这一年是平年还是闰年
闰年:能被4整除且不能被100整除,或者能被400整除
#include <stdio.h>
int main(int argc, const char *argv[])
{
int year;
printf("请输入年份 > ");
scanf("%d", &year);
if (year <= 0)
{
printf("输入的年份不合理\n");
return -1;
}
if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0))
{
printf("%d年是闰年\n", year);
}
else {
printf("%d年是平年\n", year);
}
return 0;
}
练习题3:
在终端输入三个整数,分别表示三角形的三边长
输出能否构成三角形
如果能构成三角形,再输出能构成什么类型的三角形:等腰、等边、直角、普通。
使用if嵌套。
#include <stdio.h>
int main(int argc, const char *argv[])
{
int a, b, c;
puts("请输入三角形的三个边长(a,b,c) > ");
scanf("%d%d%d", &a, &b, &c);
if (a <= 0 || b <= 0 || c <= 0)
{
puts("输入的边长至少有一个小于等于0");
return -1;
}
if (a + b > c && a + c > b && b + c > a)
{
puts("可以构成三角形");
if (a == b && b == c /* && a == c */ )
{
puts("等边三角形");
}
else if (a == b || b == c || a == c)
{
puts("等腰三角形");
}
else if (a*a + b*b == c*c || a*a + c*c == b*b || b*b + c*c == a*a)
{
puts("直角三角形");
}
else
{
puts("普通三角形");
}
}
else
{
puts("不可以构成三角形");
}
return 0;
}