C语言基础

1、计算机的基本构成

输入输出设备(键盘、鼠标)

CPU处理器:(控制器,运算器,寄存器)

存储器

程序

存储器:内存和外存

内存:工作存储器,容量较小,运行速度快,掉电数据会丢失

外存:长期保存数据,容量较大,运行速度慢,掉电数据不会丢失

2、什么是程序

程序:计算机能够识别的一组有序的指令

指令:计算机能够识别的操作

3、程序的设计步骤

Vim(编辑)-------gcc(编译)------./a.out(运行/调试)

4、计算机的数据表示

非数值数据和数值数据

10 ------0000 1010

4.1 非数值数据

字符、图片、声音

‘a’  ‘A’

ASCII码表:规定了每一个字符以哪8位二进制数去表示

1字节= 8bit(位)

4.2 数值数据(进制转换)

其他进制转十进制:(注意:从右往左:从0次幂开始)

二进制转十进制:1010 0101 = 1*2^0+1*2^2+1*2^5+1*2^7

八进制转十进制:076=6*8^0 + 7*8^1 

十六进制转十进制:0xafc = 12*16^0+15*16^1+10*16^2

十进制转其他进制:

十进制转二进制:除2倒取余数

十进制转八进制:除8倒取余数

十进制转十六进制:除16倒取余数

二进制和八进制:(将每一个八进制数用三个bit的二进制数去表示)

二进制和十六进制:(每一个十六进制可以用4位二进制数去表示)(8421)

5、基本数据类型

关键字:系统预先定义好的,有特殊含义的,并且都是小写不能重新定义

一共有32个:

数据类型:char、short、int、long、float、double、enum、union、struct、void

控制语句:if、else、for、do、while、switch、case、default、break、continue、goto

存储类型:auto、static、extern、register

const:只读

return:返回函数

signed:有符号数

unsigned:无符号数

sizeof:计算所占内存空间的大小:单位:字节

typedef:给一个已有的数据类型起别名

volatile: 防止编译器优化

标识符:程序员自己定义的,一般用来定义变量名,函数名,类型名

命名规范:(见名知意)

  1. 由数字、字母、下划线组成
  2. 第一个不能为数字
  3. 不能和关键字重名

5.1基本数据类型

32os:分别占据多少个字节:

字符型:char(1字节)

整型:int(4字节)   short(2字节)   long(4字节)

浮点型:float(4字节)   double(8字节)

64os:

字符型:char(1字节)

整型:int(4字节)   short(2字节)   long(8字节)

浮点型:float(4字节)   double(8字节)

注意:每一种数据类型所占的内存空间是不相同的,数据类型主要就是为了让我们合理的分配内存空间

5.2 有符号数和无符号数

有符号数(signed):有正数有负数(定义一个变量,默认是有符号的)

所有的数据都以补码的形式保存在计算机中

符号位:最高位表示该数据为正数还是负数(0表示正数,1表示负数

  1. --------0000 1010

-10-------- 1000 1010

10+(-10) =  0

为了保证计算的正确性:计算机中保存数据时,以补码的形式保存数据的

正数:原码,反码,补码都是一样的

负数:

原码:直接转换为二进制,并且最高位表示符号位

反码:符号位不变,其他位取反(0变1,1变0)

补码:反码+1

无符号数(unsigned):只有正数,并且都是数据位

5.3 字符型家族

值域范围:

Char(1字节)

unsigned char:

0000 0000 ------ 1111 1111   (0 - 255)

signed char:

有符号数:最高位要用来表示:符号(0正,1负)

1000 0000------ 0111 1111   (-128~127)

考点!超过这个范围:转圈去数

5.4 整型家族

Int (4字节 ==  32bit)

unsigned int :

0000 0000 0000 0000 0000 0000 0000 0000 ------1111 1111 1111 1111 1111 1111 1111 1111

(0 ~ 2^32-1)

Signed int:

1000 0000 0000 0000 0000 0000 0000 0000 ----- 0111 1111 1111 1111 1111 1111 1111 1111

(-2^31 - 2^31-1)

5.5 浮点型家族

Float(单精度浮点数):表示6~7位有效数据

%f(默认输出小数点后6位)

Double(双精度浮点数):表示15~16位有效数据

%lf(默认输出小数点后6位)

6.常量

定义:在程序运行期间,不会也不能被改变的量

6.1字符常量

‘a’ ’A’  ‘b’

6.2整形常量

二进制:1010

八进制:076

十进制:99  -2

十六进制:0xaf   0X6FC

(默认情况下,为有符号数:int、short、long)

无符号的int:66U

长整型:66L

无符号的长整型:66UL

6.3浮点型常量

小数:3.14   10000(浮点型常量也包括整形常量)

指数:10000 = 1*10的4次方   1e+4   1e-4

%g:选择小数或者指数比较短的一种形式进行输出

6.4字符串常量

“hello”  “hi”

字符串以‘\0’结尾

6.5标识常量(宏)

宏只是一个单纯的替换!!!

:#define  宏名  表达式

注意:

1、宏名一般用大写表示,小写也可以,因为要和普通的变量区分开来,所以用大写

2、宏后没有分号

宏函数:(既有宏的特点,又有函数的特点)

#define   函数名(形参)  函数体    

#define   ADD(a,b)  a+b

注意:宏只是一个单纯的替换,他并不会考虑运算符优先级的问题,因此,需要给每个形参,以及整个表达式,都加上括号。

7.变量

定义:就意味着要在内存空间中开辟空间

如何定义一个变量?

<存储类型>  数据类型   变量名;

存储类型:决定了开辟的空间在内存空间中的哪个分区

数据类型:决定了开辟的内存空间的大小

变量名:开辟的内存空间的名字

存储类型:auto、static、extern、register

7.1局部变量和全局变量

局部变量:定义在函数体(任何函数体内)内的变量;

全局变量:定义在函数体外的变量

7.2 存储类型

存储类型:auto、static、extern、register

auto:修饰局部变量,修饰的变量存储在栈区

extern:修饰全局变量,修饰的变量存储在静态区

static:既可以修饰局部变量,也可以修饰全局变量,修饰的变量存储在静态区

register:修饰局部变量,存储在寄存器中;

7.3 初始化

初始化:在定义变量的时候就进行赋值了

auto修饰局部变量,修饰的变量存储在栈区

register:修饰局部变量,修饰的变量存储在寄存器中,建议将变量存储在寄存器中,提高运行速度,但是寄存器中的内存空间很小,因此,当用register修饰时,如果寄存器中已满,变量就会存储在栈区

extern修饰全局变量,修饰的变量存储在静态区

作用:告诉编译器,该变量已经在其他文件中定义过了

程序可以由多个.c构成,但是只能有一个main函数

Static即可以修饰全局变量,也可以修饰局部变量

  1. 修饰局部变量时,延长局部变量的生命周期如果局部变量没有初始化,其值为0;如果初始化了,则只能初始化一次;

(延长了生命周期,但是并没有延长作用域!!)

  1. 修饰全局变量时,限制作用域,该变量只能在本文件内使用

7.4生命周期和作用域

7.4.1生命周期:

从开辟空间一直到释放空间

7.4.2作用域

使用的范围

局部变量:

生命周期:从定义开始,到模块结束(距离它最近的大括号)释放空间

作用域:大括号内

Static修饰的局部变量:

生命周期:从定义开始,到程序结束

作用域:大括号内

全局变量:

生命周期:从定义开始,到程序结束

作用域:整个程序

Static修饰的全局变量:

生命周期:从定义开始,到程序结束

作用域:本文件内

8.数据类型转化

8.1 强制类型转化(我们自己去转的)

8.2隐式类型转换(编译器去转的)

横向箭头:

不管有没有进行混合运算,都会进行转换;注意:char、short都当做int来用;float当做double来用

纵向箭头:

只有进行了混合运算,才会进行转换;

9.运算符

单算移关与,异或逻条赋

单目运算符、算术运算符、左移、右移、关系运算符、按位与、异或、按位或、逻辑运算符、

条件运算符、赋值

9.1 算术运算符

+  -  *  /  %  ++  --

%:取余

注意:不能用于浮点数

++在前:先自加,在赋值

++在后:先赋值,在自加

注意:如果a++或者++a,单独成立一条语句,都相当于给a加1;

9.2 关系运算符

>  <  >=  <=  ==  !=

关系运算符:比较两者之间的关系,结果为(真1或者假0)

9.3 逻辑运算符

&&  ||   !

&&

表达式1  && 表达式2

&&截断法则:有一个为假,结果就为假;前一个为假,后面就不在进行运算了

||

表达式1  || 表达式2

截断法则:有一个为真,结果就为真,前一个为真,后面就不在进行运算了

9.4 sizeof运算符

sizeof:计算所占内存空间的大小:单位:字节

sizeof(数据类型) 

sizeof(变量名)

9.5 三目运算符

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

判断表达式1是否成立,如果成立,就将表达式2的值作为整个表达式的值,否则,就将表达式3的值作为整个表达式的值

9.6 逗号运算符

表达式1,表达式2,表达式3,。。。。。,表达式n

从左往右,依次去执行每个表达式,最后将表达式n的值作为整个表达式的值

注意:逗号运算符的优先级是最低的,因此在使用时要加上括号

9.7 位运算符

&  |  ~  ^  <<  >>

9.7.1 按位与(&)

都为1,才为1,有一个为0,就为0

9.7.2 按位或(|)

都为0,才为0,有一个为1,就为1

要修改某几位时,先用&的方法,清零,在用|的方法置1

9.7.3 按位取反(~)

1变0, 0变1

~(1001 0010) == 0110 1101

9.7.4 异或(^)

相同为0,不同为1

9.7.5左移(<<)

Unsigned:

0000 0001 << 2  

高位丢弃,低位补0

0000 0100 ------------------4

Signed:

负数:-1 <<2

原码:1000 0001

反码:1111 1110

补码:1111 1111

高位丢弃,低位补0

补码:1111 1100

反码:1000 0011

原码:1000 0100------------   -4

9.7.6右移(>>)

Unsigned:

正数

0000 0100 >>2

低位丢弃,高位补0:

0000 0001---------------------1

Signed:

负数:

-4  >>  2

符号位不变,低位丢弃,高位补1

原码:1000 0100

反码:1111 1011

补码:1111 1100

      1111 1111

反码:1000 0000

原码:1000 0001-------------  -1

总结

左移:

无符号数:高位丢弃,低位补0

有符号数:符号位不变,高位丢弃,低位补零

右移:

无符号数:低位丢弃,高位补0:

有符号数:符号位不变,低位丢弃,高位补(0正,1负)

10.输入输出

函数:有独立功能的模块

标准的输入输出函数:scanf、printf(对输入以及输出的变量的类型没有限制)

输入:将键盘输入数据拷贝到内存中

输出:将内存中的数据打印至终端

10.1输出

printf(“格式控制串”,输出表);

格式控制串:原样输出的内容+格式化符

输出表:输出的内容

(格式化符要和输出表一一对应)

整型:

%d:以十进制进行输出

%o:以八进制进行输出

%x、%X:以十六进制进行输出

#:自动在八进制和十六进之前加上前缀

%u:以无符号形式(将最高位看做数据位)进行输出

%hd:short类型

%ld:long类型

%lld:long long 类型

字符型:

%c

浮点型:

%f:float

%lf:double

%e:以指数形式进行打印

%g:选择小数和指数中较短的(合适)一个进行输出

%m.nf:

.n  :决定的是输出小数点后n位(有小数点,但是省略n时,输出小数点后0位)

m. :决定所占的域宽,默认右对齐,(m为负数,左对齐)m的值大于数据的实际长度时,补空格,当m的值小于实际长度时,原样输出

10.2输入

Scanf(“格式控制串”,地址表);

格式控制串:原样输入的内容+格式化符

&+变量名://获取该变量的地址

注意:

  1. scanf的格式控制串中不要去加多余的修饰语,如果加了,就要原样输入。
  2. 如果输入“%d%d”时要给多个变量进行赋值,在格式控制串中没有间隔,那么在输入的时候,以空格、回车、Tab键作为第一个变量输入结束的标志
  3. 全部输入结束后,必须以回车作为结束符
  4. 如果以“%c%c”给多个字符变量进行赋值,在输入的时候不能由空格、回车、Tab作为输入结束的标志;因为空格、回车Tab也是一个字符

解决办法

  1. 在%c和%c中加多余的空格或者,
  2. %*c   *表示抑制符 

(抑制n个字符)%*nc

11.字符的输入和输出

字符的输入:

getchar( );

返回值:获取到的字符的ascii码值

Int a = 0

getchar();//直接使用,不获取返回值,则相当于吃掉一个垃圾字符

字符的输出:

putchar( );

需要的参数:字符的ascii码值;

12.三大结构

三大结构:顺序结构、选择结构、循环结构

12.1 顺序结构

语句按照一定的先后顺序去执行

12.2 选择结构

12.2.1 单分支if选择结构

If(表达式)

{

语句;

}

先判断表达式是否成立,如果成立,就执行语句。

12.2.2 双分支if选择结构

If(表达式)

{

语句1;

}

else

{

语句2;

}

先判断表达式是否成立,如果成立,则执行语句1,否则,执行语句2;

12.2.3 多分支if选择结构

If(表达式1)

{

语句1;

}

Else if(表达式2)

{

语句2;

}

Else if(表达式3)

{

语句3;

}

。。。。

else  if(表达式n)

{

语句n;

}

else

{

语句n+1;

}

从上往下,依次去判断表达式是否成立,如果表达式成立,则执行对应的语句

12.2.4 switch语句

Switch(表达式)

{

Case 标号1:

语句1;

Case 标号2:

语句2;

Case 标号3:

语句3;

。。。。

Case 标号n:

语句n;

    default:

语句n+1;

}

注意:

  1. 表达式不能为float类型
  2. 标号必须为常量
  3. 当表达式等于标号时,就冒号后面的语句,直到switch,case语句结束为止,或者遇到break语句结束。
  1. switch,case语句是否结束)
  2. 是否遇到了break)

12.3 循环结构

循环的起始条件

循环的终止条件

循环变量的变化

12.3.1 for循环

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

{

循环体;

}

表达式1:循环的起始条件

表达式2:循环的终止条件

表达式3:循环变量的变化

先执行表达式1,然后执行表达式2,如果表达式2为真,执行循环体,然后执行表达式3;如此反复,当表达式2为假时,结束循环

省略表达式1:

可以省略,但是需要在for循环之前给循环变量一个初始值

省略表达式2:

可以省略,但是会死循环

省略表达式3:

可以省略,不过需要将循环变量的变化在循环体内实现

总结:三个表达式都可以省略,但是分号不能省略

12.3.2while语句

While(表达式)

{

  循环体;

}

判断表达式是否成立,如果成立,就执行循环体,反之,跳出循环

12.3.3do while语句

Do

{

  循环体;

}while(表达式);

先执行循环体,然后判断表达式是否成立,如果成立,就继续执行循环体,否则结束循环

12.3.4break和continue区别

Break:1.结束switch,case语句2.跳出循环(结束循环)

continue:跳出循环(跳出本次循环,进入下一次循环)

12.3.5死循环

1.

While(1)

{

  循环体

}

2.

For( ;1; )

{

  循环体

}

goto语句

goto:无条件跳转语句

goto 标号:

标号(和标识符命名规则相同即可);

13.数组

13.1概念

一组数据类型相同的元素组合在一起

特点:1.数据类型相同 2.地址连续

13.2定义

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

Int arr[5];

数据类型:数组中元素的数据类型

数组的数据类型:int [5];

数据类型:去掉变量名,剩下的就是数据类型

数组所占的内存空间的大小=sizeof(数据类型)*元素的个数

数组名:1.整个数组 2.数组首元素的地址 arr == &arr[0]

注意:定义数组时,元素的个数必须为一个确定的值(常量/常量表达式)

13.3初始化

13.4部分初始化

当进行部分初始化时:没有初始化的部分为0

因此,我们可以利用此特性给数组进行清零

Int   a  = 0;

Int arr[100] = {0};//为了避免随机值

13.5全部初始化

nt arr[5] = {1,2,3,4,5};

只有在进行全部初始化时:元素的个数才可以省略:

Int arr[  ] = {1,2,3,4,5,6,7};

总结:

  1. 数组定义在函数体内,如果没有进行初始化,里面的所有元素是随机值(局部变量)
  2. 数组定义在函数体外,如果没有进行初始化,里面的所有元素为0(全局变量)
  3. 数组定义在函数体内,并且用static进行修饰,里面的所有元素为0(静态局部变量)

13.6访问

数组名[下标];

14.冒泡排序

思想:从左往右,两两依次比较,如果前一个数比后一个数大,就交换位置,反之,不变

For(i=0;i<N-1;i++)

{

  For(j=0;j<N-i-1;j++)

{

       If(a[j]>a[j+1])

              {

                     交换

}

}

}

15.字符数组

15.1字符数组定义

字符数组:保存一组char类型的数据

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

数据类型:数组中元素的数据类型

 定义: char  str[10];//定义了一个字符数组str,该数组中可以存放10个char类型的字符

数组所占的内存空间== sizeof(char)*10 = 10

数组的数据类型:char [10];//去掉数组名

字符串:用字符数组来保存!

给字符数组清零:

Char str[10] = {0}

Char str[10] = {‘\0’};

字符数组的本质就是字符串;

给字符数组进行赋值:

1、Char str[10] = { ‘h’,’e’,’l’,’l’,’o’ };

Str[5]----->str[9] ==’\0’;

“hello”  = ‘h’,’e’,’l’,’l’,’o’,‘\0’

  1. Char str[10] = “hello”;

//数组名就是数组首元素的地址

//&str[0] == str

15.2字符串的输入输出函数

15.2.1字符串的输出函数

%s:字符串

Printf(“ %s ”, str);

puts(数组名);

功能:将数组中的内容打印到终端,并且自动换行

注意:打印到‘\0结束

15.2.2字符串的输入函数

Scanf(“%s”,str);

gets(数组名);

功能:将输入的字符串保存在数组中,并且在末尾自动添加‘\0’

注意:gets不会进行越界检查,如果超出范围,就会操作未申请到的内存空间,段错误

出现段错误的原因:非法操作你没有申请的空间

15.3scanf和gets的区别

Scanf写在gets之上时,会出现异常情况(gets吃掉了‘\n’)

  1. gets以回车作为结束符,但是scanf以空格,回车TAB作为变量输入结束的标志

2、

缓冲区:

Gets在输入结束后,会自动清空缓冲区的内容

Scanf在输入结束后,会在缓冲区中遗留空格、回车、tab

输入:

Gets:进行输入时,回先去检查缓冲区的内容,如果缓冲区有内容,会率先输出缓冲区当中的内容

Scanf:键入,不会检查缓冲区的内容

15.4printf和puts的区别

puts会自动换行,而printf不会

16字符串的处理函数

Strlen、 strcpy、strcat、strcmp

头文件:#include  <string.h>

16.1求字符串长度

Strlen(数组名);

功能:求字符串的长度

返回值:求得的字符串的实际长度,不包含’\0’

strlen和sizeof的区别:

  1. strlen求到的是字符串的实际长度,而sizeof求到的是申请到的内存空间的大小
  2. Strlen是一个函数,sizeof是一个运算符

案例:不使用strlen函数,求字符串的实际长度

16.2字符串的拷贝函数

Strcpy(数组1,数组2/字符串);

作用:将数组2中的内容拷贝给数组1,包含‘\0’,相当于完全拷贝

注意:数组1的容量要大于数组2

Strncpy(数组1,,数组2/字符串,n);

作用:将数组2或者字符串中的前n个字符拷贝给数组1

16.3字符串的连接函数

Strcat(数组1,数组2/字符串);

功能:将数组2中的内容连接到数组1中去,数组1中的’\0’会被覆盖

注意:数组1的容量要足够大(字符串1+字符串2)

Strncat(数组1,数组2/字符串,n)

功能:将字符串2的前n个字符连接到字符串1后

16.4字符串的比较函数

Strcmp(数组1/字符串1,数组2/字符串2);

功能:比较字符串1和字符串2的大小

返回值:

大于0:字符串1 > 字符串2

等于0:字符串1 == 字符串2

小于0:字符串1 < 字符串2

比较规则:从左往右,依次去比较字符串中的每个字符的ascii,直到遇到不同的ascii码或者遇到‘\0’,结束比较

17二维数组

17.1概念

二维数组:(数组数组):一堆数组的元素组合在一起

元素为一维数组的一维数组

(一维数组的元素的类型以及个数必须相同)

17.2定义

存储类型  数据类型  数组名[行数][列数];

           Int   arr[4][3] ;

//保存了4个一维数组

行数:一维整型数组的个数

列数:一维整型数组中元素的个数

实际的元素的个数:行数*列数

内存空间的大小:sizeof(数据类型)*行数*列数

数据类型:数组最里面的元素的数据类型

17.3初始化

17.3.1部分初始化

Int  a[3][4] = {1,2,3};

Int  a[3][4] = {{1,2,3},{1},{1,2}};

Int  a[3][4] = {0};//清零

17.3.2全部初始化

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

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

思考:行数和列数是否可以省略?

Int a[  ][3] = {1,2,3,4,5,6,7,8};

//行数可以省略

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

//列数不可以省略

17.4访问

可以通过数组下标访问

18二维字符数组

二维整形数组

定义一个二维整型数组:

存储类型  数据类型  数组名[行数][列数];

           Int   arr[4][3] ;

//数据类型:二维数组最里面的元素的数据类型

二维字符数组:

存储类型  数据类型  数组名[行数][列数];

            Char    str[3][10];

//相当于定义了一个二维数组str,数组中有3个元素,每个元素又是一个拥有10个char类型的一维数组

行数:字符串的个数(一维字符数组的个数)

列数:字符串最多可以保存几个字符(一维数组中元素的个数)

19函数

19.1概念

具有独立功能的模块

19.2调用函数

函数名(参数);

Strlen(参数);

返回值:int(字符串的实际长度)

注意:参数的个数,以及参数的类型;返回值的类型(是否需要接收返回值)

19.3自定义函数

19.3.1自定义函数

存储类型  数据类型  函数名(形式参数列表)

{

函数体;

}

存储类型:auto、static、extern、register

数据类型: 返回值的数据类型(void)(数据类型省略不写,默认是int类型)

函数名: 见名知意

形式参数列表:(由程序员自己去确定!)要实现的功能需要几个参数,以及每个参数是什么类型

函数体:实现具体的功能

返回值:若没有返回值,void;返回值也可以省略,如果省略,默认int类型(返回有且只能有一个)

19.3.2调用函数

函数名(实际参数列表);

注意:

  1. 需要将实参的值拷贝给形参,实参的个数以及数据类型要和形参一致
  2. 实参,可以是变量,常量,表达式,但是必须是一个确定的值
  3. 实参和形参是两块独立的空间
  4. 传参,实际上是将实参的值拷贝给形参
  5. 形参是局部变量,在函数调用时开辟空间,函数调用结束,立即释放

19.3.3函数声明

如果函数没有写在main函数之前,就需要声明;

声明:将函数头部直接复制粘贴至main函数之前,然后加上分号

声明的作用:帮助编译器做语法检查

20指针

20.1概念

指针是一种数据类型,它是一种保存地址的数据类型

20.2指针变量

Int   a ; //a是用来保存整形数  10(整型常量)  a(整型变量)

Char  b;//b是用来保存字符的 ‘a’

Float  c;//c是用来保存浮点数  3.14

指针 p;//p就是用来保存地址的  0x100

P:指针变量

20.3定义

存储类型  数据类型 * 指针变量名;

           Int   * p;

//定义了一个指针变量p,p用是用来保存(谁的(int)地址)地址

数据类型:指针指向的数据类型(指针保存的是什么数据类型的变量的地址)

指针的数据类型:int *

20.4指针的赋值

指针的赋值相当于改变指针的指向

指针赋值时要注意 指针指向的数据类型必须相同

20.5空指针

指向零号地址的指针(值为0的指针,就认为该指针没有指向)

注意:零号地址禁止操作

NULL;

20.6野指针

野指针:不知道指向哪里的指针

局部变量,没有初始化,随机值

局部指针变量,如果没有初始化,就是野指针

如何避免野指针:让她先指向0号地址;

21二级指针

21.1概念

保存一级指针的地址         //指针指针

21.2定义

存储类型  数据类型  *指针变量名;

           Int * *pp;

数据类型:指针指向的数据类型;(二级指针指向的数据类型:一级指针的数据类型)

(int  *)

二级指针的数据类型:int **;

  1. 指针的数据类型,去掉变量名就是数据类型

Int *p;   // int *

Int **p;  //int **

Int ***p; // int ***

  1. 指针指向的数据类型,去掉的一个*和变量名,剩下的就是指针指向的数据类型

Int *p; // p指向的数据类型为int

Char *h;//h指向的数据类型char

Int **q;//q指向的数据类型为int *

Char **s;//s指向的数据类型为 char *

Int ***t;//t指向的数据类型 int **

3、指针所能访问到的内存空间的大小,由指向的数据类型决定

Char a = ‘b’;

Char *p = &a;//p能访问到的内存空间1字节 

int a;

Int *q = &a;//q能访问到的内内存空间的大小:4字节

Int **s ;

S = &q;//s所能访问到的内存空间的大小:4字节

4、

Int **p;

Int ** *q;

q = &p;

21.3指针的算术运算

p+n:p向地址增大的方向移动了n个数据

     p实际的变化:p + sizeof(指针指向的数据类型)*n

P-n:  p向地址见效的方向移动了n个数据

     p实际的变化:p - sizeof(指针指向的数据类型)*n

P++:  p向地址增大的方向移动了一个数据 //改变指针的指向

      p = p+sizeof(指针指向的数据类型)

P--:p向地址减小的方向移动了一个数据 //改变指针的指向

      p = p-sizeof(指针指向的数据类型)

p-q:(p和q数据类型必须相同):这两个指针之间相隔的个数

实际的变化:(q-p)/sizeof(指针指向的数据类型)

注意:

1、指针的算数运算只有在连续的内存空间中才有意义

2、p是指针变量,以上的算术运算也同样应用于指针常量,但是++,--除外

22指针和数组的关系

22.1指针常量和一维数组的关系

注意:数组名和指针变量的区别:数组名是指针常量::指针常量不可以自加自减!!!

22.2指针变量和一维数组的关系

注意:!!在使用指针变量的移动时:一定要注意:指针此时指向了哪里

23指针和二维数组的关系

总结

  1. &a、a、&a[0]、a[0]、&a[0][0]的值是一样的,但是表达的含义不一样

a:Int (*) [3] :他是一个指向一维数组的指针  a[0]:指向int类型元素的指针

  1. 为什么说a不是int**类型?

如果a是int**类型,那么他指向的数据类型应该是int * ,那么a+1,应该移动移动4字节,但是a+1,移动了12字节,移动了一个数组,因此a一定不是int**类型

  1. a指向a[0]、a[0]指向a[0][0]

24数组指针

24.1概念

指向数组的指针

//保存数组的地址

24.2定义

存储类型 数据类型 (* 变量名) [元素的个数];

         Int (*p)[3];

//定义了一个指向数组的指针p,指向的这个数组:有3个int类型的元素

存储类型:auto、static、extern、register

数组类型:指针指向的数组中的元素数据类型

P:数组指针的数据类型: int (*)[3];

p指向的数据类型:int [3]   //去掉变量名和一个*

p+1:移动sizeof(指向的数据类型) sizeof(int [3])

24.3数组指针和一维数组的关系

24.4数组指针和二维数组的关系

25指针数组

25.1概念

元素为指针的数组

25.2定义

存储类型  数据类型 * 变量名[元素的个数];

Int * arr[3];

//相当于定义了一个数组,这个数组种有三个元素,每一个元素都是int *类型

数组中元素的数据类型:int *

25.3指针数组和二维数组的关系

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值