×

C总结

96
eric007shine
2016.05.21 14:42* 字数 25924

C语言笔记

一终端命令

ls -l显示当前工作路径下的所有的文件及文件信息

d开头文件夹

-开头文件

r读

w写

x执行

- -当前用户的权限

- -其他用户的权限

> pwd查看终端程序的工作路径

>cd切换工作路径

>clear清理屏幕

>touch新建文件

>open开打文件

>rm删除文件

二一个project中多个target

一个项目中可以建立多个任务

如果新建:选中项目->target菜单下->add a target

如何启动:工具栏上更改target

如何开启语法事实检测:只会检测设置为启动的target

三删除引用与删除到垃圾桶

1>删除引用:只是在代码导航区,在finder中还是存在

2>删除到垃圾桶:代码导航区跟finder都删除

同时:target菜单下要删除,而且编译菜单下也要编辑删除

四枚举

用1/2/3跟1/2/4位移

区别:

用012的话,你如果是想第一种跟第二种搭配的话,就不行了,位移的话就是1.2.4,第一二种搭配就是3,第二三种搭配就是6,全部就是7

五内存

内存越大能同时执行的程序越多

因为程序运行的时候需要把硬盘中的程序拷贝到内存中,因为内存运行效率高

程序如果要处理数据,那么这个数据就需要被存储起来,并且必须存储在内存中

(加载进内存,只会加载运行的包,内存会将不在使用的包释放掉,再动态加载)

如何在内存中存储数据?

>在内存中挖个坑,将数据放到坑中,要用的时候去坑里面取

>通过16进制的地址来找到这个坑,每个坑在内存中都有一个独一无二的地址

>挖坑的时候,要给坑指定一个别名,到时候通过别名找到这个坑

坑的内型?

在挖坑的时候,需要指定坑的内型,坑的内型决定了坑能放什么数据

六数据类型

int-21亿~ +21亿之间

float存储有效位数为7位的小数(有效位数位除开小数点以后所占位数)

如果有效位数超过7位,只能精确保存前面的7位.后面的数字不能精确保存,后面的数字是随机数字

double存储有效位数为16位的小数(有效位数位除开小数点以后所占位数)

char只能存储当个字符:用单引号引起来,空格也是一个字符

七开辟空间

1>在内存中开辟一块空间,开辟空间的时候指定空间类型与别名

别名:区分空间的唯一标识

类型:决定空间存放的数据的类型

2>变量

变量内存中开辟的一块用来存储数据的空间

变量的值:

变量的类型:就是变量所代表的那块空间的类型

变量的名称:

变量的本质:内存之中用来存储数据的那块空间

3>开辟空间

在内存中开辟空间实际就是声明一个变量

语法:数据类型变量名;

intnum;

4>如何往变量所代表的存储空间存储数据

语法:变量名=数据;

num =10;

=赋值符号:

作用:将赋值符号右边的值,存放到左边变量所代表的存储空间中

注意的几个细节:

a.当我们在C语言之中直接写一个小数的时候,这个小数的类型是double类型的

要表示float类型,必须在这个小数的后面加一个f/F

b.C语言之中没有用来专门保存字符串的类型

要保持字符串用字符数组

c.如果我们声明一个变量,没有给这个变量赋值,那么这个变量里面的值是垃圾值,里面的数据是随机的

e.书写规范:在赋值的时候,赋值符号=,2边要有一个空格

八printf函数输出变量

1>printf(“格式控制占位符”,变量名);

%dint类型整型

%ffloat类型单精度浮点型/实型

%lfdouble类型双精度浮点型/实型

%cchar类型字符型

注意:占位符与变量名个数要相等,且位置要对应

实型/浮点型默认输出小数点后面六位

2>高级用法

%d是专门用来输出int类型变量的值

%md m是一个整数.表示输出的数据占多少位;

如果m>实际位数不足用空格补齐.

如果m<=实际位数,按实际位数输出

m如果是正数在左边补空格,如果是负数就在右边补空格

%0md不足用0来补齐

%f与%lf默认用来输出小数点后6位的小数

%.nf与%.nlf  n是一个整数,表示输出小数点后面多少位

%m.nf与%m.nlf输出一共m位,小数点后有n位的小数,不足的补空格(m位包含小数点)

九变量的命名规则

1>变量名任意的字母,下划线,$开头,不能以数字开头

2>后面只能跟任意字母,数字,下划线还有$

3>不能与C关键字重名

关键字:指的是C语言中代表特殊意义的英文单词,不能把他们作为变量名

4>C语言严格区分大写,age不等于Age

5>变量一定要先声明,再使用

6>在同一个大括号(作用域)中,不允许声明同名的变量

十变量的命名规范

1>变量的名字要取得有意义—>见名知意

2>如果变量有多个单词组成,第一个小写,其他大写—>遵守驼峰标识

十一总结

1>变量可以重复赋值:新值替换旧值—>喜新厌旧

2>将a变量的值赋值给b变量.是将a变量的值拷贝一份给b变量

3>char类型的变量只能存储单个字符,不能存储中文,一个中文字符占三个字符

4>变量的初始化:第一次为变量赋值就叫做变量的初始化

5>如果变量类型不匹配,系统会自动做类型转换

float->int舍弃小数

int->float自动补小数位.0

floatf1 =12.34;//会讲double12.34转换成float的12.34再存储

floatf2 =12.34f;//直接存储

6>char变量的本质int类型

charch =97;//对应ASCII表将int对应的字符

===============================================================

第三天

一scanf函数———阻塞式函数

在执行这句代码的时候,cup的执行会暂停

1>语法:scanf(“格式控制字符串”,变量地址列表);

2>例子

intnum =0;

scanf(“%d”,&num);

3>注意:

a.格式控制字符串中写占位符,占位符和printf占位符一样,代表要求用户输入一个什么类型的数据

b.第二个参数,代表将输入的数据存储到该变量中.不能直接写变量,应该写变量的地址

c.后面跟的变量的类型要和前面的占位符一致.

d.scanf是输入函数,不需要\n换行

e.使用scanf函数之前需要初始化一个变量来存放输入的值

4>执行原理

阻塞式函数

在执行这句代码的时候,cup的执行会暂停,等待用户输入.输入完毕按下回车表示输入完毕,

程序将用户输入的值保存到变量中,程序将继续执行

5>补充

1>当要求用户输入一个数的时候(),用户输入的空格,tab,回车,会被系统自动忽略

2>scanf可以一次性接受多个数的输入.

格式,在scanf的格式控制字符串中使用多个占位符,表示让用户输入多个数据

在后面跟上输入的每个数据存储到哪一个变量之中

3>用户如何分割多个数据:使用空格或者回车来分割多个数据.

4>当一次性输入多个数据的时候(整数和浮点数),默认的分隔符号是空格或者回车.

通过scanf(“%d,%d”,&num1,&num2);来自定义逗号为分隔符.

如果指定了分隔符就不能用别的字符来做分隔符

6>scanf函数的原理

a>当用户从键盘上输入数据的时候,数据会先存储在缓冲区中.

b>当执行scanf函数的时候,会先检查缓冲区当中是否有数据,如果有数据先取出里面是数据赋值给变量,如果没有

才让用户输入.

c>当是整形跟实型的去缓冲区读数据的时候会自动跳过空格和回车

d>当变量是char类型的时候,去缓冲区拿数据,不会跳过空格和回车

解决实现跟char类型配套输入,char读到回车的问题,再多一次scanf(“%c”,&ch);

7>清空缓冲区—>解决char类型的scanf问题

a>引入头文件

b>在scanf(“%c”,&ch);之前写上

rewind(stdin);//会将缓冲区中的所有数据清空

8>逗号表达式

逗号运算符:由逗号连接起来的式子;

intnum = (1+1,2+3,i+j,i-j);

将逗号运算符最后一个表达式的值,赋值给变量num;

逗号表达式目的是让前面的表达式执行

=============================

第四天

1.类型转换

将整数/实型->char类型

将这个数的整数部分,作为ASCII码,取出对应的字符

2.关系运算符/比较运算符

>, <, ==, >=, <=, !=

>在C语言之中,使用int类型的变量来表示一个条件的真假,0假,1真

>作用:用来比较2个数据的关系

>如果实型或者整数在跟char比较的时候,是跟char的ASCII比较

3.逻辑运算符

&& , || , !

>&&逻辑与,并且,都成立才成立

>||逻辑或,或者,有一个成立则成立

>!逻辑非,取反,真则假,假则真

>断路问题:

在计算逻辑表达式的时候:是先计算左边的条件表达式,再计算右边的条件表达式

如果是&&,当左边的不成立,则右边的条件表达式不会执行

如果是|| ,当左边的成立,则右边的条件表达式也不会执行

>逻辑运算符的优先级

not and  or

! > && > ||

4.运算符的优先级

>C语言中的运算符分为15个等级,1级的优先级最高

5.运算符的结合性

当表达式中的所有运算符的优先级相同的时候,才考虑到结合性

6.if结构

>语法:

if(条件表达式){//条件表达式就是:比较表达式和逻辑表达式

执行代码;

}

>执行顺序:

先判断if后面的条件表达式的真假

如果为真则执行if中的代码块,如果为假则跳过if中的代码块

7.关于分号”;”

1>在C语言中,分号代码一条指令的结束,一般情况下,我们应该在一条语句的后面跟上分号

2>如果是一个代码块的话,就不需要为这个代码块加分号

代码块:凡事一对大括号就是一段代码块,因为大括号结束就代表代码块结束

8.关于if语句后面的条件表达式

C语言的语法其实规定if后面的小括号中什么表达式都可以写

如何判断if后面的表达式先将结果计算出来:先将表达式的结果计算出来(0为假,非0为真包括负数)

虽然任何表达式都可以写,但是我们一般情况下都写的是条件表达式,其他类型的表达式没有意义

9.永真永假问题

if(1)//永真if(0) //永假

10.变量的作用域

1>变量声明以后,什么时候回收?

当CPU在执行程序的时候,如果执行完一对大括号

会将声明在这个大括号之中的变量立即回收掉

所以在定义在一对大括号之中的变量,只能在大括号之中使用,出了这个大括号就无法访问了.

如果在一个函数中,一个变量只会在前面几行代码用到,想提前回收这个变量的内存空间,可以

将相关的代码,手动加一个大括号

2>在内层作用域可以声明定义一个与外层作用域同名的变量

如果作用域重叠,内层作用域的变量会覆盖外层作用域的变量

#写代码的时候,尽量避免重名的变量

11.if--else

if结构只能完成条件满足执行,条件不满足不能搞定

需求:条件成立执行一段代码,条件不成立执行一段代码.

用if实现效率低,需要判断几次

语法:if(条件表达式){

执行代码块1;

}else{

执行代码块2;

}

if--elseif

1>要判断多个条件,而且条件的判断是有顺序的

2>从上到下依次判断每个条件表达式

3>只要有一个条件成立,就会执行其中的代码块,执行完毕结束if结构

4>语法:if(条件表达式1){

}elseif(条件表达式2){

}elseif(条件表达式3){

}else{

}

5>注意点:

>elseif可以有多个

>else可以没有

13.三元表达式

根据运算符的作用不同来区分运算符:算术运算符/比较运算符/逻辑运算符

根据参与运算的数据的个数不同,我们将运算符分为:

1>双目运算符:

2>单目运算符: ++/- - /!

3>三目运算符: ? :

三目运算符又叫三元表达式

4>语法:条件表达式?值1:值2;

5>结果:如果条件表达式成立,那么三元表达式的结果等于值1,否则为值2;

6>注意:值1和值2可以是一个数据,也可以是个表达式,也可以是一个语句

当值1和值2是一个语句的时候,会执行语句并把语句的返回值赋值给三目运算符

14产生随机数

1>引入头文件

2>arc4random_uniform(一个数字num);//产生一个0~(num-1)

3>产生一个n~m的数字

arc4random_uniform(6) +5;//0+5~5+5 ->5~10;

==================================

第五天

1.switch

1>.switch(表达式/数值(int/char都可以)){

case值1:

代码块1;

break;

case值2:

代码块2;

break;

default:

代码块3;

break;

}

2>switch与if比较

a.能够使用switch的就能使用if结构

b.能使用if的不一定能使用switch

3>总结:

a.switch只能直接做等值判断,判断switch后的值是否跟case后的值相等

b.if不仅能做等值判断,还可以做范围判断

c.switch后面的表达式的结果不能是实现,(因为计算机在保存实型的时候不是保存的精确的值,而是无限接近这个值.switch-case在

判断的时候是根据大小来判断,而实现没办法精确比较,所以就不让使用)

d.在case块的代码块中定义变量必须要加大括号,因为如果不加大括号就会造成作用域混乱(不清楚到底属于哪个case块)

4>case穿透

a.不写break可以实现case穿透

b.没有特殊情况,不要省略break

3>当多个case块的处理逻辑是一样的时候,前面case的break就不要写

程序的调试

1>断点:当cpu执行到断点处的时候,cpu会暂停执行

2>功能

a:跟踪CPU执行程序代码的步骤

b:点击调试区的stepover指令,让cpu执行该段代码

3printf缓冲区

遇到printf就会将里面的打印内容放到缓冲区

当遇到\n

4.while循环

1>需要执行多少次的需求:使用循环

2>如何寻找循环体:(使用复制粘贴完成需求)需要重复执行的代码.就是循环体

3>在利用循环进行数值比较的时候,如何解决max的初始值为0,输入的是负数的时候,最大值求出来

是0的bug

a>判断如果输入的是第一个数就不让改数跟初始值进行比较,而是直接赋值max = num

b>讲max设置为最小的值INT32_MIN

4>死循环:永远都不会结束的循环就叫做死循环

5>循环的应用

场景之一:确定循环体,确定循环次数

场景之二:确定循环体,但是不确定次数,但是确定循环继续或者结束的条件

场景之三:遍历指定范围的数.

场景之四:找出指定范围之中符号特定条件的数

场景之五:求累加和与平均值

5.break与continue

1>break

a.break关键字用在switch结构中,代表结束这个switch结构

b.break用在循环体中,就会立即结束当前循环结构

所以在循环题中,有2中方式来结束循环结构

第一种:条件不满足,第二种:break

2>continue

a.只能用来循环体中

b.如果在循环体中遇到continue,会立即结束本次循环,回到重新判断条件的位置,

continue后面如果还有代码,也不会执行

==============================

第六天

1>dowhile

2>for循环

a.语法

for(初始化表达式;循环条件表达式;循环后操作表达式){

循环体;

}

b.执行顺序

初始化表达式—>循环条件表达式——>循环体—>循环后操作

c.和while的区别

没有区别;只是语法结构不一样

3>for循环嵌套

===============

第七天

1.代码结构

a>顺序结构:从上到下按顺序依次执行

b>分支结构:程序在执行到某处的时候,会有多个分支

最终根据具体情况选择一个分支来执行

if结构,switch-case结构

c>循环结构:反复不停的执行指定代码块

while/do-while/for

2.goto

a>可以将CPU的执行跳转到当前函数的其他地方

b>如何使用呢?

1>先给要跳转到的代码的地方取一个标签名: loop:

2>在需要跳转的地方写上goto标签名;

c>如何执行的呢?

当执行到gotoXX语句的时候,这个时候cpu就会跳转到这个标签继续执行

d>虽然看起来很好用,但是不建议使用

因为它不安全,容易引起死循环.

e>注意点

1>标签名随便取,但是要符合标识符的命名规则及规范

2>不仅可以往前面跳转,也可以往后面跳转

3>goto不能跨函数跳转,只能在当前函数跳转

3.函数

1>作业:实现代码的复用

2>如何用函数实现代码重用

a.写一个函数

b.将重复的代码写在该函数中

3>如何定义函数:

a.位置:直接写在.c的源文件中,与main函数同级别,不要写在main函数中

b.语法

返回值类型函数名([参数列表]){

那段需要被重用的代码;//函数体

}

4>函数的调用

a.我们把一段程序交给CPU,cpu只会执行main函数

b.如果我们循环cpu执行我们自定义的函数,需要在执行该函数的地方调用一下

c.语法:函数名();

d.执行顺序:当cpu执行到函数调用的位置,会跳转到自定义函数中去

5>函数的返回值

a.函数返回值----void表示没有返回值

b.函数名:函数名由程序员定义,但是要符合标识符命名规则和规范

>驼峰表示

>函数名要有意义,见名知意,尽量使用一个动词,让别人知道该函数是干什么的

>一个函数,只完成一个独立的功能

>函数名后面的小括号不能少,用来放形参的

>函数调用的时候小括号不能少

6>什么时候我们需要定义一个函数

a.有重复的代码,多个地方需要被用到

b.如果有一段代码是实现一个独立的功能,可以把这段代码封装到一个函数中

7>函数的好处

a.减少代码的冗余

b.修改和维护十分的方便,只需要修改函数体,其他调用地方不用管

c.屏蔽代码的实现

对于函数调用着而应,不需要关心函数内容是如何实现的,只用关心函数的功能

8>断点调试:stepInto可以调入到函数内

4.全局变量

1>变量:本质上就是在内存中开辟的用来存储数据的空间

2>局部变量:凡事定义在函数内部的变量都叫做局部变量

3>全局变量:也是定义在.c源文件中的,也就是定义在函数外部的变量

4>全局变量与局部变量的区别

a,作用域

>.局部变量的作用域:在函数内部从定义的哪一行开始到函数结束

在一个函数中不能使用另一个函数中的局部变量

>.全局变量从定义开始到程序结尾都可以使用

全局变量一般都定义在所有函数前面

b.默认值不同

>局部变量定义的时候不赋初值,那么他就是垃圾值

>全局变量只声明不初始化的话,默认为0.

如果是char类型,那么默为’\0’空字符

c.回收时间不同

局部变量:作用域结束,所在代码块的大括号结束就会被系统回收

全局变量:程序退出

5>全局变量的细节

a.函数不调用,里面的代码不会执行

全局变量,在整个程序运行中只会产生一份,独一无二

各个函数访问的是同一个全局变量,被所有函数共享

b.在函数内部可以定义一个与全局变量同名的局部变量

5.带参数的函数

函数内部的数据到底是多少?是由调用者在调用这个函数的时候,调用者告诉他

1>什么是参数:在小括号中声明的一个变量

2>参数的本质:就是定义在这个函数之中的一个局部变量

所以不能在函数之中再声明一个和参数名相同的局部变量.所以函数内部能直接使用参数的值

3>在声明参数的时候,实际上就是声明一个变量,只不过变量放在小括号之中的.所以在声明的时候

一定要指定参数的类型

4>如何给函数的参数赋值呢?

在调用函数的时候将需要传递的值放在调用函数名后的小括号

5>形参:定义函数的参数

实参:调用赋值的参数

6>实参的类型最好和形参的个数与类型一直.(类型不一致会做类型转换)

7>函数的参数可以实现什么功能?

调用者可以将自己的数据,通过参数传递到函数的内部去

8>什么时候需要定义一个参数

a>参数的功能:函数的内部需要调用者提供的数据的时候,调用者想要给函数传递一些数据

b>函数内部在完成一个功能的时候,发现需要一些数据才可以继续完成.这个数据的类型确定

但是这个数据的具体取值只有调用者才清楚

9>注意点

a>函数可以声明多个参数吗?可以,多个参数直接用逗号分割

b>我们在声明参数的时候,如果不指定参数的类型,那么默认就是int类型(就算可以省略但是不建议)

在声明多个参数的时候,如果后面的参数不知道类型,类型默认就是int

c>如果在函数调用的时候,函数带多个参数,必须要为每个形参传递实参,实参也是用逗号隔开

并按照顺序赋值

d>实参可以是数值/变量/表达式

变量就传递的是变量的值.表达式传递的是表达式的结果

6.return关键字

1>在函数中,结束函数,不在执行return后面的语句

2>返回值

7.函数的返回值

1>什么时候函数需要返回值

函数执行完毕之后,函数内部不确定如何处理这个数据,

函数就应该将这个数据返回给调用者,由调用者自己来决定如何处理这个数据

2>函数如何将数据返回给调用者?

a>确定返回值类型

b>将函数的返回值类型修改要返回的数据类型

c>使用return关键字返回结果

d>函数调用者如何拿到这个数据,定义一个对应类型的变量接受,讲函数的返回值赋值给这个变量

3>注意点

a>函数的返回值类型,代表函数执行完毕之后,有一个这个类型的数据返回给调用者

调用者可以选择不接受.

b>void代表函数执行完毕后没有任何数据返回给调用者

c>return:

如果函数没有返回值:直接使用return代表立即结束函数的执行,后面不要跟数据

如果函数有返回值:在函数结束之前必须使用return关键字结束函数,并返回数据

如何函数内部有分支,必须保证每个分支都有返回值,否则会报错

如果函数定义了返回值没救必须要有return+数据;

d>为什么函数定义在后面会报错

1) C代码,先编译,链接,运行(编译是从上往下编译,在编译到函数的调用的时候找不到函数就会报错)

如果函数的定义放在后面,那么在编译调用函数的那句话的时候就会出问题

在编译这句代码的时候,编译器会认为这个函数并不存在,所以就报错了.

2)函数的定义包括:函数的声明+函数的实现

函数的声明

语法:只写函数头.直接在后面加一个分号.

作用:告诉编译器,这个函数是有的,只不过这个函数在后面或者其他文件之中.

函数的实现:完成函数的功能

3)如果被调用的函数,定义在主调函数之前,那么就不用声明直接定义

4)声明函数的函数投必须要和定义函数的函数头一致.

函数声明的时候,形参可以只要形参类型,省略形参名

=============================

第八天

一预处理指令

C源文件之中的代码主要分为两种

->c代码

->预处理指令

1>.c源文件->预处理操作->检查语法->编译->链接->执行

预处理指令的执行时机:在编译之前

2>预处理指令

1).分类

文件包含指令#include

宏定义#define

条件编译#ifdef

2).特点

a.所有的预处理指令以#开头

b.指令结束的时候没有分号.

c.在编译之前执行

3>#include指令文件包含

a.作用可以讲文件的内容拷贝到写指令的地方

b.语法:

#include “文件路径”

#include<文件路径>

c.用法

#include “/Users/appe/Desktop/abc.txt”

>在编译之前,做预处理操作的时候,会讲这个文件的内容拷贝到指令处

然后在编译,链接,执行

>如果被包含的文件中代码不符号C语言的规范,那么在编译的时候就会报错

在预编译的时候,只是拷贝,在编译的时候会检查语法

>文件的后缀名可以随便取,重要的是文件内容

4>实际情况下我们不会将要被包含的文件乱放

一般都是和源文件放在同一个目录中,这样方便管理

如果被包含的文件和当前源文件在同一个目录下,那么这个时候写路径的时候就不用写完整的路径了

>路径部分和当前源文件文件夹路径相同的部分可以直接省略—>”直接从当前源文件的文件夹开始写”

>绝对路径:路径从根目录开始,叫做绝对路径

相对路径:路径不是从根目录开始,而是从当前源文件所在的目录开始的

>一般情况下,被包含的文件我们都是和源文件放在同一个文件夹的

那么我们在#include的时候,写相对路径就可以了.直接从当前源文件所在的文件夹开始写

5>#include指令的详细使用

1).#include指令的后面路径可以是双引号与尖括号

a.相同点都是包含文件

如果路径是一个绝对路径,效果是一样的

b.不同点如果路径是一个相对路径的时候

#inclue “文件路径”先去当前源文件所在的文件夹目录下去查找是否有这个文件,有则包含

再去Xcode自带的编译器目录下去查找是否有这个文件,有则包含,无则报错

#include<文件路径>直接查找Xcode编译器所在的目录,如果有直接包含,如果没有就报错

c.建议.如果是系统自带的用<>性能高(也能用””) ,自定义的是在源文件所在文件夹目录下,只能用””

6.C语言提供了很多的函数,函数库

如果我们去调用函数库之中的函数,那么就必须要把这个函数的声明所在的头文件包含进来

二多文件开发

1.实现步骤

a.先新建一个.c源文件,实现这个功能模块的人在这个之中实现函数

b.写模块的人,一般情况下,还需要一个.h文件

c.然后在.h文件中将.c文件中的函数进行声明

d.其他人如果要使用模块中的函数,只需要包含这个模块的头文件(.h)文件

e.如果写模块的人,要增加,删除,修改.那么.h文件也需要同时修改

2.总结

a.一个模块至少包括2个文件

.h写函数的声明

.c写函数的实现

b.要修改的时候,2个文件需要同时修改

c.如果想用模块中的函数,只需要包含这个模块的.h(头文件)就可以了

三进制

1.二进制

intnum =0b11011;//在C语言中用数字0与字母b标识这个数据是二进制数,(没有格式控制符输出二进制)

2.八进制

intnum =014730;//在C语言中用前缀数字0标识这个数据是八进制数,输出用%o(字母o)

3.十进制

intnum =10;//输出控制服%d

4.十六进制

intnum =0x12adf0;//在C语言中用前缀数字0与小写字母x来标识这个数据是十六进制的(输出控制符为%x(字母x))

5.基本概念

6.十进制—>二进制

葵花宝典:除2取余法.十进制数除以2,直到商为0或者1为止,然后余数倒过来读

7.二进制—>十进制

葵花宝典:加权法将二进制数的每一个数码的位权相加

8.十进制—>八进制

葵花宝典:除8取余,直到商小于8为止,余数倒过来

9.八进制—>十进制

葵花宝典:加权法

10.二进制—>八进制

宝典:三合一从低位到高位每三位分成1组.高位不够补0

然后求出每组转换为一个八进制,再把这些十进制相连就是这个二进制对应的八进制

11.八进制—>二进制

宝典:一拆三将八进制的每一个数码,拆成一个三位的二进制,再将这些二进制连起来

12.二进制—>十六进制

宝典:四合一从低位到高位每四位分成1组.高位不够补0

然后求出每组转换为一个十六进制,再把这些十进制相连就是这个二进制对应的十六进制

13.十六进制—>二进制

宝典:一拆四将十六进制的每一个数码,拆成一个四位的二进制,再将这些二进制连起来

14.八进制—>十六进制

宝典:八进制—>二进制—>十六进制

四变量在内存之中的存储细节

0.内存中的数据存储单元是由一个个的二进制位组成,每一个二进制位只能存储0或者1.

这样一个二进制位只能存储0或者1

1.8个二进制位(bit)叫一个字节(byte),作为存储数据的最小基本单位

如果使用一个二进制位:最多存2个数据

如果使用一个字节:最多存储2的8次方256个数据

2.为了让内存单元可以存储更多,更大数据,把八个二进制位合成一组,叫做一个字节

一个字节有8个二进制,那么一个字节能表示256种状态,一个字节可以存储更多的数据

3.单位换算

8bit =1byte

1024B =1KB

1024KB =1MB

1024MB =1GB

1024GB =1TB

4.变量

声明一个变量,实际上是在内存中申请指定字节数的空间,来存储数据

int会在内存中申请4个连续的字节空间

float4个连续存储空间

double8个字节的连续空间

char1个字节的连续空间

5.sizeof运算符

1>作用:计算指定数据类型的变量,常量,变量在内存之中占据多少个字节

2>语法:sizeof(数据类型/变量/常量);//返回给定的数据在内存之中占据的字节数

3>注意:

a.除了char类型之外,其他类型的数据,无论是变量还是常量在内存之中占据的字节数都是一样的

b.char类型的变量在内存中占一个字节,但是char类型的常量占据的是4个字节

c.所有的常量数据是存储在常量区的,字符常量在常量区占据的是4个字节,因为要支持更多的字符

d.如果要计算的是常量或者变量可以省略sizeof后面的小括号,如果要计算的是数据类型那么小括号不能省略

五原码,反码,补码

1.无论任何数据在内存中都是以其二进制形式存储

2.原码,反码,补码都是二进制,只不过是二进制的不同表示形式

3.原码

a.正数符号位是0,其他位是二进制

b.负数符号位是1,其他位是绝对值的二进制

4.反码

a.正数的反码就是其原码

b.负数的反码就是在其原码的基础上符号位不变,其他位取反

5.补码

a.正数的补码就是其原码

b.负数的补码就是在其反码的基础上加1;

6.所有的数据都是以其二进制的补码的形式存储在内存中的

7.为什么要使用补码来存储数据

因为计算机之中只有加法,没有减法.为了更低成本的计算出结果,所以使用补码来存储数据

3-2—>3+(-2)

原码计算

00000000000000000000000000000011

10000000000000000000000000000010

—————————————————————————————

10000000000000000000000000000101结果-5

反码

00000000000000000000000000000011

11111111111111111111111111111101

—————————————————————————————

00000000000000000000000000000000结果0

补码

反码

00000000000000000000000000000011

11111111111111111111111111111110

—————————————————————————————

00000000000000000000000000000001结果1

六位运算

1.什么叫位运算

一个二进制数的每一位来参与运算,参与位运算的前提:这个数必须是二进制数

2.参与位运算的二进制数据必须是补码,并且算出来的结果也是补码

3.按位与运算:&

a.按位与运算:指的是两个数的二进制的补码按位与进行与运算,如果都为1,结果就是1,否则为0.

b.思考的问题

任何数按位与1结果是这个数的最低位

偶数的最低位一定是0,奇数的最低位一定是1;———>应用场景:判断一个数是奇数还是偶数

4.按位或|

参与按位或的二进制补码只要有一位为1,那么结果就是1,只有都为0的时候才为0

5.按位取反~

这是一个单目运算符,每个补码进行取反,0为1,1为0

6.按位异或: ^

相同为0,不同为1

两个变量一样的时候进行按位异或得出1: a ^ a =1;

应用场景: ————>交换2个变量的值

inta =3;

intb =2;

a = a ^ b;

b = a ^ b;——>b = a ^ b ^ b = a;

a = a ^ b;——>a = a ^ b ^ a = b;

7.按位左移: <<

1个二进制补码按位左移.就是将这个二进制位,向左移动指定的位数,溢出部分丢弃,低位补零

3<<2

3的补码按位左移2位

注意:1)一个数按位左移,有可能改变其正负性

2)一个数按位左移N位,相当于这个数乘以2的N次方

8.按位右移动: >>

参与按位右移的二进制补码,向右移动指定的位数,溢出部分补齐,高位补符号位(正数补0,负数补1)

注意:1)按位右移不会改变一个数的正负性

2)一个数安位右移N位,相当于这个数除以2的N次方

七深入变量的细节

1.内存之中存储数据的最小基本单位是字节

1个字节是由8个二进制位组成的

2.每一个字节在内存之中都有一个独一无二的地址

这个地址是一个十六进制的数(因为十六进制表示一个数是最短的)

连续的两个字节的地址一定是连续的

3.当我们声明一个变量的时候:就是在内存中申请指定字节的连续

申请的变量所占的字节一定是连续的,并且是从高地址到低地址分配的

数据是以二进制的补码形式存储在空间之中

存储二进制补码的时候,高位存储在高字节

4.变量的地址

变量的地址就是组成这个变量的低字节的地址

取出变量的地址: &变量名;格式控制符%p

5.变量的回收,垃圾值是如何产生的

1>申请一个变量:就是向系统申请一块指定字节数的空间,这个空间归这个变量所有

这个时候,如果还有人申请空间,是不会把已经申请的空间给别人

2>变量的回收:当一个变量被回收的时候,这个变量的数据是不会被清空的.

所以当这个时候申请一个变量如果不赋初值,就会是以前留下的垃圾值

3>所以我们声明一个变量的时候,第一件事情就是为变量初始化.

八int类型的修饰符

1.int类型4个字节32位除去符号位,表示区间在-2^31~2^31

有时候4个字节浪费(如存储age)

有时候又不够

2.int类型修饰符类别

short在内存中占2个字节,格式控制符: %hd范围:-2^15~2^15(shortint—>可以省略int)

long32位系统内存中占4个字节,64位系统下8个字节(OS X系统都是64位)格式控制符: %ld(%zd),longint可简写long

longlong无论多少位系统都是8个字节格式控制符:%lld可简写longlong

3.声明一个int类型的变量,占4个字节,最高位是符号位

但是有些情况不会出现负数(age),为了去除符号位可以用unsigned.

unsigned修饰的int类型是没有符号位的.范围0~2^32

占位符:%u

九char类型变量的深入

1.char类型的变量在内存中如何存储?

存储的是这个字符对应的ASCII码的补码(如’a’ —>ASCII值97——>二进制的补码)

2.所以char类型的本质是一个int类型的整数

3.所以在给char变量赋值的时候可以直接赋值整数

4.char的变量在输出的时候可以用%c(先读存储的整数->在查ASCII对应的字符),%d

==============================================================

第九天

一数组

1.数组的特点:存储多个类型相同的一组数据

2.数组的使用:创建/修改/拿数据/遍历

3.数组的声明

1>声明前,确认2点:存储的数据的类型/数据的个数

2>语法:

要存储的数据的类型数组名[要存储的数据的个数];

intscores[5];//在内存中创建一个scores的数组

3>数组在内存中是如何参加的

首先,在内存中开辟一块空间,这个空间就是数组

其次,将这个数组空间,平均划分成N等分的小空间

数组中真正存数据的不是数组,而是数组中的元素

4.几个专业术语

元素:数组中的每一个小空间,就叫做数组的元素

下标/索引:数组中有多个元素,为了区分每一个元素,C系统就为每一个元素编号

这个号码就是元素下标/索引

下标:从0开始,依次递增

最小下标:0

最大下标:元素个数-1

长度:数组中元素个数

5.如何存数据到数组中

1>数组名代表整个数组;

intarray[3];

array =10;//错误的不能直接给数组赋值

2>数组元素的赋值

数组名[下标] =数值;

array[0] =10;

3>元素的本质:其实就是一个普通类型的变量

4>注意点:

a.元素赋值的时候,数据的类型和元素不一致的时候,会类型转换

b.数组越界会导致程序崩溃

6.取出数组中的元素

通过下标取出

语法:数组名[元素下标];

7.数组的遍历

for(inti =0; i <数组的长度;i++){

array[i];

}

8.使用数组的时候需要注意的几个细节

1>声明数组的时候必须要指定数组的长度

2>数组的长度:只能是>=0的整数(不能是小数,不能小于0)

3>长度可以是常量,也可以是变量,或者是个表达式跟宏

4>长度也可以是个char类型的字符

5>数组的元素的默认值的问题

a.如果声明一个数组,没有赋值,里面存的都是垃圾值

b.声明的同时初始化

intarray[6] = {1,2,3,4,5,6};

intarray[] = {1,2,3,4,5,6};

intarray[5] = {100};//将第一个初始化为100,其他初始化0

intarray[5] = { [1] =100};//指定下标初始化,其他初始化为0

二数组在内存之中是如何存储的

1.在内存之中从高地址向低地址申请

数组的长度*每1个元素占用的字节数个空间

2.下标为0的元素是在低字节

3.所以数组的本质其实就是由指定个数的连续的变量组合成的

4.数组的地址问题

1>数组的元素的地址

数组的每一个元素是一个普通的变量,所以要拿到地址用取地址符&

2>数组的地址是什么呢?

a.数组的地址是下标为0的元素的地址,也就是最低字节的地址

b.array数组名,这个数组名中存储的是这个数组的地址(首元素的地址)

c.数组名存储的是数组的地址,要输出数组名的地址用%p

d.数组名不代表整个数组(代表的是数组的地址)

5.数组的长度问题

1>sizeof()计算数据在内存中占有的字节数

sizeof(数组名):就会计算出这个数组在内存之中占用的总字节数

数组的长度=总字节数/每个元素的字节数

2>为了能在不同系统下计算的长度都是准确的,所以一个元素的字节不要写死

因为有些类型,不同平台元素的长度不一样

解决办法

intlength =sizeof(array) /sizeof(array[0]);

6.初始化遇到的问题

1>在声明数组的同时初始化数组元素:

如果指定数组的长度用的是常量,可以在初始化的时候给数组元素赋值

如果指定数组长度用的是变量,就不能在定义数组的时候给元素赋值

intarray[4] = {1,2,3,4};//不会报错

——>编译的时候会转换成如下代码在执行.

array[0] =1;

array[1] =2;

=======================

编译器在编译的时候是还没有声明数组,

intlength =4;

intarray[length] = {1,2,3,4};//会报错.因为在编译的时候length的值不确定,不能转换成赋值代码

编译器在编译的时候,数组的长度还不确定,(因为只有在程序运行的时候才会给length赋值为4)所以在编译成

array[0] =1;//可能会导致数组越界

三数组的应用

1.求一个整型数组中的最大值

2.最小值

3.累加和

4.平均值

5.判断数组中是否包含指定的元素(定义一个flag来做标记)

6.找出指定元素在数组之中第一次出现的下标

7.随机产生N个不重复的整数(数组记录产生的数,没产生一个与之前数组中的数字比较,相同就重新随机,索引--)

四数组与函数

1>在调用带参数的函数的时候:为形参传值的本质是赋值,将实参的值赋值给形参

2>函数的参数可以是一个数组

因为数组本事也是一个数据类型(构造类型)

a.如果函数的形参是一个数组,那么在调用这个函数的时候也要传一个数组

b.数组的类型也要一样(int类型的数组就必须传人一个相同类型的数组)

c.当数组作为函数参数传递的时候,会丢失数组的长度.所有无法在函数的内部通过sizeof

去计算参数数组的长度

d.sizeof(数组名)永远得到都是8个字节;因为数组传递是指针(地址)传递

而指针的长度是固定的8个字节

e.当数组作为函数参数的时候,在声明这个数组参数的时候,并不是去真正的声明一个数组,而是去声明一个用来存储

地址的指针变量.调用函数的时候传递的是数组名(地址指针)

f.可以在调用函数的时候查看参数的提示是一个:类型*数组名

g.解决办法

在要求传递数组的函数中:多加一个形参这个形参是数组的长度

因为数组传递的是地址,所以在形参中定义数组的时候,数组的长度可以不写

voidtest(intarray[],intlength){}

五排序算法

如果数组中有N个数据要比N-1轮(最后一个元素不需要比较)

第M轮,拿下标为M的元素和下标为M+1到最后一个元素挨个比较

for(inti =0;i < length-1;i++ ){

for(intj = i+1; j < length; j++){

if(array[i] < array[j]){

//i跟j交换位置

}

}

}

===============

第十天

一冒泡排序(每次相邻2个数比较)

0.与选择排序的比较

1>选择排序,每次从第N个位置的元素与他后面所有的元素进行比较

1.特点

数组中N个数据比较N-1次//外层控制比较次数

第M轮,循环的次数为length-1-i//内存控制每轮比较多少次

二二维数组

1.一个二维数组就是一个有行有列的表格

2.声明语法

元素类型数组名[行号][列号]

3.几个术语

元素:每个单元格就是二维数组的元素

下标:一个元素有2个下标,一个行下标一个列下标

长度:单元个的个数

4如何存储数据

数组名[行下标][列下标] =数据;//注意下标不能越界

5.如何遍历二维数组中的所有元素

intlength =sizeof(array)/sizeof(int)

for循环遍历二维数组

6.二维数组的初始化

1>.

intarray[2][3]={

{1,2},

{3,4}

}

2>省略行数自动根据后面的大括号的个数来计算行数

intarray[][3]={

{1,2,3},

{4,5,6};

}

3.>注意点

再初始化的时候行号可以省略,但是列号不能省略

7.二维数组的本质:

1>二维数组其实是一个一维数组.只不过这个一维数组的元素的类型是一个数组

2>二维数组的本质就是一个一维数组,二维数组的每一行就是这个一维数组的元素

我们可以拿到二维数组的每一行的地址.每一行是一个数组

二维数组的地址,就是这个二维数组的第0行的地址

3>二维数组名中存储的是这个二维数组的地址

4>二维数组在内存中的地址分配:一块连续的存储空间.从高字节开始分配存储空间

下标小的元素存放在内存地址低的字节中.

8.二维数组的长度,行数,列数的计算

长度:单元格的个数

行数:sizeof(数组名)/sizeof(二维数组名[0])

列数:sizeof(二维数组名[0]) /sizeof(二维数组名[0][0])

9.二维数组与函数

1>如果函数的参数是一个一维数组,那么在调用这个函数的时候,可以传人一个二维数组的行

2>二维数组也可以作为函数的参数传递,但是一样会丢失这个二维数组的行数和列数.在函数内容使用sizieof得到永远是8

解决办法,传人二维数组的时候,同时传人行号与列号

3>当二维数组作为函数参数的时候,行数其实没什么用,因为根本不会创建数组

但是列数不能省略,而且实参的列数必须与形参的列数一致

解决办法:将函数与列数放在形参的前面,二维数组放在形参的后面voidtest(intx,inty,array[x][y])

10.字符串

字符串常量需要使用双引号””括起来

字符使用单引号''

1>字符数组

charchs[5];

表示声明了一个长度为5的字符数组.这个数组之中只能存储字符数据

2>字符数组的初始化

charchs[5] = {‘j’,’a’,’c’,’k’,’\0'};

3>遍历字符数组

4>字符数组默认值问题

a.声明一个字符数组,如果不为数组的元素赋值,元素就是一个垃圾值

b.如果声明字符数组的同时,我们初始化了部分元素的值,其他的元素的值会被自动初始化为’\0’

‘\0’表示一个不可见的字符

5>C语言是如何存储字符串数据的

a.字符串数据是以字符数据的形参存储的

字符串数据其实都由一个一个的字符组成的,那么我们可以将这个字符串的每一个字符存储起来

charnames[10] ;

//用’\0’来表示字符串的结束

//如果不用’\0’,初始化的时候里面都是垃圾值,如果赋值了前没3个,第四个赋值一个’\0’,就能有效的标识字符串结束了

6>字符串的声明

在声明字符串的时候如果指定字符串的长度,应该至少等于字符个数+1(‘\0’)

//通过字符给在字符串赋值的时候,最后一定要加’\0'

charnames[5] = {‘j’,’a’,’c’,’k’,’\0'};

charnames[] = {‘j’,’a’,’c’,’k’,’\0’};

charnames[] = {“jack”};//讲字符串中的每一个字符存储到字符数字中的每一个元素中,并自动追加’\0’

//常用方式

charnames[] = “jack”;//自动加’\0’,长度等于字符个数+1

7>注意细节

a.如果指定了字符数字的长度,那么这个字符数组的长度就是指定的长度

b.如果指定了长度,但是赋值的长度超过指定的长度那么就会出现存不下的状况

所以一般情况下,在声明字符数组的同事,建议不写长度

c.如果在声明的同时初始化一个字符数组的时候,可以给中文

“中文占三个字节,emoji表情占四个字节”

8>输出

占位符s% :printf(“%s”,names);

输出原理:将数组的地址传递过去,从给定的地址开始,一个字节一个字节读取输出,只到遇到’\0’结束

9>输入

scanf(“%s”,name).//不需要加取地址符,因为数组名就代表数组的地址

原理:将输入的字符串中的每一个字符存储到字符数组中,并自动追加一个’\0’

注意:a.输入的字符的长度如果超过了给定的字符数组的长度,会报错

b.如果输入了空格,会自动代表输入结束

三system(“clear”);

#include库里面有个system(“clear”);会讲终端屏幕上的所有信息清空

四走迷宫

======================================================

第十一天

一字符串的长度的计算

1.计算存储在字符数组中的字符串的长度

1>charname[] = “jack”;//sizeof计算出来5

2>charname[10] = “jack”;//sizeof计算出来为10

3>更加靠谱的算法

while(1){

if(name[count] != ‘\0’){

count++;

}else{

break;

}

}

二字符串常用函数

1.puts()函数

1>作业:输出一个字符串数据

2>优点:输出完毕字符串数据之后,会自动换行

3>缺点:只能输出字符串,并且不能使用格式控制符

2.gets()函数

1>作用:从控制台输入一个字符串数据,并存储在指定的字符数组之中

2>语法:gets(存储字符串数据的数组名)

3>特点:如果用户输入的有空格,也会接受

4>缺点:只能接受输入字符串

无论是gets还是scan都是不安全的,当准备存储字符串数据的字符数组的长度不够时候,就会出问题

————————————以上2个函数放在stdio.h文件之中

————————————以下4个函数的声明在string.h中

3.strcmp()函数compare

1>作用:比较两个字符串大小

2>语法:strcmp(字符串1,字符串2);//返回一个int类型的数据

3>比较原理:按位比较字符的ASCII码的大小

如果返回0,代表2个字符串是一样的

如果返回负数,说明第一个字符串比第二个字符串小,

如果返回正数:说明第一个字符串比第二个字符大

4.strlen()函数length

1>作用计算字符串的长度(计算的是字符串元素的个数,而不是字符数组的长度)

2>语法:strlen(字符串);

3>原理

4>返回值:unsignedlong/size_t (%lu输出)

5.strcpy()函数copy

1>作用:将str2中的字符copy到str1中(注意会连’\0'一起copy过去)

2>语法:strcpy(str1,str2);

3>注意:如果第一个字符数组的长度小于第二个字符数组的长度,那么使用strcpy就会运行奔溃

6.strcat()函数contact

1>作用:将str2中的字符拼接到str1最后一个字符后面

2>语法:strcat(str1,str2);

3>注意:a.如果字符数组1的长度,不够会运行出错

b.str2的第一个字符会覆盖str1中的’\0’

三指针—>C语言的灵魂

1.什么是变量的值,什么是变量的地址

1>变量的值:是指存储在这个变量空间中的数据

2>变量的地址:内存中每个字节都有独一无二的地址(地址是一个十六进制的数表示)

我们的变量是由多个字节(一个字节有8个二进制位)组成

组成这个变量的低字节的地址,就是这个变量的地址

2.指针变量

1>变量的地址就叫指针,指针就是地址

2>指针变量

首先是一个变量,用来存储地址的变量,也就是说指针变量中存储了另外一个变量的地址

这个指针变量指向了另外一个变量

3>神马用?

访问变量的方式

a.直接访问:通过变量名

b.间接访问:通过指针变量来访问

3.指针变量的声明

1>声明语法

数据类型*指针变量名;

2>注意

a. *的位置.int*p;int* p;int* p;

b. *的意思:代表这个变量不是普通变量,而是一个专门用来存储地址的一个指针变量

3>一个指针变量只能存储和这个指针类型相同的普通变量的地址

4>指针是一个变量

a.要符合变量的命名规则和规范

b.批量声明

int*p1,p2,p3;//就p1是指针变量

int*p1,*p2,*p3;//都是指针变量

4.指针变量的初始化

1>指针变量的特点:这个指针变量中只能存地址,并且只能存储相同类型变量的地址

所以不能直接赋值一个变量给它

2>intnum =10;

int*p1 = #

3>特别注意:一个指针变量只能存储这个类型的普通变量的地址

4>重要概率

int*p;//int *是一个整体, p才是指针变量名

直接写一个变量名取到的是存储在这个变量中的值

&变量名去到的是这个变量的地址

5.如何使用指针变量

intnum =10;

int*p1 = #

1>.p1:指的是p1的值,而p1的值是num变量的地址, p1 == &num

*p1:指的是p1指向的那个普通变量. *p1 == num

操作*p1就相当于操作num

6.使用指针需要注意的三个问题

1>野指针

声明一个指针变量,如果没有去初始化,这个指针变量之中是有值的,是一个垃圾值.一个随机值,一个随机的内存地址

无法确认这个随机值指向的空间是否有人使用?

像这样的指针,没有经过初始化的指针,指向了一块随机的空间,就叫做野指针

2>所有,当我没声明一个指针以后,最好要初始化一下这个指针,

如果声明指针的时候,不确定这个指针指向哪一个变量,那么就为其赋值NULL.代表这个指针不指向任何字节空间

//也可以直接赋值为0.

3>可以让多个指针指向同一个变量

7.指针作为函数参数

C语言中没办法直接返回多个值

返回数组的指针也是不可以的(原因,在函数中定义一个数组,返回了数组的地址,但是函数结束该数组也已经不再了)

解决办法,在主调函数中,定义一变量,将改变量的地址当坐实参传递过去,在函数中修改主掉函数对应的变量的值,

实现返回多个返回值的效果

8.为什么指针要分类型

1>指针变量是一个变量,既然是一个变量,肯定会在内存之中申请字节空间,

无论是什么类型的指针变量,在内存之中都是占据8个字节

无论是什么类型的指针变量,存储的都是变量的地址

2>通过指针变量的值可以找到变量的低字节的地址

那么在操作这个变量的时候,是操作多少个字节的呢?

是根据指针的类型来决定的:int*就从这个字节开始操作4个字节char操作1个字节...

3>所以一个指针变量只能存储和指针类型相同的变量的地址

否则会出错

四.二级指针

1.一级指针:如果一个指针变量中存储的是一个普通变量的地址,那么这样的指针就叫一级指针

2.二级指针:如果一个指针变量中存储的是一个一级指针的地址,那么这样的指针就叫二级指针

3.二级指针的声明

数据类型**指针名;

4.二级指针的初始化

1>二级指针是用来存储一级指针变量的地址,并且要求一级指针的类型和二级指针一样

intnum =10;

int*p1 = #

int**p2 = &p1;

num//num的值10

*p1//num的值10

&num//num的地址

p1//num的地址

*p2//num的地址

2> *指针名:拿到的是这个指针指向的变量的值

**指针名:要求这个指针至少要是二级指针以上

拿到是这个指针所指向的指针所指向的变量

五多级指针

intnum =12;

int*p1 = #

int**P2 = &p1;

int***p3 = &p2;

*p1 = num

*p2 = p1

**p2 = *(*p2) = *p1 = num

***p3 = *(*(*p3)) = *(*p2)= *p1 = num

六指针与整数的加减法

1.指针可以和整数进行加减运算

2.所代表的意义

+1不是指的一个字节,而是指的是这个指针类型的普通变量在内存中占用多少个字节(int*p; p+1加多4个字节)

3.注意

加的这个数,并不是直接加这么多字节

而是加这个数*指针类型所占的字节数

七指针与数组

1.数组的地址的问题

a.数组名==数组的地址==数组的第0个元素的地址==数组的第0个元素的低字节的地址

注意:数组名是个常量不能改变

当一个数组在内存中创建完毕,数组的地址是无法改变的array++会报错

2.当函数的参数是一个一维数组的时候

声明这个函数的参数的时候,只会创建一个存储数组地址的指针变量

voidtest(intarray[]){}——>可以写成voidtest(int*array){}

八指针数组

1.存储多个指针的数组.

2.指针数的声明

数据类型*数组名[长度];

int*ps[4];//只能存储int指针类型的数组

ps[0] = &num1;

================================

第十二天

一.指针与指针间减法运算

1.指针与指针之间是可以做减法运算的

结果是整型的,long类型的

结果的意义:代表这2个指针之间相差多少个单位变量

两个指针都是int类型结果就是这2个指针之间相差多少个int变量

2.原理:拿到2个指针之间相差的字节数除以每一个普通变量占用的字节数

3.应用场景:

有2个指针变量,都指向一个数组中的2个元素

我们想知道这2个元素之间相差多少个元素

4.一般情况下,指针的减法只在数组的元素之中发生,这样才会有意义

5.指针与指针之间只能做减法运算

参与减法运算的指针的类型必须是相同的

二指针间的关系运算

//判断的是指针变量的值

> >= < <= == !=

1.判断的是指针与指针的关系

判断2个指针谁在高字节,谁在低字节

==可以判断2个指针是否指向同一个变量

三指针与字符串

1.指针与字符变量

charch = ‘a’

char*p1 = &ch;

*p1 = ‘b’;

2.指针与字符数组

charchs[] = {‘j’,’a’,’c’,’k’};//字符数组,不是字符串

char*p1 = chs;//p1指针指向了chs数组中的第0个元素

3.字符串在C语言中的存储方式

1>.字符串数据是以字符数组的形式存储在字符数组中的

字符串的每一个字符存储在字符数组中,以’\0'作为结束符

charstr[] = “love”;//本质,将字符数据的每一个字符存储在数组中,自动追加’\0’

4.内存的分区

1>栈空间:(存储所有的局部变量)

2>堆空间:(可以由程序员手动的在堆区申请字节空间来使用,可以申请任意个数的空间)

3>BSS段:存储未被初始化的全局变量,静态变量,全局变量虽然有默认值,但是在初始化之前,这个变量是存储在BSS段

4>数据段(常量区):存储已经被初始化的全局变量,静态变量,常量数据,字符串常量数据

5>代码段:执行一个程序,会将这个程序加载到内存,一个程序中其实就是代码

这个程序的代码存储在代码区域

5.字符数组存储字符串和字符指针存储字符串的区别

1>当他们都是局部变量的时候

charstr[] ="love";

这种方式是以字符数组的形式存储字符串数据的

会在栈内存之中创建一个长度为5的字符数组讲字符串中的每一个字符存储进去

char*str ="hate";

首先str指针是一个局部变量,所以这个指针声明在栈空间之中

"hate"这个字符串是以字符数组的形式存储在常量区之中的

str指针之中存储的是常量区中的字符数组的地址

2>当他们都是全局变量的时候

charname[] ="Jack";

这个时候,name字符数组是创建在常量区的

char*name ="Rose"

name指针存储在常量区,Rose字符串也是在常量区

3>以字符数组存储的字符串可以通过下标或者指针去修改存储在数组中的每一个元素的值

字符指针存储在常量去的字符串数据是无法更改的

charname[] = “jack”;

name[0] = ‘r’;//这样是可以的

char

存储在常量区的字符串只能读不能修改,只能读

6.几个注意点

1>只有声明字符指针的同事为这个字符指针初始化一个字符串数据的时候

这个字符串才会存储在常量区

7.存储在常量区的字符串的恒定性

大前提:存储在常量区的字符串

1>.存储在常量区的字符串的每一个字符是无法改变的,一旦参加就无法更改

char*name ="Jack"

"jack"字符串是存储在常量区的,那么指针存储的是Jack的地址

2>我们说的不可更改指的是存储在常量区的字符串不可更改

但是指针的指向是可以改变的

char*name ="jack";

name ="rose”;

3>当系统准备要在常量区中创建一个字符数组来存储字符串数据的时候,

会先检查常量区是否有一个数组存储了相同的字符串函数

如果有直接将这个数组的地址返回,如果没有才创建并返回地址

8.说明

char*name ="jack";//jack存储在常见区,将j的地址赋值给name指针

name ="Rose";//将Rose存储在常量区,将r的地址赋值给name指针

chararr[] ="rose";

arr[0] ='j';

arr ="jack";//错误的因为arr的是个地址,数组的地址当数组初始化以后就确定了,是不可以改变的

9.中括号[]的本质:

1>所有的指针名后面都可以写一个中括号,其中写一个整数

2>指针名[n] == *(指针名+n)

3>数组名就是一个地址,地址就是指针

4>只有指针名才可以跟中括号

四字符指针数组

//保存多个字符串数据

char*names[] = {

“jack”;

“rose”;

“lucy”;

};

首先,names是一个数组,一个一维数组,元素是char*类型的

每一个字符串数据是存储在常量区的

数组的元素之中存储的是字符串常量的地址

五字符串函数补充

1.fputs()函数. f->file

1>作用:可以将字符串输出到指定的流之中,可以输出到标准输出流(控制台).也可以输出到文交流中

2>语法:fputs(字符串,输出流);

3>关于输出流:stdout,代表标准输出流,也就是我们的控制台

4>使用fputs()函数将字符串保存到磁盘上的文件之中

a.需要一个指针,指向磁盘上的文件,FILE *

b.通过这个指针,就可以找到磁盘上的文件,操作这个文件

c.操作完毕之后,释放这个指针

FILE *pFile = fopen("路径","w");//w代表write

char*str ="字符串";

fputs(str,pFile);

fclose(pFile);

5>关于文件流:

1) fopen()函数可以返回指定的文件的指针

有2个参数:

第一个参数是文件路径

第二个参数是操作文件的模式:

w->write写入数据到这个文件;

r->read从这个文件中读取数据;

a->append追加,在文件的末尾追加数据

使用w的时候:如果文件不存在,则创建写入

如果文件存在,先删除之前的,在创建,最后写入

使用a的时候,如果文件存在,则会在文件的末尾追踪内容

2)使用完毕之后,千万记得调用fclose函数关闭这个文件

2.fgets()函数f->file

1>作用:从指定的流之中读取数据.这个流可以是标准输入流(控制台),也可以是文件流

2>语法:fgets(存储读取进来的字符串数据的字符数组名,要读取多少个长度的字符串数据,指定流);

3>参数解释:

第一个参数:将读取出来的字符串数据存储到哪一个字符数组中

第二个参数:最多读取多少个长度的字符串

第三个参数:指定输入流,stdin代表标准输入流,也就是控制台

4>与scanf和gets函数的比较

a.当他们都输入字符串的时候

scanf输入空额的时候,会被认为结束,并且如果输入的数据过多,没有地方放'\0'

gets函数虽然可以接受空格,但是同样的如果输入的字符串的长度超过了数组的长度-1无法存储'\0'

5>fgets()函数特点

比如第二个参数我们写的是N,那么这个函数最多只会接收用户输入的N-1个字符,最后一个会自动添加'\0'

6>注意的问题:当流是标准输入流的时候

a.第二个参数要和数组的长度保持一致

b.如果输入的字符串长度大于等于了第二个参数,只会存储前面的N-1个字符,最后一个自动追加\0

c.如果刚好输入的长度是N-1,

d.如果用户输入的字符串长度小于N-1,那么这个时候会连用户输入的回车也会当作字符串内容一起接受

输入的字符串后的字符是一个'\n',然后才是'\0'

这个时候,这个换行符号'\n'是肯定不想要的,我们要想办法去掉

判断最后一个字符是否是'\n',如果是将其替换成'\0'

7>使用fgets函数从文件刘之中读取字符串数据

步骤

a.首先要创建一个文件指针指向要读取的文件

b.通过这个文交流读取字符串数据

c.关闭文件流

FILE *pFile = fopen("路径","r");

charstr[100];

fgets(str,100,pFile);

printf(“%s”,str);

fclose(pFile);

六const

1.const是C语言提供的一个关键字.

在声明变量的同事,来修饰这个变量

被const修饰的变量在某种程度上这个变量具备不可更改性

2.const修饰基本数据类型

基本数据类型:intdoublefloatchar

的时候,这些基本数据类型的变量具备不可更改性

可以将const写在数据类型之前:constintnum =10;

也可以将const写在数据类型之后:intconstnum =20;

效果一致,不能为这个变量重新赋值

3.const还可以修饰数组

1>constintarray[3] = {10,20,30};

代表数组中的元素的值是无法更改的

2>intconstarray[3] = {10,20,30};

效果同上,数组中的元素的值是无法改的

特别强调,无论如何数组名的值是改变不了的

4.const还可以修饰指针

intnum =12;

1>constint*p1 = #

无法通过p1去修改p1指向的变量的值;//*p1 = 200;报错

但是p1指针变量的值是可以改变的;//p1 = &num1;正确

2>intconst*p1 = &num

效果同上

3>int*constp1 = #

可以通过p1去修改p1指向的变量的值;

但是无法更改p1指针变量的值

4>intconst*constp1 = #

无法通过p1指针去修改p1指针指向的变量的值

也无法修改p1指针变量的值

5.然后,这有什么用?

1>.const的作用:让变量具备不可更改性

2>使用场景之一:

如果在程序运行期间,有一个数据的值是死的,不会发生变化,并且这个值在多个地方需要使用,那么这个时候可以用const

使用场景之二:

当指针作为函数的参数的时候,这个时候函数的内容是可以通过指针来改掉调用者的值的

有的时候,调用者不希望函数的内部通过指针修改调用者的变量,并且函数也想告诉调用者

只会通过指针使用你的变量的值,而不会修改,那么这个时候,可以在指针参数前面加个const

voidprintArray(constint*array,intlength){

//函数内容只能读数组array里面的值,没办法修改array里面的值

}

七C语言的内存管理

1.内存主要分为五大区域

栈空间:存储局部变量

堆空间:

BSS段:存储未初始化的全局变量,静态变量

数据段(常量区):存储已经初始化的全局变量,静态变量,常量数据,字符串常量数据

代码段:存储程序的代码

2.内存中有一个孤独的地方叫堆空间

1>堆空间的作用

a.允许程序员申请任意个字节数的空间来使用,在堆中

b.申请在堆之中的字节空间,除非程序员主动释放,程序结束,否则申请的空间不会被释放

3.在堆之中申请字节空间的相关函数

malloc()函数

calloc()函数

realloc()函数

free()函数

这几个函数的声明是放在stdlib.h的系统头文件之中的

4.malloc()函数

1>.作用:在堆之中申请任何个字节数的空间,传人一个字节数就可以了

malloc(4);//就会在堆之中申请4个字节的空间的

2>.malloc函数的返回值:返回的是第一个字节的地址

返回值的类型void*.代表一个没有类型的指针,也就是万能指针

3>我们应该使用哪一种类型的指针来存储这个函数的返回的地址呢?

语法上任意的指针类型都可以接收这个函数的返回值,返回的第一个字节的地址

到底使用哪个类型的指针?看你想如何去操作申请过来的字节空间

如果你想一个字节一个字节的操作使用char*,2个用short*,4个用int*

4>malloc在向堆申请字节空间的时候,有可能会失败的

如果申请失败,返回的指针是NULL

一般情况下,我们使用malloc函数申请字节空间后,先判断在使用

int*p = malloc(8)

if(p !=NULL){

//代表申请成功

}

5>注意:当你申请的这块空间不在使用时候,记得释放

调用free()函数释放空间

free(p);

6>使用malloc函数在堆申请字节空间时候

a.从低字节向高字节分配

b.每次申请字节空间的时候,地址都会从0重新开始

所以这个时候第一次申请的字节空间和第二次申请的字节空间并不是连在一起的

但是,我们每次申请的指定字节数的空间一定是连在一起的

我们可以使用,malloc函数在对中创建一个不会被回收的数据了

5.calloc()函数

1>作用:在堆中申请指定字节数的空间来使用

2>语法:calloc(m个数,n字节数);//申请了m个有n个字节的空间

3>与malloc函数的区别

int*p1 = malloc(4);

*p1 =100;

free(p1);

int*p2 = malloc(4);//这个时候p2的地址里面会是p1留下的垃圾值

a.malloc函数申请到的字节空间中是有可能会包含垃圾值的

b.calloc函数在申请字节空间的时候,会先将申请到的字节空间的数据清零

6.realloc()函数

1>作用:对已经神奇的字节空间增大容量

2>语法:realloc(已经存在的空间的指针,想扩容到多少个字节);

int*p1 = calloc(2,sizeof(int));//申请8个字节的空间

int*p2 = realloc(p1,16);//将p1扩容到16个字节

3>原理:如果原来的字节空间后面有足够的空间扩容,那么就直接在原来空间的屁股后面扩容

如果原来的字节空间后面的空间不够,会重新开辟一块新的内存空间,

然后把之前申请的空间的数据拷贝过来,再将原来的内存空间释放掉

八推箱子

九字符串数组

1.使用char指针数组

2.使用二维字符数组

================================

第十三天

一指针与函数

1.指针作为函数的参数

在函数内部可以通过指针形参去修改调用者的值

当函数需要向调用者返回多个数据的时候

注意:指针变量中不能存储常量的地址

当指针作为函数参数的时候,调用者不希望你改变变量的值,

函数也循环告诉调用者不修改变量的值,参数可以加const

2.指针作为函数的返回值

1>指针是可以作为函数的返回值的

在返回的时候,不能返回局部变量的指针

因为当函数执行完毕之后,局部变量就被回收掉了.指针就指向了一块被释放的空间

这样使用话,就会出问题

int*test(){

intnum =100;

return#

}

虽然能返回变量的地址,但是该变量在函数结束后会被回收

2>如果我们真的要返回一个指针

就必须包装函数执行完后,这个指针指向的变量仍然存储在内容中,不被回收

这样调用者调用完函数后,还可以使用这个数据

3>如果函数需要返回一个字符串,那么返回值应该是char*

并且字符串数据不要存储在字符数组之中,要让其使用字符指针的形式存储

二指向函数的指针

1.在内存中有一块空间是用来存储一个一个的函数的

每一个函数占用一块空间来存储

这样我们调用这个函数的时候,就可以直接使用函数名来调用

也可以使用这个指针来间接调用

2.如何定义一个指向函数的指针

语法:返回值类型(*指针名)([参数列表]);

eg.void(*pFunction)();

声明了一个指针这个指针的名字叫做pFunction.这个指针只能存储函数的地址

虽然这个指针是用来存储函数的地址的,但是并不是任意的函数的地址都可以存储

只能存储和指针签名相同(返回值,参数列表)的函数的地址

3.指针的初始化

a.1个指向函数的指针只能指向和指针签名相同的函数

声明一个指向指定函数的指针:

将函数头拷贝,删除函数名使用一对小括号里面写*再写一个指针名

b.赋值的原理

1>取到符合条件的函数的地址

函数名就代表函数的地址,所以可以直接将一个符合条件的函数名,直接赋值给一个指针变量

2>将函数的地址赋值给指针变量

void(*pFounction)() = test;

这个时候,pFunction指针指向了test函数

3>注意,在初始化的时候,是把函数名赋值给指针

函数名(),这是调用函数,表示的是把函数的返回值赋值给了指针.这样是错误的

4.通过指针间接的调用指向的函数

1>直接使用指针名调用就可以了

pFunc();

2>也可以使用*来调用

(*pFunc)();

三指向函数的指针的应用场景

1.指向函数的指针

本质上是一个变量,那么我们就可以声明,赋值,赋值给另外一个类型相同的指针变量

四结构体

1.语法

struct类型名{

数据类型1成员名1;

数据类型2成员名2;

......

};

structStudent{

char*name;

intage;

};

代表定义一个新的类型,这个类型的名字叫做structStudent

大括号中声明了一个一个变量,表示这个新类型的变量是由这些小变量联合而成

定义在大括号之中的变量,叫做这个新类型的成员

2.作用:

允许我们新创建一个数据类型,指定这个类型的变量有哪些不同类型的小变量组合而成的

3.结构体变量的声明

1>struct这只是声明了一个类型,并没有定义变量

2>去内存中创建一个我们自定义的类型的变量,参加一个结构体类型的变量

语法:struct结构体名称变量名;

注意:struct不能省略

structStuent stu;

代表声明了一个变量stu.变量stu的类型是structStudent

这个stu变量,是由结构体中定义的小变量组成的

4.结构体变量的初始化

通过点语法为结构体中的小变量赋值

stu.name="jack";

stu.age =18;

5.什么时候需要使用结构体

当某个数据无法使用一个普通变量来存储,而是需要多个不同类型的变量联合起来才可以描述

这个时候就可以使用结构体来定义一个新的的类型

6.结构体只是定义了类型,并没有创建变量

使用时候需要先定义类型,然后再创建对象

7.注意点

1>一定要先定义结构体类型,才可以根据这个类型创建这个结构体变量

2>结构体变量本质上也是一个变量,所以可以批量的声明结构体变量

3>定义结构体的时候,结构体的名称要求首字母大写

4>在声明结构体类型的同时,就定义结构体变量

structCar{

intwheels;

char*brand;

char*color;

} bmw,benz;

5>匿名结构体,这个结构体类型没有名字.

//只能在声明类型的时候,定义变量

//使用一次后就没办法在使用来定义变量

struct{

char*name;

intage;

} stu;

8.结构体变量的其他初始化方法

1>先声明变量,在用点语法一个一个赋值

2>在声明变量的同时,使用大括号为变量的所有成员赋值

Struct Car bwm = {4,"宝马","红色"};

3>声明变量的同时,按照顺序为部分成员赋值

Struct Car BYD = {4,"比亚迪"};

4>声明变量的同时,指定成员初始化

Struct Car benz = {.brand="奔驰"};

当声明一个结构体变量的时候,如果没有为结构体变量的成员赋值

那么它的成员的值是垃圾值

如果在声明的同时,初始化了部分成员,其他成员会自动初始化为0

五结构体的高级使用

1.相同类型的结构体变量之间,是可以相互赋值的

结构体变量名,直接代表整个结构体

structStudent stu1 = {"kevin",18,100};

structStudent stu2 = stu1;

stu2.name="Jack";

除数组,指针,函数名代表的是地址位,其他变量名代表它本身

2.结构体类型的作用域

如果把姐哦固体类型声明在函数内部,那么就只能在这个函数内部去声明结构体

如果把结构体类型声明在最上面,在该文件中都可以用

3.结构体数组

a.结构体数组的声明

struct结构体类型名数组名[长度];

structStudent students[5];

声明了一个长度为5的structStudent类型是数组

b.声明时初始化

structStudent students[3] = {

{"kevin",18,100},

{"jack",20,90},

{"rose",19,98}

}

c.先声明后初始化

structStudent stuents[3];

//前面要加强制类型转换,不然会报错,因为数组的赋值也可以用大括号

//如果不加类型转换,xcode不知道后面到底是数组还是结构体

stuents[0] = (structStudent){"tom",19,100};

4.结构体的长度

结构体长度:sizeof(students)

结构体一个元素的长度:sizeof(structStudent)

元素个数:sizeof(students) /sizeof(structStudent)

六结构体与指针

1.结构体变量首先是一个变量,那么在内存之中就有地址

2.如何声明一个指向结构体变量的指针

struct结构体类型名*指针名;

structStudent *p;

表示声明了一个指针p,用来存储structStudent类型的变量的地址

结构体指针:仍然是只能指向限定内型的结构体变量

3.初始化

取出符合限定的结构体比阿里的地址,然后将地址赋值给指针

如果要取出结构体变量的地址,要使用取地址运算符

structStudent *p = &stu;

4.使用结构体指针

使用结构体指针间接的操作指针指向的结构体变量

1>使用*来操作

(*指针名).成员=数据;

2>指针名->成员=数据;

(*p).name ="jack";//.的运算符优先级高于*,所以要给*p加小括号

p -> name ="rose";

七结构体的嵌套

1.在为一个结构体写成员的时候,

发现某个成员需要多个小变量联合起来使用,

就把这个成员定义成一个结构体

structDate{

intyear;

intmonth;

intday;

};

structPerson{:

char*name;

intage;

structDate birthday;

}

2.初始化

structPerson stu = {"rose",18.{2004,9,10}};

structPerson stu1 = {"jack",18,2002,6,6};

八结构体与函数

1.结构体可以作为函数的参数

结构体作为参数传的时候,是值传递,在函数内部修改结构体形参的值不会影响实参

2.如果要想在函数内部改变形参的值,影响实参的值

需要传递指针,也就是结构体的地址

3.关于返回值

可以直接返回变量的值,无论是全局的还是局部的都是可以返回的

不能返回的是局部变量的指针

============================

C语言第十四天

一枚举

1.作用

一种数据类型,他的取值只能描述我们规定的几个值里面的一种

2.语法

enum枚举名{

枚举值1,

枚举值2,

......

};

枚举是我们自定义的一个数据类型,这个数据类型的名字:enum枚举名

3.声明枚举变量

枚举数据类型变量名;

enumsexType{

sexTypeMan,

sexTypeWoman

};

enumsexType sex;

4.枚举变量初始化

一定要注意的地方:只能取枚举项中的某一个

sex = sexTypeMan;

5.使用注意点:

1>枚举的作用域:如果定义在外部的从定义的那行开始到结尾

如果是在函数内部的枚举,就只能在函数内部使用

2>每一个枚举项对应的是一个整形的数的

3>C语言中没有一个格式符是用来输出枚举的,只能输出枚举项对应的整形数

4>声明一个枚举变量的时候,这个变量里面实际存储的是这个枚举项对应的整形数

虽然他存储的是变量对应的整形数,但是我们在赋值的时候推荐使用枚举项,这样一目了然

5>我们声明一个枚举,写枚举项的时候,最好加上枚举名,这样方便别人在调用的时候好写枚举项

6.应用

structPerson{

char*name;

intage;

enumsexType sex;

};

structPerson person = {"kevin",18,sexTypeMan};

二typedef

补充请看//http://www.cnblogs.com/afarmer/archive/2011/05/05/2038201.html

1.作用

就是给我们的变量类型,取一个你觉得容易记忆的名字

2.语法

typedef数据类型更改成的名称

3.应用

//声明结构体

structPerson{

char*name;

intage;

};

//取别名

typedefstructPerson Person;

//用别名定义变量

Person person;

//声明结构体的时候取别名

typedefstructPerson{

char*name ;

intage;

} Person;

//声明枚举的时候取别名

typedefenumSex{

sexTypeMan,

sexTypeWoman

}sexType;

4.可以在声明匿名结构体的时候,用typedef取别名

typedefstruct{

intyear;

intmonth;

intday;

}Day;

5.typedef给数组重定义

typedefintnumber[3];//定义一个三个int类型的数组

number num1 = {10,20,30};//定义一个number类型的变量num1;

6.注意

1>typedef并不创建新的类型。它仅仅为现有类型添加一个同义字。

2>typedef是在程序编译的时候执行的

三预处理指令

1.预处理指令-预编译指令

1>#开头没有分号

2>执行时机:程序在编译之前

2.预处理指令有哪些

1>宏的定义

a.在程序编译之前就会把使用宏的地方,替换成宏值

b.语法

#define宏名宏值

2>宏的使用

直接使用宏名,编译之前把使用宏名的地方替换成宏值就可以了

3>使用注意

a.宏值可以是任意的东西,

b.宏值可以是一个表达式,宏值并不是这个表达式的值,而是整个表达式

如果你确定要这个表达式的结果作为宏值,需要使用小括号把表达式括起来

c.宏值当中如果有变量,那么使用这个宏值之前就应该声明这个变量

d.如果双引号中出现了宏名,其实这不是宏名,只是一个和宏名一样的字符串

e.如果你在写宏值的时候,带入了一个分号,那么这个分号是宏值的一部分

f.定义一个宏名,他的宏值中可以四另外定义的宏名

3.宏替换,是本色替换

4.宏的作用域

宏定义从他定义的那一行开始,到函数的结尾.

因为宏是在编译之前进行本色替换.只要在使用之前有定义就可以.

5.#undef宏名

取消宏定义,前提是在#undef之前有定义这个宏.

在取消宏定义以后,定义的这个宏名将不在起作用

6.有参宏定义

1>使用宏的时候,需要调用宏的人传人一个值作为宏值

语法:

#define宏名(参数)宏值(参数)

#define Log(str) printf(str)

#define SUM(a,b) (a+b)

intnum1 =10;

intnum2 =20;

intnum3 = SUM(num1,num2);//在宏替换的时候,传参过去传的是num1,num2

//预编译成: int num3 = num1 + num2;给num1和num2赋值是在程序运行才执行的

2>宏不是函数,参数传递的时候,不需要类型

四条件编译

1.第一种情况:

//判断值所在的范围

#define Score48

intmain(){

#if Score>=90

printf("");

#elif Score>=70

printf("");

#else

printf("");

#endif

}

.注意点

1>条件编译一定要使用宏,而不能使用变量

2>endif不能省略,它表示这个条件编译结束

3>如果不是条件编译,是普通的一个流程控制,那么会把所有的分支都编译成二进制代码

如果是条件编译,只会把符合条件的那一个分支编译成二进制代码

4>写在函数内部

2.第二种情况

//判断某个宏有没有定义

#define Score60

#ifdef Score

printf("");

#else

printf("");

#endif

3.第三种情况

//判断宏没有被定义

#define Score60

#ifndef Score

printf("");

#else

printf("")

#endif

4.实际应用

#define ITCAST_DEBUG1

#if ITCAST_DEBUG ==0

#define Log(str) printf(str)

#else

#define Log(str)

#endif

5.条件编译,防止文件多次包含

#ifndef宏名

#define宏名

#include"abc.h"

voidtest();

#endif

五static和extern

voidtest(){

intnum =10;//static int num = 10;

//被static修饰的局部变量会被放在常量区,只有一份,不会被回收.除非程序结束

num ++;

printf("%d\n",num);

}

intmain(){

for(inti=0;i<5;i++){

test();//打印出来的值全部都是11;因为每次test函数调用完,num都会被回收

//每次都要重新创建num变量,所以每次都是10进行++

}

}

1局部变量

被static修饰的局部变量会被放在常量区,只有一份,不会被回收.除非程序结束

局部变量不能被extern修饰

2.全局变量

1>被static修饰的全局变量,只能在当前模块中使用,不能在别的模块中使用

2>被extern修饰的全局变量,能在当前跟别的模块中使用

3>注意:在Xcode6.3之前默认是extern,可以省略不写,

但是在xcode6.3extern不能省略

在.h文件中声明一个全局变量的时候如果想让外部使用

externintnum;

在.m文件中使用

intnum =10;

3.函数

如果一个函数被static修饰只能在当前文件中使用

如果一个函数被extern修饰就能在其他文件中使用,默认是extern的

六数据类型分类

1>基本数据类型intcharfloatdouble

2>构造类型数组枚举结构体

3>指针

4>空类型void

5>自定义类型typedef

七补充

1.如果if后面只有一条语句,那么这个大括号是可以省略的

日记本
Web note ad 1