#### 计算基础 #########
CPU(核心) 内存条(RAM) 固态硬盘(flash) 设备
CPU: 运算能力强
内存条(RAM): 速度快XX Gbps,掉电丢失数据 贵 运行内存 8G 16G
固态硬盘(FLASH): 速度慢 5Gbps,掉电不丢失数据 便宜 存储内存 256G 512G
程序是如何运行的:
程序是存储在 flash里面,当需要运行的时候,拷贝到RAM,然后运行.
####### unix 和 C语言发展史 ##########
unix--------|----------------------> linux 免费开源,强大
|----------------------> Mac OS
|----------------------> IBM os
|_---------------------> HP OS
|----------------------- xx
linux和windows:
linux : 免费 开源 安全性高 可以自己定制 服务器 嵌入式 真多用户
window: 收费 闭源 不是很好 不能定制 PC(perison computer) 假多用户
目录结构:
windows: G:\smartlock\smartlock
盘符:\目录1\目录2\目录3\xxx.out
有很多棵树构成,每个盘符都是一棵大树.
linux:
/usr/include/misc
/home/lsf/linux-4.7/drivers/char
linux所有文件的起源都是 "/" 根目录
只有一棵树.
命令:
ls , list-列出
ls 目录:列举该目录下内容 ls testdir/
ls 不家目录: 列举当前目录 ls 列举当前目录下内容
选项
-l 详细的列举出当前 文件夹内容 ls -l
-h human人性化的 ,配合-l使用 ls -l -h 主要作用是显示 文件大小单位
-a --all,显示所有 ls -a
linux的隐藏文件,以 "."开头.
cd 目录名 ,进入该目录
cd: change directory
"..",表示上一级目录 cd .. 回到上一节
"." ,表示当前目录 cd . 切换到当前目录
cd /usr/include 切换到指定目录
家目录:
linux支持多用户同时使用,那么每个用户 必须有一个 自己的 工作文件夹.
家目录 存在于 /home/
每个人 都有一个目录,存在与 /home/用户名
~ 符号,表示 当前用户的家目录 /home/lsf
pwd: 显示当前所在的 位置 Print Working Directory
touch filename : 创建普通文件
touch good.c
rm filename : 删除普通文件, rm remove移除
rm good.c
rm -r 目录名 : 要删除目录
rm -r testdir
mkdir dirname : make-制造 directory-目录
mkdir testdir
rmdir dirname : remove directory
只能删除 空目录
rmdir testdir
cp 原文件名 目的路径 :copy
cp test.txt /home/lsf/dir 拷贝到制定目录
cp test.txt /home/lsf/dir/xx.txt 拷贝并且重命名
mv 原文件名 目录路径 : mv move 搬运
mv test.txt ../testdir/ 搬运
mv test.txt ../testdir/xx.txt 搬运并且重命令
重命名: mv 原文件名字 目的文件名字
mv hello.c good.c
vi filename ##打开该文件########
############ 第一个C程序 ###################
C程序文件后缀都是 .c
头文件后缀都是 .h
#include <stdio.h> 包含C语言的头文件 stdio.h
int main(void) C程序的 入口函数
{
printf("hello world\n"); 很多条语句,语句之间使用";"分割
printf("good night\n"); 执行顺序,从上到下以此执行
return 0; 函数结束,并返回0
}
上述程序是不能够直接执行的,因为计算机只认识 二进制 01
我们需要将上述代码 翻译为 二进制, 这个过程称之为 编译 compile
编译: 将.c程序翻译为二进制,可以直接被计算机执行的文件.
gcc编译器
main.c ---------------> main.out
命令: gcc main.c -o main.out
-o: --output 后面跟 输出目标文件的名字
执行呢: ./main.out
###### 文件类型和后缀#########
window上 使用文件后缀作为 识别文件类型的一种方法
linux: linux系统并不会使用 后缀 区分文件类型.
后缀本身就是文件名称的一部分.
当时我们还是建议,使用 后缀来区分文件类型.
##### 变量 ,可变的量 ##########
variable--善变的,易变的
int aa = 5;
数据类型 变量名字 = 变量值
计算机内部做了什么事情:
aa=8;aa=12;aa=100;aa=420000000;
####数据(变量)类型###
long : long int 长整形 4B/8B=64bit 未知的大小
unsigned long ll;
signed long ll;
int: integer 整形 4B=32bit
signed int ii; -20亿 20亿
unsiged int ii; 大概0-42亿的样子
short: short int 短整型 2B=16bit
signed short ss; -3w~3w
unsiged short ss; 0~65535
char: charator int 字符类型 1B=8bit
char cc; 默认是有符号
signed char cc ; -128->125
unsigned char cc; 0-255
浮点型:
float 4B, 单精度浮点,可以精确到 小数点后 7位的样子
double 8B ,双精度浮点, ... 14的样子
有符号和无符号: + -
signed-有符号的, unsigned-无符号的
一个数据,占据一定的bit数量,用来存放数据. 范围0~ ( 2^位数-1 )
但是无法表达 负数, 那么如何表达负数呢?
我们 要去 数据的最高位,当做符号位 1-表示负数, 0-整数
###变量的命名规则########
int aa ; aa是变量名字,名字是否 有一定的规则.
命名规则:
1. 只能有"字母a-z" "数字0-9" "_"构成
int a$b; X
2. 数字不能打头
34abc X
3.区分大小写
int aa; int AA; 是两个不同的不变量
4.命名不要和关键字冲突
int int = 8;
练习: $abc aa?dd _abc _abcA _23dd 34adb T_abc t_abc *_abc double doublea a&b a=d
X X X X X X X
######## 字符和字符串###########
字符: 符号, 'A' 'a' '*' '(' '[' '`' '|' '0' '7' '$' '#'
手工输入字符的时候,使用 ' '裹起来. '用来裹字符的.
字符串: 字符构成的串 "hello world\n"
字符串使用 " " 裹起来.
有哪些符号:
总共256个符号. 使用 字符类型 来存储 字符.
char cc = 65;
char cc = 'A'; gcc编译器在编译的时候,会将 'A'转换为65;
printf("cc=%d %c\n",cc,cc);
cc = cc + 1;
如何存储,计算机只能存放 数字, 无法直接存放 符号.
我们 给每个符号 安排 一个对应的数字, 存的是 该数字.
如何产生对应关系:
assccii码表, 美国通用的字符表
练习:
char cc ; 请你将他转换为 小写
cc = cc+32;
请你将他转换为大写:
cc = cc-32;
已知char cc='5'; 请你将他转换为 数字 5
cc=cc-'0';
### 转义字符 ##########
转变 意义 的字符
有很多符号,人眼看不到的 比如 换行符 删除符 上下左右
代码中如何 使用他们呢?
printf("hello world");
printf("%c",10);
char cc = 10; //记录了一个换行符
很难手工输入到计算机中,如何简化输入方式呢: a --- z 0-9
可否 '\n' 对'n'进行转义,变为 换行
\表示 转移,即 '\'后面的一个字符被转义
printf("hello world\n"):
'\n' : 换行的意思 ,编译器遇到 \,会将后面得字符表达为另一种意思
'\r' : 回到行首
'\t' : tab
'\'' : 如何输入一个 正宗的' , char cc = '\''
'\"' : 如何输入一个 正宗的 " , char cc = '\"';
printf(" the present says:\"the world belong to us.\"...\n");
'\\' : 如何纯粹的 打印 '\'
printf("the char \\ is very good \n");
######### 字符串 string ####
字符在一起形成的 串
"hello world\n";
"good good study,day day up"
"welcome to our home."
计算机如何存储字符串呢:
按照字符的格式以此存储, 每个字符占据 1B(char)
注意,字符串 必须以 '\0'作为结束.
######## 进制 ############
十进制
二进制
十六进制
八进制
生活中,使用的 十进制
古时: 一打 12进制
星期 7
时间: 30天 一个月 24小时 60sec
1sec=1000ms 1ms=1000us
十进制: 0-9 十个数 逢十进一
1789= 1*103 + 7*10^2 + 8*10^1 + 9*10^0 ;
二进制: 0-1 二个数 逢二进一
二进制转换为十进制
(1010) = 1*2^3 + 0*2^2 + 1*2^1 + 0*2^0 = 10
十进制转换为 二进制:
除余法即可.
小技巧: 8421码
8421
规律 1100 1101
11 0011 = 32+16+2+1=
14 = 1110
9 = 1001
二进制主要用在计算机领域,
十六进制:
二进制 表达太麻烦,十进制和二进制隔阂太大
我们使用十六进制来代替 二进制.
0-9 A B C D E F, 逢 十六 进制
十六进制 转换为 十进制: 0x1AB5 = 1*16^3 + 10*16^2 + 11*16^1+5*16^0
十进制如何转换为 十六进制:
除余法
最常见的用法:
十六进制 <--->二进制
二进制->十六进制 将二进制分为4bit一组 ,4bit转换为一个 16进制
0110 1100 0110 1101
6 C 6 D
十六进制-->二进制 每个16进制数据,都要转换为 4bit二进制 .
6 C 6 D
0110 1100 0110 1101
八进制:
0-7 逢八进一
八进制和十进制转换:
0125 = 1*8^2 + 2*8^1+5*8^0
十进制转换为 8进制:
除余法
八进制和二进制 转换:
110 101 011 111
6 5 3 7
#### printf 的用法###########
printf("hello world\n");
int aa = 456; printf("int counter = %d\n", aa); // %d:decimal 十进制
printf("octuber aa = 0%o\n"); // %o: octuber 八进制
printf("hex aa = 0x%x\n"); // %x: hex 十六进制
unsigned int aa=12586; printf("uint counter= %u\n", aa); // %u, unsigned 无符号打印,也可以使用%d,建议%u
short int aa; printf("short int aa= %d\n",aa); // %d
unsigned short aa; printf("short uint aa=%u\n",aa); // %u
long int aa; printf("long int aa=%ld\n", aa); // %ld long decimal
unsiged long [int] aa; printf("ulong aa=%lu\n", aa); // %lu long unsigned int
char aa ; printf("char aa=%c\n", aa); // %c charator
float aa; printf("float aa=%f\n" ,aa); // %f: float浮动的
double aa; printf("double aa=%lf\n" ,aa); // %lf: long float
"hello" printf("string hello=%s\n", "hello"); // %s: string
高级用法:
printf(" %[flags][总宽度][ . 小数位精度]X"); X=d/o/x/u/lf/f/c/...
总宽度: 如果没有指定数据的宽度,那么按照真实的数据宽度来显示
printf("%8d"); 如果你指定的宽度,小于数据真实宽度,则按照真实的来.
使用空格' '来填充
flags: 指定 填充的字符
flags 要么为0,要么不写,不写则以' '填充.
printf("%08d"); 0表示填充,8表示宽度
.小数宽度
指定小数位的宽度
printf("%08.4f");
printf("%.4f");
########## 运算符 #############
#### 算术运算符########
+-*/% =
"+" : 两个数相加 5+6 a+8 2.3+6.6 5+6.3 cc = 5+3.69
"-" : 两个数相减 5-6 a-b 2.6-9.9 5-6.1 8-c cc = a-5
"*" : 两个数相乘 5*6 a*b 3.6*9.5 5*6.2 cc = a*5;
"/" : 两个数相除 3/6 5.2/2 6/3.2
两个整数相除,结果还是整数 ,称为 #整除#
3/6 == 0 5/6==0 19/2=9
% : 取余 3%2
取余,只能用于 ###整数间求余####
'=': 赋值运算符 动作, a=5; 将 '='右边的结果(先进行运算),交付给 左边的变量
a=5+6+9+8+9;
####运算符的简化##########
a=a+5; a += 5;
b=b-3; b -= 3;
c=c*2; c *= 2;
d=d/4; d /= 4;
f=f%5; f %= 5;
a=a+1; a += 1; a++; b=-++; 先将a的值给b,然后a++; b=++a;先讲a的值++,在交付给b 无论如何,a都是++了的.
a=a-1; a -= 1; a--; b=a--; 先将a的值给b,然后a--; b=--a; ..................
(a++) 的结果是 a原始的值 ,a的值+1;
(++a) 结果 a的+1的结果 a的值+1
######### 比较运算符 > < >= <= == !=
a = 5 + 6;
a = 5 > 6; 比较运算符,对两个数进行比较,得到结果 如果成立结果为1-true-真 否则结果为0-false-假
a = 34<38;
a = 45==55;
if(a=5){
printf("相等");
}else {
printf("不相等");
}
小明 int ming_score=88; 小红 int hong_score=99;
if( ming_score > hong_score ) { //如果判断为真,即 结果为1 ,执行 下一条语句
printf("xiaoming is good\n");
}else { //如果为假, 即 0,则执行 该语句.
printf("xiaohong is good\n");
}
if用法:
if( 条件判断 ) {
如果条件合适,则执行这里
}
if(条件判断){
如果条件合适,则执行这里
}else {
如果条件不合适,则执行这里
}
小丽的成绩 int score = 99; A:90-100 B:80-90 C:60-80 D:60以下
if(score >= 90){
printf("A\n");
}else if(score >=80){
printf("B\n");
}else if(score >=60){
printf("C\n");
}else {
printf("D\n");
}
注意问题:
if后面如果没有 {},则 if的作用范围是 第一条语句.
练习题:
已知三个数: int a=5, b=54,c=12;
请你找出 其中的最大值,并打印出来.
if(a>b){
//b 淘汰, a c
if(a>c){
printf("max=%d\n",a);
}else {
printf("max=%d\n",c);
}
}else {
//a淘汰 b c
if(b>c){
printf("max=%d\n",b);
}else {
printf("max=%d\n",c);
}
}
#### 条件组合 ######
语文 数学 英文
优秀 >=90 >=90 >=90
尖子 只要有一门成绩>=95
良民 >=60 >=60 >=60
已知某个学生成绩: int yuwen=95; int shuxue=90; int yingyu=82;
条件组合:
&&--与 ||--或 !--非
&&: 都成立才可以
||: 只要有一个合适就是合适的
优秀: (yuwen >= 90 ) && (shuxue>=90 ) && (yingyu>=90)
尖子: (yuwen >=95 ) || (shuxue>=95 ) || (yingyu>=95)
if( (yuwen >= 90 ) && (shuxue>=90 ) && (yingyu>=90) ){
printf("you are good\n");
}
if( (yuwen >=95 ) || (shuxue>=95 ) || (yingyu>=95) ){
printf("you are top\n");
}
爱国者: yingyu <60
if( !( yingyu >= 60 ) ){
printf("re ai guo jia\n");
}
练习题: 已知一个年份 int year=2065;
请你判断他是不是 瑞年.
闰年的规则:能被4整除,但不能被100整除,或者直接能被400整除
(year%4==0 && year%100!=0 ) || ( year%400==0) 闰年
!( (year%4==0 && year%100!=0 ) || ( year%400==0) )
中国足球来你校招聘 运动员
( (yuwen>=60 && shuxue>=60 ) || (height>185cm) ) && (sex!=woman)
####三目运算符: ? :
两目运算符: +-*/ >< == 5+6
作用:
if( 条件判断 ) { if(a>b) {
如果条件成立,执行这里 max=a;
}else { }else {
条件不成立,执行这里 max=b;
} }
上述的语句功能非常简单,但是我却写了5行. 我们可以使用 三目运算符 取代.
max = a>b ? a : b;
max = 条件判断 ? 成立结果 : 不成立结果 ;
举例: 小明 考试得了 int score=65;
请你判断合格了吗:
score >=60 ? printf("合格") : printf("不合格");
int daoshoumomey = salary >5000 ? salary-300 : salary;
练习: 使用三目运算符 求取三个数中最大的那个
int a=45,b=43,c=23;
条件 a>b代码 a<=b代码
max= a>b ? ( a>c?a:c ) : b>c?b:c ;
###### 位运算符 ############
数电 : 按位与 按位或 按位取反
位,即一个bit,要么为0 要么为1
与& : 与, 和 并且 都为真(1)结果才为真(1)
1 & 1 = 1
0 & 1 = 0
1 & 0 = 0
0 & 0 = 0
规律: a & 1 = a a=[0 1] 和1相与则不变
a & 0 = 0 a=[0 1] 和0相与则置零
short aa = 1100 0011 1010 0101
& bb = 0101 1110 0111 1100
----------------------------
= 0100 0010 0010 0100
练习: 已知 一个 short int aa, 请你 将它的 0-3位 置零,其他位保持不变
aa = xxxx xxxx xxxx xxxx
& 1111 1111 1111 0000
= xxxx xxxx xxxx 0000
总结: 与操作主要目的 是将一个数据的某些位 置零.
按位 | : 有一项为真就是真
1 | 1 = 1
0 | 1 = 1
1 | 0 = 1
0 | 0 = 0
规律: 和 1 相或 为1 a | 1 = 1
和 0 相或 不变 a | 0 = a
short aa = 1100 0011 1010 0101
| bb = 0101 1110 0111 1100
----------------------------
= 1101 1111 1111 1101
练习: 已知一个数 aa ,请你将他的 4-7位 置一,其他位保持不变
aa = xxxx xxxx xxxx xxxx
| 0000 0000 1111 0000
= xxxx xxxx 1111 xxxx
总结: 用于将数据的某些位 置一.
思考题: 有一个数据aa ,请你将 aa 4-7位,修改为 0101
aa = xxxx xxxx xxxx xxxx
& 1111 1111 0000 1111 先进行 &,清零
= xxxx xxxx 0000 xxxx
| 0000 0000 0101 0000 在进行 |, 置一
= xxxx xxxx 0101 xxxx
按位取反 ~ :
~0=1
~1=0
~ 1010 1100 1101 0101
= 0101 0011 0010 1010
作用:将一个数所有的位都进行取反
异或^ :
相异为1,相同为0
1 ^ 1 = 0
0 ^ 1 = 1
1 ^ 0 = 1
0 ^ 0 = 0
规律: 和1异或取反 a^1=~a
和0异或不变 a^0=a
作用: 取反数据的某些位
练习, 请你 将 aa的 8-11位取反,其他位保持不变
aa = xxxx xxxx xxxx xxxx
^ 0000 1111 0000 0000
= xxxx XXXX xxxx xxxx
<<左移 >>右移 : 位的左移和右移
0011 << 1 = 0110 使用0来补充
0011 >> 1 = 0001 使用0来填充
char aa = 0x3C; 60
aa = aa << 1; // aa = 0x78 = 120
aa <<= 1; // aa = 0xF0 = 240
#### 发现 <<1,等于 *2 <<2,*4 ####
### 类似, >>1,等于/2 整除的效果 ####
通过 << >>,取代部门 * 和除法 ,从而提高代码执行效率
#### 类型转换 ############
int double float char short ...数据有很多类型
short aa =5; int bb=6; float cc=7.78925;
不同类型的数据,有时候需要 进行互操作 5+6.3
但是 CPU在硬件上 不支持 不同类型数据的运算. 硬件上不支持 6+3.6
但是 C语言是支持的: 如何做到的
C语言 会偷偷的 将你的数据,进行 隐式的类型转换 6+3.6--->6.0+3.6 short a=5;int b=56; a+b
隐式类型转换: C语言发现两个类型不同的数据进行运算的时候,会进行 隐式类型转换.
规则:
1. 小类型向大类型转换 避免数据被破坏.
5+6.6 int->double 5.0+6.3
short a; int b; a+b short->int
char ch='A'; int b; b+ch; char-->int
2. 运算符 右边的类型无条件转换为 左边的类型.
int aa = 6.9; 取整
short cc = 216456645;
3. 有符号和无符号 相互操作
int aa=-34; unsiged int bb=123;
有符号无条件转化为 无符号
隐式类型转换是 C语言自动进行,我们无法控制.我们可否按照自己的需求进行类型转换
强制类型转换: 按照程序员的 想法去转换
(转换后的类型)转换前的数据 (int)5.689
举例:
工程今天生产了 5.8L 牛奶, 6.8L果汁 , 3桶
请问 今天的量是多少
(隐式) 5.8+6.8+3.0 = 15.6
(强制) (int)5.8 + (int)6.8 + (int)3 = 14
######## homework 练习#############
1.定义一个三位数变量,最后编程输出该变量的个、十、百位上的数值
int aa=789;
个位: = aa % 10 ;
十位: = aa /10 %10;
百位: = aa/100;
2.定义两个变量,编程交换两个变量的值,最后输出交换后的数据
int aa=44; int bb=55; 请你交换他们的数值
int cc = aa; aa=bb; bb=cc; 需要借助第三个数值
3. 已知 五个数,int aa=33,bb=-4,cc=0,dd=-343,ee=23;
请你求取 正数的个数 0的个数 负数的个数
int positive=0; //积极地,正面的
int zero = 0;
int negtive=0; //消极的,负面的
if(aa ==0){
negtive++;
}else if(aa>0){
positive++;
}else if(aa<0){
negtive++;
}
....
printf("positive=%d zero=%d negtive=%d\n",positive,zero,negtive);
4. 请你用三目运算符完成 :
score >=90使用 输出 A
60-89之间 输出 B
其他的输出 C
score > 90 ? printf("A") : ( score>=60 ? printf("B") : printf("C"); ) ;
########### 运算符的优先级 #############
int aa = 5*4 + 6* ( 5+9) ; *运算符优先级高于+ , ()优先级是最高的
++y*5 ; --> (++y)*5
要求: 尽可能的使用() 避免歧义的问题.
()[] > ++ -- > */ > + -
######### scanf #############
printf("%d %c %u %ld %f", 23,'A',234,2342,25.36); 程序 -------> 终端
scanf(); 终端 -------> 程序
int aaa;
scanf("%d", &aaa); &,取地址运算符 scanf会等待终端输入一个整数(%d),scanf得到整数后会存到aaa中.
int age; char sex; int id; double weight;
scanf("%d %c %d %lf", &age,&sex,&id,&weight ); scanf会以此从终端读取 %d整数 %c字符 %d整数
%lf浮点,以此存入后面的&age,&sex,&id,&weight
多个输入,以空格作为间隔.
scanf有很多的bug
如果输错,可以通过 ## ctrl+c ## 的方式结束程序.
######### if 和 switch ####################
if的用法: 所有的if都建议 使用 { }
if(条件判断){
成立则执行.
}
if(条件判断){
成立则执行
}else {
不成立执行
}
if(条件判断1 ){
如果成立执行
}else if(条件判断2){
...
}else if( ...){
}
### if的缺点, 如下 ############
char keynum = getKeyboard();
if( keynum=='A'){
...
}else if(keynum=='B'){
}else if(keynum=='C'){
}else if(keynum=='D'){
}
...... 太长了 ....
}else {
}
### switch 用法 ####
char keynum = getKeyboard();
switch(keynum){ switch根据变量keynum, 依次去匹配每一个 case 项,如果配上则 执行对应代码.
case 'A': 遇到break则终止本次swtich, 代码继续执行.....
如果是A,则处理这里代码. 如果没有遇到break,会继续以此执行.
break;
case 'B':
如果是B,则处理这里代码;
break;
case 'C':
如果是C,则处理这里代码
break;
......
default:
如果以上都没有匹配的,则执行这里 如果一个case 都没有匹配上,则执行default的操作
};
注意1,switch只能 用于 ##相等##判断的情况,不能用作范围匹配.
比如以下,无法完成.
if(score>90){
}else if(score >80){
}else if(score >60){
}else {
}
注意2: switch 进入某个选项后,如果没有遇到break,则继续 执行.
练习题: 根据成绩 打印 等级 ,使用switch完成
int score;
printf("input score:");
scanf("%d",&score);
90---99 和 100 A 9, 10
70--89 B 7 ,8
60-69 C 6
其他 D
swtich(score/10){
case 10:
case 9:
printf("A");
break;
case 8:
case 7:
printf("B");
break;
case 6:
printf("C");
break;
default:
printf("D");
}
练习: 从终端输入 月份 [1-12],打印出 春夏秋冬
int month;
printf("input the month:");
scanf("%d",&month);
switch(month){
case 1:
case 2:
case 3:
printf("spring festvol\n");
break;
case 4:
case 5:
case 6:
printf("summar festvol\n");
break;
case 7:
case 8:
case 9:
printf("autumn festvol\n");
break;
case 10:
case 11:
case 12:
printf("winter festvol\n");
break;
default:
printf("unkown month=%d\n",month);
}
注意3:
请你输入一个浮点,使用switch处理. switch不能用于浮点处理.
以下是错误 用例:
double weight ;
scanf("%lf",&weight);
switch(weight){
case 75.23564544 :
case 75.23564545:
case 86.2634554564564646:
case
}
##### 原码 反码 补码 ##########
研究数据到底在计算机中是如何存储的. ##补码###
原码: 原始存储/表达方式
正数 原码 int a = 5; 0000 0000 0000 0000 0000 0000 0000 0101
负数 原码 int a =-5; 1000 0000 0000 0000 0000 0000 0000 0101
反码: 正数的反码和原码相等 负数的反码,符号位不变, 其他取反.
正数 反码 int a = 5; 0000 0000 0000 0000 0000 0000 0000 0101
负数 反码 int a =-5; 1111 1111 1111 1111 1111 1111 1111 1010
补码: 正数, 原码=反码=补码 负数的补码=反码+1
正数 补码 int a = 5; 0000 0000 0000 0000 0000 0000 0000 0101
负数 补码 int a =-5; 1111 1111 1111 1111 1111 1111 1111 1011
练习:
0.分段函数:
键入一个整数x,
如果小于3则执行x+=3操作,
如果大于等于3且小于等于9则执行x=3*x+9
如果大于9则执行x=9*x-10
int value;
printf("input the value:");
scanf("%d",&value);
if(value<3){
value = value + 3;
}else if( value>=3 && value <=9 ){
value=3*value+9
}else {
value=9*value-10
}
1.输入三个值判断这三个值是否构成三角形
如果是:
(是否是直角 等腰 等边 普通 不能)
三角形:最小的两边之和大于第三边 可以使用 && &&
int b1,b2,b3;
if(b1>b2){ //b2不是最大的
if(b1>b3){ //b1 is max
if(b2+b3 > b1){
printf("可以");
}else {
printf("不可以");
}
}else { //b3 is max
if(b1+b2>b3){
printf("可以");
}else {
printf("不可以");
}
}
}else { //b1不是最大的
}
直角:a*a+b*b==c*c
等腰:任意两条边相等
等边:三边相等
2.输入三个整数x,y,z,请把这三个数由从小到大输出(两两交换,三次)
3.从scanf输入一个成绩,判断成绩的等级: 学习成绩>=90分的同学用A表示,60-89分之间的用B表示,小于60用C表示
5.停车场收费系统,3小时以内,收费每小时30元,超出部分每小时50元,输入一个时间,计算 费用.
int hour;int money;
printf("input park time hour:");
scanf("%d",&hour);
if(hour<3){
money = hour*30;
}else {
money = 3*30;
hour-=3;
money += hour *50;
}
printf("momey is %d\n",money);
6.判断输入的4位数是否是回文数(1221是回文数, 1234不是)
int value;
int qian,bai,shi,ge;
ge= value%10;
shi = value/10 %10;
bai = value/100 %10;
qian = value/1000;
if( (qian==ge) && (shi==bai) ){
printf("shi");
}else {
printf("fou");
}
7.输入年份判断该年是否是闰年
//闰年
//能被4 整除但是不能被100整除 或者能被400整除
8.输入一个整数,判断是否既是3 也是5 又是7的倍数
if( (value%3==0) && ( value%5==0)&& ( value%7==0 ) ){
}
########### 循环 loop ############
有时候我们需要 一段代码,重复 循环 执行很多次.
案例: 从键盘输入10个数,输出0的个数.
int counter = 0;
int aa;
loop: 标签
scanf("%d",&aa);
if(aa==0){
counter++;
}
goto loop;
##### 第一种循环结构 goto ########
练习: 实现 1+2+3+4+....+100的和
int i =1; // i=1 2 3 4.. 100
int sum=0; // sum += 1 2 3 4 5 ... 100
loop:
sum = sum+i;
i = i+1;
if( i <= 100){ //边界问题,走两步
goto loop;
}
printf("sum=%d\n",sum);
练习: 实现阶乘, 从键盘中输入n, 打印n!=1X2X3X4X5X6X7
int -- 32bit --42亿
n!=1X2X3X4X5X...Xn
总结:
对于一个非死循环, 三要素: 起始值, 每次循环修改, 每次循环都需要判断
#### while循环 ############
条件起始值
while( 条件判断 ){
条件成立,进入循环体
修改条件值
}
一旦条件不满足,立即结束循环
案例: 累加 1+2+3+....+100
int sum=0;
int i=1;
while( i<= 100 ){
sum+=i;
i++;
}
printf("sum=%d\n",sum);
代码执行到这里,i==101
案例2: n! 从键盘中输入n,求取n的阶乘
n!=1x2x3x...xn
int val = 1;
int i = 1;
while( i<= n ){
val *= i;
i++;
}
printf("val=%d\n ",val);
##### break中止 continue继续 ############
while( 条件判断 ){
循环体
break; 中止当前的循环,结束while, 继续执行后续代码
条件变化
}
.......
案例: 从键盘输入 数据,计算它们的累加和,遇到 -1则结束循环.
int sum=0;
int val;
while( 1 ){
printf("input val:");
scanf("%d",&val);
if(val == -1){
break; break中止当前循环,继续执行后续代码
}
sum+=val;
}
printf("sum=%d\n",sum);
##continue
案例 实现累加和 0+2+4+6+... +100
int sum=0;
int i = 0;
while(i <= 100){
i++;
if(i %2 == 1){
continue; //放弃后续代码,直接开始下一次循环
}
sum+=i;
}
### while的变体 #########
条件起始;
do {
循环体, 循环体第一次无条件执行的,后续 如果条件判断成立,才成立
条件变化;
}while(条件判断) ;
案例: 累加和 1+2+3+...+100
int sum = 0;
int i = 100000;
do {
i++;
sum+=i;
}while( i < 100 );
printf("sun=%d i=%d\n",sum,i);
## 练习: 从键盘输入一个整数,判断他是否是 素数/质数
质数 : 一个数 只能被1和自身整除.
具体该如何做: 比如 n
从 2 ..... n-1,这些数都不能被整除,则认为他是素数
int n;
printf("input the value:");
scanf("%d",&n);
int i=2;
while( i<= n-1 ) {
if(n%i == 0){
break; //中间中止, i<= n-1
}
i++;
}
//不论如何,代码会抵达这里 中间中止 i<=n-1, 如果是 正常中止i==n
if(i==n){
printf(" n=%d is zhishu\n");
}else {
printf(" n=%d is not zhishu\n");
}
挑战###
请你找出 1000以内的所有质数:
val = 2 3 4 5 ......... ,1000
int val = 2;
while( val <=1000 ) {
//判断val是否是质数 i = 2 3 4 ......... (val-1)
int i = 2;
while( i<= val-1 ){
if(val%i == 0){
break;
}
i++;
}
if(i == val ){
printf(" %d ",val);
}
//寻找下一个val
val++;
}
#### 第三种循环 for ##############
不死循环: 三要素 1起始条件 2条件改变 3条件判断
for(起始条件; 条件判断; 条件变化 ){
循环体
}
工作过程:
1. 执行起始条件,执行一次即可.
2. 条件判断,如果成立 执行循环体, 如果不成立 结束for循环
3.条件变化 ,goto 2;
案例: 累计和 1+2+3+....+100
int i; int sum=0;
起始条件
for( i=1 ; i <=100 ; i++ ){
//i = 1 2 3 4 5 6 .....
sum += i;
}
练习: 判断一个数,是不是素数
int num;
int i;
printf("input num:");
scanf("%d",&num);
// i=2 3 4 5 6 .. num-1 num%i==0
for( i=2 ; i<= num-1 ; i++ ){
//i = 2 3 4 5 6 7 .. .. num-1
if(num % i == 0){
break;
}
}
//代码到了这里 i==num 是质数 i<=n-1不是质数
i == num ? printf("yes") : printf("yes");
练习2: 找出1000以内所有的质数
val = 2 3 4 5 ............. 1000
int val;
int i;
for(val=2; val<=1000; val++ ){
//val = 2 3 4 5 6 7 ... 100
//判断val是否为 质数 i=2 3 4 5 6 ... val-1
for(i=2; i<=val-1;i++){
if(val%i == 0){
break;
}
}
if(i==val){
printf(" %d ",val);
}
}
死循环:
while(1){
}
for(; ; ){
}
练习:
要将5张100元的大钞票,换成等值的50 20 10 5小钞票,每种面值至少一张,
有多少种换法,把所有的可能性的东西,全部列举
50元 范围 a [ 1 10 ]
20元 b [ 1 25 ]
10 c [ 1 50 ]
5 d [ 1 100 ]
int a,b,c,d;
int counter = 0;
for(a=1;a<10;a++){
//a=1 2 3 4 .. 9
for(b=1;b<25;b++){
// b =1 2 3 4 .. 25
for(c=1;c<50;c++){
//c = 1 2 3 4 .. 50
for(d=1;d<100;d++){
if( a*50 + b*20 + c*10 +d *5 == 500 ){
printf(" %d %d %d %d \n",a,b,c,d);
counter++;
}
}
}
}
}
练习:
从键盘输入 行和列,打印如下形式
int hang = 4; int i; //i=1 2 3 4
int lie = 5; int j; //j=1 2 3 4 5
***** 1
* * 2
* * 3
***** 4
printf("input hang lie:");
scanf("%d %d",&hang,&lie);
for(i=1;i<=hang;i++){
//i=1 2 3 4 .. hang
//要区分 第一行,最后一行 和其他 行
if( i==1 || i==hang){ //全部打印*
for(j=1;j<=lie;j++){
printf("*");
}
}else { //打印* *
for(j=1;j<=lie;j++){
if(j==1 || j==lie){
printf("*");
}else {
printf(" ");
}
}
}
printf("\n");
}
从键盘输入行数,打印如下形式:
输入n的值,n代表行数,输出如图所示的图形
行号 空格 *
* 1 3 1
* * * 2 2 3
* * * * * 3 1 5
* * * * * * * 4 0 7
i n-i 2i-1
..
n
(此图为n=4时的输出结果)
int n;
printf("input n:");
scanf("%d",&n);
for(int i=1;i<=n;i++){
//i 行, i= 1 2 3 4 5 ........ n
//先打印 n-i 空格
for(int j=1;j<=n-i;j++){
printf(" ");
}
//在打印 2i-1个 *
for(int j=1;j<=2*i-1;j++){
printf("*");
}
//打印\n
printf("\n");
}
### 小游戏 ####
产生一个随机数 1~100以内
srand(getpid());
int randval = rand() %100 ; //rand()返回的随机数 范围 0--42亿
while(1){
printf("input val:");
scanf("%d",&val);
if(val < randval){
printf("your input is little\n");
}else if(val > randval){
printf("your input is bigger\n");
}else if(val == randval){
printf("congratulations \n");
break;
}
}
int i ; //行 1 2 3 4 5 6 7 8 9
int j; // 1 2 3 .. i
for(i=1;i<=9;i++){
// i = 1 2 3 4 5 ... 9
for(j=1;j<=i;j++){
printf("%d X %d = %d ",j,i,i*j);
}
printf("\n");
}
###### 数组 array ###############
以前: int a ,b ,c,d ,e ...; 如何一次定义100个变量.
数组允许你一次定义N个变量.
int aa[10]; //int a,b,c,d,e,f,g,h ,i,........
如何使用某个成员: aa[0]~aa[9] 下标范围 0-9
定义并赋值:
int a=4,b=3;
int aa[10] = {12,34,345,32,23,23,4,23,23,233 }; 依次赋值
int aa[ ] = {12,34,345,32,23,23,4,23,23,233 }; 如果不指定数组个数,那么 会根据 赋值的个数来确定.
int aa[10] = {12,34,345,32,23,23,4,23 }; 依次赋值 ,未赋值处置零
求取数组占据的空间,单位 B :
printf( "sizeof a = %d\n",sizeof(a) );
printf( "szieof aa[]= %d\n",sizeof( aa) "); ## sizeof(数组)
求 数组元素的个数:
sizeof(aa)/sizeof(aa[0])
数组名aa,记录了整片空间的地址. 类似指针 .
例子: 定义一个数组,内有10个整形数据; 从键盘输入10个数据,存入其中.
int aa[10];
//从键盘读取数据 以此存入 aa[0] aa[1] ... aa[9]
for(int i=0;i<10;i++) {
printf("input num%d:",i);
scanf("%d", & aa[i] );
}
printf("travel array:");
for(int i=0;i<10;i++){
printf("%d ",aa[i]);
}
printf("\n");
//继续: 请你算出他们的 总和 平均值
int sum=0;
for(int i=0;i<10;i++){
sum += aa[i] ;
}
printf("sum=%d average=%lf\n",sum,sum/10.0);
## 定义两个数组,你从键盘 给一个数组输入数据.
将数据拷贝到另一个数组.打印出
int aa[10] = {23,43,52,63,78,90,93,99,100,105};
int bb[10];
for(int i = 0; i< 10 ; i++){
bb[i]=aa[i];
}
####### 已知数组
int aa[ ] = {23,43,52,63,78,90,93,99,100,105};
//请你设计算法,将他逆序:
##方法1:
// i = 0 1 2 3 4 ... cnt/2 -1
// 交换 a[i] aa[cnt-i-1]
int cnt = sizeof(aa)/sizeof(aa[0]) ;
for(int i=0;i<cnt/2 ;i++ ){
int temp=aa[i];aa[i]=aa[cnt-i-1];aa[cnt-i-1]=tmp;
}
for(int i=0;i<cnt;i++){
printf("%d ",aa[i]);
}
printf("\n");
## 方法2:
int aa[ ] = {23,43,52,63,78,90,93,99,100,105};
int cnt = sizeof(aa)/sizeof(aa[0]) ;
int i=0; int j=cnt-1;
while( i< j ){
int tmp = aa[i];aa[i]=aa[j];aa[j]=tmp;
i++;j--;
}
for(int i=0;i<cnt;i++){
printf("%d ",aa[i]);
}
printf("\n");
### 字符串数组##############
"hello world" == "hello world\0" 编译器帮你添加伪0
char str[16];
char str[] = {'h','e','l','l','o',' ','w','o','r','l','d' };
这是一个#字符数组#,因为没有\0,不是字符串
char str[] = {'h','e','l','l','o',' ','w','o','r','l','d','\0' };
char str[] = "hello world"; 是上面的简写方式.
char str[16] = "hello world";
访问某个字符: str[i]
printf("string %s %s ","hello world", str);
C语言中,使用 字符数组来存储 字符串.
字符串是一个特殊的 字符数组,特殊在 尾部\0.
练习: 已知一个字符串 char str[] = "hello world";
请你求出他的长度?
char str[] = "hello world";
int i; // 0 1 2 3 4 ..
i=0;
while( str[i] ) {
i++;
}
printf("string length=%d\n", i);
练习:1. 已知字符串 char str[] = "hello world";
请你 将他们转换为 大写 "HELLO WORLD"
int i = 0;
char str[] = "hello world";
while(str[i]){
if(str[i]>='a' && str[i] <= 'z'){
str[i] -= 32;
}
i++;
}
2.已知字符串 char str[] = "123 hello world 345 ";
请你 将他们转换为 大写 "123 HELLO WORLD 345 "
3. 已知字符串, char str[] = "Hello world";
请将他们的大写转小写 小写转大写
4. 将 char str[] = "I love china"; 修改为 "anihc evol i"
char str[] = "I love china";
int i=0; int j=0;
while( str[j] ){
j++;
}
//代码到这里了,说明了什么 str[j]=='\0'
j--;
while( i<j ){
int temp= str[i];str[i]=str[j];str[j]=temp;
i++; j--;
}
printf("%s\n",str);
####### 二维数组 ##########
一维数组: int aa[10] = {23,243,44,23,45,24,53,23,23};
二维数组: int aa[5][6]; 计算机会分配 5*6个 int单元,他们是连续的空间.
定义赋初值:
int aa[10] = {23,243,44,23,45,24,53,23,23};
int aa[3][4] = { {1,2,3,4}, {23,23,4,2}, {432,23,123,24} }
int aa[3][4] = { {1,2,3}, 23,23,4,2, 432,23 }; 其中 1 2 3 0放第一行 ,23,23,4,2 第二行
访问某个成员:
aa[行号][列号] 行号: 0--- ,列号:0----
for(int i=0;i<3;i++){ //i 行 = 0 1 2
//针对第i行,扫描列
for(int j=0;j<4;j++){ //j列 0 1 2 3
printf("%d ",aa[i][j]);
}
printf("\n");
}
二维数组的应用:
#字符串数组#
字符串: 它是字符构成的数组.
字符串数组: 字符构成的数组 数组, 其实就是个 字符的 二维数组
{'x','i','a','o','w','a','n','g','\0'}
char names[4 ] [16 ] = { "xiaowang","xiaohong","xiaoming","xiaoli" };
char names[可以省略][不可省略] = { "xiaowang","xiaohong","xiaoming","xiaoli" };
char str[] = "dawang"; printf("%s",str);
char name[][] = {} printf("%s", name[i=0 1 2 3] );
遍历字符串数组:
char names[4] [16] = { "xiaowang","xiaohong","xiaoming","xiaoli" };
for(int i=0;i<4;i++){
printf("%s ",names[i]);
}
## 二维数组练习题:
使用二维数组,打印如下方阵
*
* *
* * *
* * * * 特性: i>=j * i<j ' '
char aa[4][4];
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
aa[i][j] = (i>=j )? '*' :' ';
}
}
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
printf("%c",aa[i][j]) ;
}
printf("\n");
}
练习:
*****
* *
* *
*****
练习1:
给定一个字符串 char str[] = "good doog";
判断他是不是回文;
int i=0;int j=0;
while(str[j]!='\0'){
j++;
}
j--; //str[j] == \0
while(i<j){
if( str[i] != str[j]){
break; //
}
i++;j--;
}
// i<j,中途终止,不相等
if(i<j){
printf("not equal\n");
}else {
printf("equal\n");
}
return 0;
练习2:
完成字符串的拷贝
char src[] = "hello world";
char dst[16];
int i = 0;
while( src[i] ){
dst[i]=src[i];
i++;
}
// src[i]== \0
dst[i]=src[i]; //最后一步, 将dts尾部置零
printf("%s\n"dst);
练习3:
比较两个字符串,是否相等
char str1[] = "hello world";
char str2[] = "hello wor"
方法1: 先求 各自的长度,长度不一致 go out
长度一致,以此比较...
方法:
int i=0;
while( str1[i] && str2[i] ){
if( str1[i]-str2[i] ){
break;
}
i++;
}
//如果长度一致 str1[i] == str2[i] == \0 相等的
//如果长度不一致 只有一个 为0 不相等
if( str1[i] - str2[i] ){
printf("不相等\n");
}else {
printf("相等\n");
}
挑战:
将一个字符串 char str1[] = "12345";
转换为 整数.
int aa = 12345;
char str1[] = "12345";
int sum = 0; //最终结果
int i=0;
while( str1[i] ){
char v = str1[i] - '0';
sum = sum*10;
sum+=v;
i++;
}
printf("sum=%d\n",sum);
########## 函数 function ###############
function: 功能
函数: 在英文中,函数翻译为 function rst=sin(30)
函数,就是为了完成 特定功能的代码段
int len = strlen( "hello world." );
int size = sizeof(aa); //暂时可以认为是函数
int maxa = min(45,65.25);
函数构成:
返回值类型 函数名 (类型1 参数1, 类型2 参数2 )
{
对输入的参数进行加工,将结果返回
return 结果;
}
int main( int argc, char argv[][] )
{
加工
return 0;
}
// mymax函数,对输入的 两个int类型数据 a,b进行加工,输出 最大值(int)
int mymax(int a,int b)
{
if(a>b){
return a; //return 结束当前函数,并返回结果.
}else {
return b;
}
return -1;
}
int main(void)
{
int c = mymax(55,66);
printf("max c is %d\n",c);
int d = mymax(1001,1098);
printf("max d is %d\n",d);
}
特殊的函数:
有的函数 没有返回值
sleep(1); void sleep(int sec);
sleep(int sec); 如果不写,默认 int
有的函数 不需要参数
int r = rand(); int rand(void);
有的函数,既没有 有没有
sleep1s(); void sleep1s(void)
小练习:
实现一个 abs函数 ,返回 绝对值
int myabs(int val)
{
int rst = val>0?val:-1*val;
return rst;
}
求三个数据最小值
int mymin(int a,int b,int c)
{
int min;
if(a>b){ //a 被淘汰
if(b>c){
min=c;
}else {
min=b;
}
}else {
if(a>c){
min =c;
}else {
min =a;
}
}
return min;
}
int main(void)
{
printf("the min is %d\n", mymin(45,64,23) );
return 0;
}
##数组的传参: 参数,argument 传递: pass , 传参 pass argument
char str[] = "hello world";
实现函数,求取字符串长度
char str[] = "hello world";
int mystrlen( char s[] ) //##参数定义 数组
{
int i = 0;
for( ; s[i];i++ ){ //while(s[i]){
// i++;
} //}
return i;
}
int main(void)
{
printf("stringlen = %d\n", mystrlen ( str ) ); //###传参的时候,只需要指定数组名即可
}
练习: 判断字符串是不是回文 如果是返回1,否则返回0
int str_loop(char s[])
{
int i=0;int j=0;
while(s[j] ){
j++;
}
j--;
while(i<j){
if(s[i] != s[j]){
break;
}
i++;j--;
}
if(i<j){
return 0;
}else {
return 1;
}
}
int main()
{
char str[] = "good doog";
int cc = str_loop( str );
if(cc){
printf("yes");
}else {
printf("no");
}
}
##练习:
int str2num(char str[])
{
int sum = 0; //最终结果
int i=0;
while( str[i] ){
char v = str[i] - '0';
sum = sum*10;
sum+=v;
i++;
}
return sum;
}
int main(void)
{
char string[16];
printf("input num:");
scanf( "%s", string );
int num = str2num(string);
printf("number = %d\n");
return 0;
}
### 函数的 声明####
函数可以 先定义,后使用. 即,在使用函数之前 定义函数 main函数要在文件的尾部
函数如果 先试用,在定义. gcc在编译的时候,会给出警告 implict declare function of xxxxx :
int str2num(char s[]); //声明该函数, 告诉编译器, 发现先试用后定义的情况也不要给警告
int main()
{
str2num("123456"); //gcc编译的时候,发现没有定义....
}
int str2num(char s[])
{
....
}
### 全局变量 和 局部变量
#include <stdio.h>
int gg = 10086;
int main(void)
{
int gg = 5;
printf("gg=%d\n",gg); 使用的肯定是 局部变量
}
局部变量: 定义在 {}内部的变量称之为 局部变量. 有效范围在{}内部
在函数执行的时候,才分配空间. 当退出函数理解释放空间.
全局变量: 定义在{}外部的变量,称为 全局变量 有效范围是 全局
在程序执行之处就已经分配空间,程序结束才释放空间. 周期是全局的
###### 形参 和实参 #############
实参: 实际存在的参数,确定数值的参数
形参: 形式上的参数,值也是不定的
### 实现函数,交换两个变量的值
void myswap(int ax, int bx)
{
int tmp=ax; ax=bx; bx=tmp;
}
int main(void)
{
int aa = 56; int bb = 78;
myswap(aa, bb); ### 形参的改变 没有影响到实参
printf("aa bb=%d %d\n",aa,bb);
return 0;
}
再来一个:
void myadd(int ax)
{
ax++;
}
int main(void)
{
int aa=55;
myadd(aa);
printf("aa=%d\n");
}
如何通过修改形参来影响实参呢: 数组的传参
void array_swap(int arr[] ) //C语言禁止 函数内定义函数: 嵌套定义
{
int tmp= arr[0];arr[0]=arr[1];arr[1]=tmp;
}
int main()
{
int aa[2] = {12,34}; //通过调用函数 完成 aa[0] aa[1]的交换
array_swap(aa);
printf("aa[0 1] = %d %d\n",aa[0],aa[1]);
return 0;
}
发现通过 数组的传递,可以改变实参的值.
########## 变量和常量##########
变量: variable 可变的量
int aa = 55; aa=543; aa=23243;
常量: const 恒定不变的量.
const double PI = 3.141592654; 定义的时候,使用const修饰变量,则 该变量是#只读#的.
一般const修饰变量, 定义就必须初始化.
PI=3.14; 非法,编译器报错. error: assignment of read-only variable ‘PI’
####### 宏定义 #define ################
宏替换
#define PI (+3.1415926) // # 预处理指令,告诉gcc 以后遇到 PI这个符号,统统都替换为 后面的##东西##
#define PRINT printf("nice hello world\n")
#define SECOND_PER_YEAR 365*24*60*60
double circle_square(double r)
{
PRINT ;
return PI*r*r;
}
double circle_length(double r)
{
PRINT;
return PI*2*r;
}
double circle_xxx(double r)
{
PRINT;
return PI*xxx ;
}
######宏参数/宏函数 #######
求最大值
#define MAX(A,B) A>B?A:B
int cc = MAX(5,6);
被替换为 5>6?5:6
#define MAX3(A,B,C) A>B? A>C?A:C : B>C?B:C
printf("max is %d \n", MAX3(33,44,55) );
乘法:
#define MUL(A,B) A*B
int cc = MUL(5+3,6+8); 5+3*6+8 发现有问题
解决方法:
#define MUL(A,B) (A)*(B)
MUL(5+3,6+8) (5+3)*(6+8)
#define ADD(A,B) (A)+(B)
ADD(5+1,6+2)*2 (5+1)+(6+2)*2
解决方法:
#define ADD(A,B) ( (A)+(B) )
ADD(5+1,6+2)*2 ( (5+1)+(6+2)*2 )
#define MAX(A,B) ( (A)>(B)?(A):(B) )
MAX(++a,8); ( (++a)>(8)?(++a):(8) )
出问题了,没有解决方法,不要 这么用
宏函数使用注意事项:
1.所有的 参数,都必须使用 () 裹起来
2.整个宏函数必须被() 裹起来
3.参数不要++ --
宏参数 和 函数的区别:
都是代码段,可以实现相同的功能
区别:
#define MAX(A,B) ((A)>(B)?(A):(B))
int max(int a,int b)
{
return a>b?a:b;
}
main()
{
int cc = max(344,234);
max(45,234); max(123,253);
int dd = MAX(234,2344);// 替换为int dd = ((A)>(B)?(A):(B));
MAX(234,2323); MAX(234,3532);
}
1. 函数参数返回值都有类型,宏函数没有类型
2. 函数调用会发生跳转,而宏函数本地直接替换执行,执行效率高.
3. 函数多次调用,只有一份代码.宏函数在每次使用处展开一份,消耗空间.
编译过程:
gcc
main.c --------> main.out
编译
编译是一个很复杂的过程:
1. 预处理
代码中 有#开头的,都是在预处理阶段进行的. gcc 会对你的代码进行改动.
1) 将所有的 宏定义替换为 具体的内容
#define PI 3.14
2) 将#include 包含的头文件,在当前文件 中展开.
2. 编译
将C语言翻译为汇编语言
符号语言
3.汇编
将汇编语言转换为 二进制语言
4.链接
main.c aa.c bb.c cc.c dd.c .......
| | | .... 预处理
main.x aa.x bb.x
| | | 编译
main.S aa.S bb.S .....
| | | 汇编
main.o main.o bb.o 很多二进制文件
\ | /
\ | / 链接, 将众多二进制文件合并为一个 可执行文件.
main.out
练习:
实现一个函数,比较两个字符串是否相等. 如果相等返回0,否则返回 其他值
int mystrcmp(char s1[],char s2[])
{
int i=0;
while(s1[i] && s2[i]){
if(s1[i] - s2[i] ){
break; //中止
}
i++;
}
//代码到这里, 1) 两个都不为空,不相等 2) 只有一个为空,不相等 3) 两个都为NULL
return s1[i]-s2[i];
}
实现一个函数,完成字符串的拷贝:
char s1[]="hello wrold";
char s2[18];
mystrcpy(s2,s1);
printf("s2 = %s\n",s2);
void mystrcpy(char dst[],char src[])
{
int i = 0;
while(src[i]){
dst[i]=src[i];
i++;
}
//结束了,为什么 src[i]==NULL
dst[i] = '\0';
}
显示一个函数,完成字符串的拼接
"hello world" = "hello "+"word"
char s1[]="world";
char s2[32] = "hello ";
mystrcat(s2,s1);
printf("%s\n",s2);
void mystrcat(char s2[],char s1[])
{
int i=0,j=0;
//j移动到s2的\0位置
while( s2[j] ){
j++;
}
//j已经抵达 对应位置
while(s1[i]){
s2[j] = s1[i];
i++;j++;
}
// s1[i]已经抵达了 \0位置,但是 s2[j]还没有赋值
s2[j]='\0';
}
int main(void)
{
char s1[]="world";
char s2[32] = "hello ";
mystrcat(s2,s1);
printf("%s\n",s2);
}