c语言知识总结

1、关键字

关键字:在规范C语言时,用于表示一定的特殊含义的字符,只要在C程序中使用,就代表了一定的操作和含义,约定的具有特定功能的单词或字符

auto、double、int、struct、break、else、long、switch、case、enum、register、typedef、char、extern、return、union、const、float、short、unsigned、continue、for、signed、void、default、goto、sizeof、volatile、do、if、while、static

auto:默认类型,通常可以省略,表示定义在栈区,由系统进行管理

double:双精度实

int:整型

struct:结构体类型

break:break语句作用是结束当前这个循环,跳出当前循环

if-else:选择语句

switch-case:选择语句

enum:枚举类型

register:寄存器类型,存储到cpu中(通常等同于 auto)

typedef:用于自定义数据类型的一个别名,或者称之为 “定义了一种新的数据类型”。可以有效简化定义一个复杂数据类型的代码实现。

char:字符型

extern:外部类型

return:返回值

union:共用体类型

const:在定义变量时,使用const关键字修饰,变量不可修改,作用类似于常量

float:单精度实型

short:一种整型变量家族的一种

unsigned int:无符号整型

continue:提前结束循环中的本次循环,跳过本次循环体没有执行完的内容,直接进行下一次

for:循环语句

signed int:有符号整型

void:无类型

default:与case等同,放在swich语句的最后

goto:无条件跳转语句

sizeof:sizeof 运算符,计算类型、变量或表达式的空间大小(字节数)

volatile:用于表示变量是易变的,告诉编译器不缓存该变量,也就是每次访问该变量都要去内存访问,不会访问该变量在缓存中的副本。

do-while:循环语句

static:静态类型

C语言程序中,我们所定义的名字不能和关键字重名(一样)

2、标识符

标识符:在当前程序中设定的一些字符符号表示,表示一定的意义,代表一个定义的作用(我们自己所定义的字符符号含义),自己命名的符号。

标识符的表示:

由字母数字和下划线构成,且只能以 字母或 下划线开始

A-Z  ,  a-z , 0-9 ,  _

合法标识符:

abc,a1,a2,o_k

非法标识符:

%abc,a$b,1a

3、数据类型

double:双精度实

int:整型

float:单精度实型

signed int:有符号整型

unsigned int:无符号整型

char:字符型

1、进制与转换

对于计算机而言,只认识 0 和 1

十进制表示:每位数据值范围:0、1、2、3、4、5、6、7、8、9

满10进1

二进制表示:每位数据值范围:0、1,计算机中存储数据以二进制存储

满2进1

八进制表示:每位数据值范围:0、1、2、3、4、5、6、7

满8进1

十六进制表示:每位数据值范围:0、1、2、3、4、5、6、7、8、9、A(10)、B(11)、C(12)、D(13)、E(14)、F(15)

满16进1

整数十进制转二进制:除以2取余数,把余数按照从低位到高位依次表示

二进制转十进制:二进制每一位的权 乘以 当前位的值  (权:以2为底数,以位数为指数幂)的累加和

二进制转十六进制/八进制(十六进制/八进制转二进制):把四位/三位 二进制转为一个十六进制位/八进制位,如果高位不够补0进行转换

10101010111====>16进制

0 101  0101  0111===> 5  5  7

10101010111====>8进制

010 101 010 111====>2 5 2 7

2、数的存储:

计算机以二进制方式(0、1)存储数据,但是数据中存在 正 负之分

有符号数:把数据中,最高位作为符号位,用0表示正数,用1表示负数

无符号数:数据中,所有位都是数据位,没有符号位,所有无符号数都是正数

计算机中存储数据是以  补码  格式存储

原码:数据的二进制格式

10:0   .....0000...   1010

-10:1   .....0000...   1010

反码:

正数:反码 == 原码

负数:在原码的基础上每一位(除了符号位)取反(1变为0,0变为1)

10:0   .....0000...   1010

-10:1   .....1111...   0101

补码:

正数:补码 == 原码

负数:在反码的基础上 + 1

10:0   .....0000...   1010

-10:1   .....1111...   0110

位:bit

一个单独的0或1 二进制----1bit

字节:byte

八位二进制---------1Byte    1B = 8bit

千字节:KByte---KB

一千个字节---------1KB       1KB = 1000B

3、基本数据类型

1、整型

整型:根据在计算机中设定的大小

short (int):短整型------16位二进制(16bit),2B

int:整型-------------32位(32bit),4B

long (int):长整型-------在32位系统大小为 32位(32bit),4B ;在64位系统大小为 64位(64bit),8B

long long (int):超长整型----64位(64bit),8B

2、浮点型(实型)

浮点型:设定类型大小

float:单精度浮点型---32位(32bit),4B,精度:6/7

符号位:1bit

阶码:8bit

尾数:23bit

double:双精度浮点型-----64位(64bit),8B,精度:15/16

符号位:1bit

阶码:11bit

尾数:52bit

3、字符型

对于字符型数据,在计算机中存储,依旧使用二进制 0 和 1表示

对于每个字符统一用一种标准的二进制来表示

字符存储:

存储的字符对应的ASCII码,ASCII码就是整数,以二进制存储

字符类型:

char:字符类型--------8位(8bit),1B

字符类型可以当做整数进行操作:char 可以表示为 只有8位的整数

4、变量与常量

常量:在整个程序中都不会进行改变的数据

变量:在整个程序中可以进行变化的数据,在内存中存储数据后,空间中的数据值可以进行改变,变量在使用的使用需要有一个名字(能够找到对应的变量);对于变量而言,必须先有(定义),才能使用

变量定义:存储类型     数据类型     变量名;

存储类型:

auto:默认类型

通常可以省略,表示定义在栈区,由系统进行管理

static:静态类型

register:寄存器类型,存储到cpu中(通常等同于 auto)

extern:外部类型

5、输入输出

1、输出

printf:由C语言标准所设计的输出功能,只要使用printf就可以实现输出

printf功能包含在 stdio.h中,所以要使用的话:#include

格式:printf("要输出打印的内容   格式化字符1,格式化字符2 ", 输出列表);

格式化字符:作用就是占位 表示要打印对应的数据值,以% 表示

输出列表:格式化字符要打印的数据

格式化字符:%

格式化字符输出指定的位数:

%m.p格式字符:m 数据的宽度,p小数的精度

在输出中,如果要输出某些特殊字符,在字符编码上没有对应的字符表示,在C语言中,设计转义字符:把普通字符转义为特殊字符,特殊字符转义为普通字符

转义字符: \

回车换行:\n

反斜线字符:\\

\:续行符

2、输入

scanf:输入功能,可以从键盘输入数据给变量

使用scanf 必须包含对应的头文件  #include

格式:

scanf("键盘输入匹配,格式化字符1,格式化字符2,",输入列表);

格式化字符:格式化字符位置匹配的内容输入到变量中

输入列表:列出要输入的变量

注意:如果是连续两个数值格式化字符,在键盘输入时需要隔开(空格、回车)

6、运算符

1、算数运算符

+:加法

-:减法

*:乘法

/:除法

%:取余

进行运算时,如果是同种类型数据进行运算,则结果为对应的类型

隐式类型转换:

在进行各种运算操作,如果是不同的数据类型,会把不同的数据类型转换为相同的数据类型然后再进行运算(原则:精度低往精度高的类型转换),原数据不变

强制类型转换:

把数据的值取出,然后指定转换为某种类型,原数据不变

语法格式:

(要转换的类型)数据

2、关系运算符

<        小于

>        大于

>=      大于等于

==      等于

!=      不等于

关系运算符是进行比较运算,判断关系是否成立(比较左右两边的表达式是否满足关系),比较结果:成立为真(值:1),不成立为假(值:0)

注意:在进行运算时,如果有连续的多个运算符,单一运算符进行运算之后得到结果再与下一个运算符进行运算

注意:

浮点数a 和 b 判断相等

a - b > -精度  &&  a - b  < 精度

3、逻辑运算符

连接表达式,根据表达式的真 假,进行组合得到新的结果,结果也是 真(值:1)  假(值:0)

逻辑运算表示两个数据或表达式之间的逻辑关系,逻辑运算的结果也只有两个:真为1和假为0。

&& (与):

表达式1  &&  表达式2

如果表达式1为真,且表达式2为真,逻辑与 结果 为真(值:1),否则 逻辑与 结果为假(只要有一个表达式为假,结果为假)(值:0)------判断,表达式1 和表达式2 是否同时成立为真

截断原则:当表达式1 已经为 假(0),不会运算 表达式2

|| (或):

表达式1 ||  表达式2

如果表达式1和表达式2 都为 假,逻辑或 结果为 假(值:0),否则 逻辑或为真(只有有一个表达式为真,结果为真)(值:1)-----判断,表达式1和表达式2 是否同时都不成立为假(是否存在表达式为真)

截断原则:当表达式1 已经为 真(1),不会运算 表达式2

! (非):

!表达式

改变表达式的真假结果,如表达式为假,逻辑非 结果为 真(值:1),如表达式为真,逻辑非 结果为 假(值:0)

4、位运算符

位运算对数据中的对应的二进制位进行运算操作(不会涉及到符号位说法)

&(位与)

表达式/数1  &  表达式/数2

把数1的二进制 与 数2的二进制,对应的每一位进行与运算操作(两个数对应的位有0,为0,都为1,则为1,位运算规则为:1 & 1 = 1       0 & 1 = 0       1 & 0 = 0      0 & 0 = 0)

|(位或)

表达式/数1  |  表达式/数2

将两个运算量的各个相应位分别进行“或”运算操作(两个数对应的位,有1,为1,都为0,则为0,运算规则为:1 | 1 = 1       0 | 1 = 1       1 | 0 = 1       0 | 0 = 0)

^(位异或)

表达式/数1  ^  表达式/数2

将两个运算量的各个相应位分别进行“异或”运算(两个数对应的位,相同为0,不同为1,运算规则为:1 ^ 1 = 0       0 ^ 1 = 1       1 ^ 0 = 1       0 ^ 0 = 0)

~(位取反)

~数

将一个数据中所有位都取其相反值,即1变0,0变1,运算规则为:      ~1  -->  0         ~0   -->   1

数据值

将一个数据所有二进制位向左移若干位,左边(高位)移出的部分舍去,右边(低位)自动补零

>>(按位右移)

数据值

将一个数据所有二进制位向右移若干位,右边(低位)移除的部分舍去,左边(高位)根据原最高位自动补值(原最高位为1:补1,元最高位为0,补0)

5、复合运算符

复合运算符:可以使用 = (赋值运算符)和 其他的运算符(算数运算符,位运算符)结合使用

+=、-=、*=、/=、%=、|= 、&=、^=

变量  +=  表达式======> 变量 = 变量 + (表达式)

6、其他运算符

1、自增自减运算符

++ 、 --

变量++:先取变量的值,进行其他运算,然后变量 +1 ,使用变量时,使用+1之前的值

变量;

变量 += 1;

++变量:先把变量+1,然后取变量的值,进行其他运算

变量 += 1;

变量;

变量--

--变量

前缀:先自增自减后再参与表达式运算。

后缀:先参与表达式运算,后自增自减。

2、条件运算符(三元运算符)

运算符----   ?  :

条件表达式:

表达式1 ? 表达式2 :  表达式3

表达式1为真,执行表达式2,把表达式2的结果作为整个条件表达式的结果

为假,执行表达式3,把表达式3的结果作为整个表达式的结果

3、逗号运算符

逗号运算符

表达式1,表达式2,…,表达式n

依次运算操作每个表达式,把最后一个表达式运算作为整个逗号运算符的结果

4、sizeof运算符

sizeof(数值/类型):作用 计算数据 对应类型的大小,以字节表示

sizeof 运算符,计算类型、变量或表达式的空间大小(字节数)

sizeof(变量);

sizeof(表达式);

sizeof(类型);

7、选择结构

根据实际的当前情况条件,选择性执行/选择性不执行某些功能内容

1、if...else选择结构

1、单分支选择结构

根据条件,如果满足条件 则 执行对应的功能操作代码,执行完后,然后继续往下执行;否则跳过对应的功能代码,继续往下执行

if(条件表达式)

{

语句块;

}-----{}满足if选择的范围语句块,如果语句块只有 一条 语句,则{}可省略

条件表达式:只计算表达式的结果为 真(非0) 或 假(0)

如果满足条件则执行语句块,否则跳过语句块

2、双分支选择结构

满足条件表达式,执行一段语句功能内容,不满足则执行另一段功能内容;之后继续往下执行

if(表达式)

语句块1;

else

语句块2;

如果满足表达式,则执行语句块1,否则执行else 语句块2

3、多分支选择结构

if(表达式1)

语句块1;

else if(表达式2)

语句块2;

else if(表达式3)

语句块3;

……

[else

语句块n;]

多种情况选择性执行一种,判断第一种是否满足,满足则执行,不满足则判断下一种是否满足,满足则执行,不满足则继续判断.....

注意:if选择,只看真假,经过各种运算得到 0 或者 非0 都可以

2、switch...case选择结构

switch选择结构,根据表达式的结果表示从多种情况进行选择,选择情况(表达式 == 情况)进行执行对应的语句块

switch (表达式)

{

case 常量表达式1:语句块1;break;//每个case 就是一个情况

case 常量表达式2:语句块2;break;

case 常量表达式n:语句块n;break;

default: 默认情况语句段n+1;[break];

}

注意:表达式和常量表达式 结果为 整型(因为要判断相等)

比较 switch 表达式   是否 等于  case 常量表达式 ,如果相等 则执行对应的语句块

default 表示 如果 switch 和case 比较所有都不相等,则执行default 默认语句块

当switch 表达式和 case 表达式 比较相等后则执行对应的语句块,同时所有的case 表达式都失效(则会从当前case 一直往后执行,直到swicth结束)

break:表示结束当前switch

8、循环结构

重复多次执行某个功能

1、while循环

表达式为真,则执行一次要重复的内容(循环体语句),再次判断表达式是否真,表达式位置,则再次执行一次要重复的内容,继续判断表达式,直到表达式为假,则跳出循环执行while的后面内容

while (表达式)-------条件,是否重复执行

{

循环体语句;------要重复执行的内容

}

表达式的初始条件值

条件表达式

循环中包含改变条件值

2、do...while循环

do...while循环:先直接执行一次循环体,条件表达式从第二次开始判断是否满足,执行

语法结构:

do

{

循环体语句;

}

while (表达式);

while与do...while 区别:while从第一次条件开始判断,do...while 跳过第一次条件判断,从第二次判断开始;do...while最少执行一次

3、for循环

语法格式:

for (表达式1;表达式2;表达式3)

{

循环体语句;

}

表达式1:在整个for循环之前执行一次,且只执行一次,通常用于在for循环初始化条件的值(可以不进行设置,相当于没有初始化,可能在其他之前位置设置)

表达式2:循环条件,每次执行循环体前,先判断条件是否成立(判断一次,执行一次循环体)(可以不设置,相当于 条件一直为真 1)

表达式3:每次在执行一次循环体后,就立即执行(先于下次的条件判断),通常用于设置改变条件(可以不设置,相当于在表达式3中无操作)

表达式可以省略,但是 ; 必须添加

4、循环的嵌套

在循环内部循环体语句可能包含另一个循环,叫做循环的嵌套

while()

{

循环体

for()

{

}

}

外层循环执行一次,内层循环执行完一遍

5、break与continue

1、break

break:break语句作用是结束当前这个循环,跳出当前循环

while()

{

break;-------从当前位置结束整个循环

}

2、continue

continue:提前结束循环中的本次循环,跳过本次循环体没有执行完的内容,直接进行下一次

while循环使用continue直接结束本次循环体内容,直接进行下一次条件判断

for循环使用continue直接结束本次循环体内容,但是由于for循环在结束一次循环后,会执行表达式3,所以continue结束时,跳到表达式3执行,进行下一次条件判断

9、函数 

函数:就是一个独立的功能代码模块,在需要使用这个功能时,进行调用,就会去执行这个功能模块

库函数:由C语言标准实现的功能模块函数,编译器自带已经实现的函数

自定义函数:在程序中由于可能多次使用某个功能,自己实现这个功能模块函数,由用户对其进行定义,在其函数的定义中完成函数特定的功能,这样才能被其他函数调用

1、函数定义:

函数:包含两部分---函数头与函数体

函数头:

对函数的描述说明,表示某个函数----标记

3个部分:

返回值类型:函数功能结束,返回的结果是什么类型,表示有一个结果返回

函数名:标识符,表示这个功能的名字,之后就使用这个名字来标识使用这个功能函数

参数列表:在编写功能时不确定,需要在调用使用这个函数,传递的值

函数体:

功能模块的操作代码--功能的实现

定义:

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

{

函数体——函数实现特定功能的过程;

}

1、无参无返回值

void:空类型,没有数据类型

void 不能定义变量

void  函数名()

{

函数体;

}

2、无参有返回值

返回值数据类型  函数名()

{

函数体;

return 表达式值;

}

return:只要执行到return 语句,表示 函数功能到这里结束

return + 值:结束当前函数,同时把 值 返回,返回到调用位置(在调用位置得到函数的执行结果)

对于有返回值类型,在函数体中 必须包含 return + 值 语句

3、有参无返回值

void  函数名(参数列表):在编写函数功能时,存在不确定的一些数据值,使用参数列表来表示在定义函数功能时不确定;在使用时,根据参数列表情况,调用时传递参数列表实际的值

{

函数体;

}

参数列表:

数据类型1  变量名1,数据类型   变量名2,......

4、有参有返回值

返回值类型   函数名(参数类型1 参数名1,参数类型2 参数名2,...)

{

函数体;

return 值;

}

2、函数调用

在需要的位置使用这个函数功能,叫做函数调用

调用过程:

当调用时,跳转到对应函数位置进行执行函数功能,当函数执行完({}结束或return语句), 再跳转回调用位置,继续执行

1、无参无返回值调用

函数名()

调用无参函数,则没有参数列表,但小括号不能省略

2、无参有返回值调用

函数名()

调用有返回值函数,在调用位置就会得到函数返回结果

3、有参无返回值调用

函数名(参数的值1,参数值2,参数值3,......)

在调用时,参数值 需要和 函数定义的参数列表 一一对应

在调用时,会把参数值 赋值(传递)给  参数列表中的变量

注意:调用时,参数值 可能是变量,表示把变量的值传递给函数的参数列表,而不是把变量直接传递给参数列表

4、有参有返回值调用

函数名(参数值1,参数值2,参数值3,.....)

调用有返回值函数,在调用位置就会得到函数返回结果

定义有参函数时,给定的参数列表,在参数列表中的参数,叫做 形式参数(形参)

调用有参函数时,给定的参数值,叫做实际参数(实参)

3、函数的嵌套调用

在调用一个函数的过程中,被调用的函数又可以调用另一个函数

函数的定义是平行的、独立的,不允许嵌套定义

4、函数的声明

编译时提示函数是什么样子的函数(有无函数,函数有无返回值,有无形式参数列表)

如果在前面调用了函数,在后面位置才进行定义需要在调用前进行声明

函数声明 语法:

返回类型  函数名(形式参数列表);

写法:

返回类型 函数名(参数类型1,参数类型2,参数类型3....);

返回类型 函数名(参数类型1  参数名1,参数类型2  参数名2,参数类型3 参数名3....);

5、递归函数

函数中直接或间接调用自己这个函数,叫做函数的递归调用,当前函数也叫做递归函数

通常递归函数需要用结束条件,在函数内部加控制语句,只有当满足一定条件时,递归终止

10、全局变量与局部变量

1、局部变量

只要在函数内部定义的变量就叫做局部变量

函数的形式参数类似局部变量 ,与局部变量有相同的性质

性质:

生命周期:存储期限。变量的存储期限,在变量所在程序区块执行期间有效存储,区间结束或函数返回时,局部变量的值无法保留。

作用域:局部变量在定义所在的区域块内访问可达,离开区块不可访问。

程序块:用一对大括号{}括起来多条语句区域就是一个程序区块

2、全局变量

不在函数内定义的变量叫做全局变量

性质:

生命周期:存储期限。变量的存储期限,在整个程序运行期间都存在有效。

作用域:从变量被定义的点开始一直到所在文件的末尾都可以使用访问。

3、变量名的重名

在程序中,如果作用域相同则变量不能相同

在不同作用域时,允许定义相同的变量名,如果存在相同的变量则默认使用作用域小的变量进行操作

4、变量的默认值

当变量定义时,如果没有进行初始化时,变量的默认值:

局部变量:随机值

全局变量:默认初始化为0

5、static存储类型

static静态存储类型

static修饰局部变量:

延长生命周期为整个程序(程序结束变量的生命周期结束),但是作用域不变,只能在定义变量的作用域中使用(但作用域仍为局部)

当多次定义static 的局部变量时,只会定义第一次,之后都是跳过定义

static修饰全局变量:

设置为静态变量,只能在本文件内使用这个变量

static修饰的变量未初始化会自动初始化为0

11、数组

数组:由多个数据组成一个数据集合,在集合中存在多个数据内容,数组是包含有多个数据值的数据结构,并且每个数据值具有相同的数据类型

数组元素:数组这个集合中的一个数据

1、一维数组

1、一维数组的定义

定义:

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

类型:每个数据的类型

数组名:整个数据集合的名字

数组长度:数据集合中数据的个数

int   a[4];

占用内存空间:类型 * 数组长度

以连续的内存空间创建数组,每个数组元素是相邻的

2、一维数组元素的访问

存取特定的数组元素,通过数组名在后边加上一个用方括号表示整数值(整数值:数组取下标、索引:从0开始的编号位置)

格式:

数组名[下标]

下标:下标值只能是整数或结果为整数的表达式,取值范围是 0   ~   数组长度 - 1

注意:如果下标 >= 数组长度 叫做越界,不能使用

3、一维数组的初始化

在定义一维数组时,可以对数组进行初始化,对数组进行初始化就是对数组的元素进行初始化

使用一个 {},在 花括号中,添加要对数组元素初始化的值

格式:

类型  数组名[元素个数] = {值1,值2,值3};

完全初始化:

类型  数组名[元素个数] = {值1,值2,值3 == 元素个数};

对数组中每个元素都进行初始化赋值,会按照值的顺序依次对数组元素进行初始化

float price[5] = {1,2,3,4,5};

部分初始化:

类型  数组名[元素个数] = {值1,值2,值3 < 元素个数};

按照顺序 依次初始化 数组中前几个值,未初始化 会有编译器初始化为0

float price[5] = {1,2,3}

指定初始化:

类型  数组名[元素个数] = {[下标] = 值1,[下标] = 值2,[下标] = 值3};

float price[5] = {[0] = 1,[4] = 2,[2] = 3};

在进行初始化时,由于会编写元素值,可以使用值的个数来表示元素个数,在定义的位置元素个数可以不写

类型  数组名[] = {值1,值2,值3};----虽然不写,但是有值的个数个元素

2、二维数组

二维数组:一维数组的集合,集合中的数组元素是一维数组

例:二维数组有 5个一维数组元素,二维数组每个元素(一维数组)又包含8个数据

1、二维数组的定义

定义:

数据类型  数组名[常量表达式1][常量表达式2];

数据类型:一维数组的元素数据类型

常量表达式1:二维数组的元素个数(有几个一维数组)

常量表达式2:在二维数组中的一维数组的元素个数(一维数组中有几个元素数据)

当定义了二维数组,在内存中存储二维数组,是按照行顺序,即先存储第一行(二维数组第一个一维数组),在存储第二行(二维数组第二个一维数组)

2、二维数组的访问

数组名[二维数组下标]:二维数组中的某个一维数组

数组名[二维数组下标][一维数组下标]:二维数组中的一维数组的数据元素

3、二维数组初始化

把二维数组按顺序,从第零个一维数组依次进行初始化

数据类型  数组名[常量表达式1][常量表达式2] = {值1,值2,值3,....};

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

把二维数组,每个{}表示初始一个一维数组

数据类型  数组名[常量表达式1][常量表达式2] = {{值1,值2},{值3,.}...};

int a[2][4] = {{1,2},{5,6,7}};

对于二维数组初始化时可以不指定一维数组的个数

即:数据类型  数组名[][常量表达式2] = {};

int a[][3] = {1,2,3,4,5,6,7,8};-------有3个一维数组

12、指针

是直接访问内存的方式

内存地址:在内存空间中,对每一个字节都分配了一个唯一的编号,用于区别不同的位置。每个字节都有唯一的地址,用来和内存中的其他字节相区别

指针:在内存空间(定义变量)申请空间来存储地址,就叫做指针,也叫做指针变量

指针就是操作内存地址,使用内存地址

1、定义指针变量

指针变量:本质就是一个变量,存放的是一个内存地址

指针变量定义的形式:

指向数据类型 * 指针变量名;

指向数据类型:存储哪种类型数据的地址,指向哪种类型

指针变量:定义一个变量,用于存储地址,如果要存储哪种类型的地址,数据类型就是对应的类型

2、指针的使用

存储地址:

指针变量 = 地址(要求地址的空间能够使用)

变量的地址获取:通过 & 取地址运算符,得到变量的地址

指针变量 = &变量

指针变量访问内容:操作对应地址的数据,通过地址的方式访问数据

用变量名来表示代表变量中的值

用指针来访问变量:

*指针名 访问对应地址(指针存储的地址)的数据空间

int * p;

p = &a;

*p ; // ==== a 表示访问 p存储的地址(即a的地址),对应空间的空间

指针变量赋值地址:通过指针建立与对应内存空间联系

指针 取*:得到建立联系的内存空间的值

指针变量的初始化:

在定义指针变量时,进行赋值,就叫做初始化

类型 * 指针名 = 地址;

野指针:

指针记录的地址不明确(存储的地址不知道,或地址对应空间是否具有操作权限不确定),这种指针叫做野指针

野指针不需要直接进行 取 *

空指针:

指针记录的地址是NULL(地址:0x00),系统规定NULL地址不允许进行操作

只要操作就会报错

空指针通常表示,该指针当前不可用

万能指针:

void * 类型指针变量,可以存储任意类型的地址,也可以把指针赋值给其他的任意类型指针变量

void * 指针,指针存储地址,不能进行 取值操作(取 *),因为指向的类型未知不明确

3、指针的运算

指针 + / - 整数,表示移动指针 指向 的位置

+:

指针 + 整数n

往地址增大方向,移动 n 个 指向(指针指向,指针存储哪种地址)的数据类型 大小

int * p;

p + 5 ==== >移动 5 * 4

指针 + n == 指针 + n * sizeof(指向类型)

-:

指针 - 整数

往地址减小方向,移动指针指向类型(指针存储哪种类型地址)的大小 * 整数大小

指针 - 整数 * sizeof(指向类型)

指针++:

先使用指针,然后 指针 = 指针 + 1

++指针:

先 指针 = 指针 + 1 ,然后再使用指针

指针--,--指针

指针 - 指针:

获取两个指针之间间隔多少个对应类型的数据

(指针 - 指针) / sizeof(指向类型)

4、指针与一维数组

一维数组是一段连续的空间存储多个数据元素,在数组中相邻的元素,间隔大小为每个元素类型的大小,即 &数组名[元素i] == &数组名[元素i-1] + 类型大小

指针能够进行运算,指针 + 1,移动一个数据类型的大小,即 指针 + 1 == 指针 + 指向类型大小

如果指针变量存储了数组中的元素地址,指针+1 ,就是数组中下一个元素的地址

指针与数组的操作方式:

可以通过指针访问整个数组

只要知道数组的起始地址(第零个元素的地址),就可以遍历整个数组

数组首地址:数组的起始地址,就是第零个元素的地址

int * p = &a[0];

*(p+n) == a[n]

在数组中,数组名 有个特殊作用。数组名就表示 数组的首地址

数组名,地址常量

int a[5];

a == &a[0]

数组首地址(数组名) + n:偏移n个数据元素大小

*(数组名 + n) == 数组名[n]

*(a + 3) == a[3]

基于数组名(常量地址),可以将数组名当做指针进行使用,除了不能赋值运算(a = a+1)

因为数组名可以表示数组首地址,而指针变量也可以存储数组首地址,在访问数组的操作时,指针变量和数组名作用一致,所以

数组名[n]:访问数组的n元素 ==== 指针名[n]

int *p,a[5];

p = a;

p + n == a + n//等价

a[n] == *(p+n) == *(a+n) == p[n]

基于指针变量,可以将指针当做数组用,不能越界

字符串与字符数组

字符串:有多个字符组成一个连续且有序的字符序列

"abcdef"------字符串

C程序中,通过字符数组来存储字符串

字符数组通过访问数组中的元素,就是访问字符串(按照字符数组,每个元素单独访问)

如果需要整体访问字符数组中存储的字符串,要求在字符串结束的下一个字符位置存储'\0'

'\0'字符就表示 字符串的结束

字符数组存储字符串:

字符数组初始化存储字符串

char 数组名[大小] = "字符串";

注意通常,在进行输入前把数组初始化全为'\0'

输入字符串到字符数组中

scanf("%s",数组名/首地址);

输出打印字符数组中的字符串

printf("%s",数组名);

常量字符串表示:

"acbde"-----常量字符串

在常量字符串中,在最后字符后默认包含'\0'字符

在程序中如果写出常量字符串,则常量字符串表示常量字符串的首地址(第零个字符地址)

如:“abccde”,得到就是字符串的首地址,地址常量

地址,指针类型,都是统一的大小,各个类型之间没有区别

32位机器:4B

64位机器:8B

5、指针与二维数组

二维数组:二维数组中,每个元素是一个一维数组,在元素(一维数组)中,每个成员就是一个值

二维数组:

数据类型 数组名[行][列]

行:有多少个一维数组

列:一维数组的元素个数

对于二维数组而言,数组名是整个二维数组的首地址,第零个元素的地址,二维数组的元素都是一维数组,即二维数组数组名表示其中元素,整个一维数组的地址。

int a[3][4];

a == &a[0];//a[0]是整个一维数组

由于a表示整个元素的地址(一维数组的地址),所以进行指针运算时,+1 ,加上 整个一维数组大小

a:&a[0],第零个一维数组的地址

a+1:&a[1],第一个一维数组的地址

a+2:&a[2],第二个一维数组的地址

a[0]:表示二维数组的元素零,第零个一维数组,a[0]是一维数组的数组名,在这个一维数组的首地址

a[0] == &a[0][0]

a[0]+1 == &a[0][1]

a[1]:第一个一维数组,也是这个一维数组的数组名(首地址)

a[1] == &a[1][0]

a[1]+1 == &a[1][1]

注意:

a+1,表示移动二维数组的一个元素(一维数组)大小

a[0]+1,表示移动一维数组的一个元素(数据类型值)大小

数组指针:

是一个指针,指针用于存储整个数组的地址,指针的指向类型为数组

定义:

数组元素类型 (* 指针变量名)[大小];

int (*p)[4];//定义一个指针变量,指针变量存储 整个数组的地址(int [4])

数组指针和二维数组名是等价的,因为二维数组表示第零个元素(一维数组)的地址

int a[3][4];

int (*p)[4];

p = a;//&a[0]

p+1 == a+1 == &a[1]

*(p+1) == a[1]

*(p+1)+2 == &a[1][2]

*(*(p+1)+2) == a[1][2]

6、多级指针与指针数组

指针数组:

是一个数组,只是每个元素为指针类型

指向类型 * 指针数组名[元素个数];

int * p[5];

定义 包含 5个元素 每个元素为指针(int *)

int a;

p[2] = &a;

多级指针:

一级指针:存储变量的地址

二级指针:存储一级指针的地址:一级指针类型 * 指针名;

三级指针:存储二级指针的地址:二级指针类型 * 指针名;

......

指向类型 * 指针名;

int **p;

int * a[10];

p = a;

p+1 == a+1;

*(p+2) == a[2]

二级指针与指针数组名等价

7、指针与函数

指针作为函数的参数:可以表示变量的地址,或者是数组名/数组首地址,作用就是表示参数为地址

把地址作为参数进行传递

返回值类型 函数名 (指针参数1,指针参数2); 接受传递的是地址

调用:

函数名(地址,地址/指针);

如果是数组作为形式参数,会由编译器自动变为对应类型指针

int sumarray(int p[10],int length) p就是指针 int*

指针作为函数返回值:返回一个地址,把指针作为函数的结果返回

函数指针:指针存储是的函数的地址

函数的类型表示:

返回值类型 (参数1,参数2,参数3,......);

int (int a,char b);-1

int (int a,int b);-2

int (int c,int d);-3

1和2是不同函数类型,2和3是相同函数类型

函数指针表示:

返回值类型 (* 指针变量名)(参数1,参数2,参数3,......)

函数地址:

函数名就是用于表示函数的地址

函数指针 = 函数名;

调用函数:

通过函数指针进行调用

函数指针名(实参);

13、构造类型

由于基本数据类型不能满足需要,需要把多个的数据类型进行组合,共同表示新的复合数据,形成新的类型。构造新的数据类型的方式就叫做构造类型

1、结构体

使用多种数据类型作为成员,进行组合,构成的新的类型,就叫做结构体

声明结构体:结构体的类型表示

struct 结构体名字

{

类型1 成员1;

类型2 成员2;

类型3 成员3;

....

};

在程序中添加一种新的类型,不占用内存空间,只是说明在程序中有一中新类型

定义结构体变量:

struct 结构体名字 变量名;

对结构体变量的操作,就是对结构体变量的成员进行操作

结构体变量访问成员:

结构体变量名 . 成员名;

结构体变量初始化:

在定义结构体变量时,对其成员进行初始化

顺序对成员初始化:

struct 结构体名 变量名 = {成员1值,成员2值,成员3值,......};

指定成员初始化:

struct 结构体名 变量名 = { .成员名2 = 成员值,.成员名4 = 成员值,......};

结构体指针如何访问变量的成员:

结构体指针:

struct 结构体名 * 指针名 = 结构体地址;

访问方式:

指针->成员://访问结构体指针对应地址中的成员

(*指针).成员 == 指针->成员

结构体特殊的声明方式:

struct 结构体名字

{

类型1 成员1;

类型2 成员2;

类型3 成员3;

....

}结构体变量名;--------在声明时同时定义结构体变量

struct

{

类型1 成员1;

类型2 成员2;

类型3 成员3;

....

}结构体变量名;--------在声明时同时定义结构体变量,但是之后不能使用这个声明进行定义变量

2、共用体(联合体)

使用多种数据类型作为成员,进行组合,但是使用同一段空间存储(多个成员共用一个空间),构成的新的类型,就叫做共用体

使用共用体的问题:同一时刻只能操作一个成员

声明共用体类型:

union 共用体名

{

类型1 成员1;

类型2 成员2;

类型3 成员3;

....

};

用法:共用体与结构体一致

3、枚举

枚举就是定义一种新类型时,这个类型能够取值的范围是确定的,通过这个定义的新类型把能欧取值的范围一一列举出来,这种类型就叫做枚举

声明枚举类型:

enum 枚举名

{

成员1,

成员2,

成员3,

......

};

枚举类型中,每个成员就代表能够取的一个值

声明类型时,如果成员没有赋值,成员就等于上一个成员的值+1,如果成员1没有赋值则为0

定义枚举变量:

enum 枚举名 变量名;

变量名 = 成员;

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

(*~.@天蓝@.~*)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值