计算机的数据表示
非数值数据和数值数据
10 ------0000 1010
4.1 非数值数据
数值数据(进制转换)
可以直接进行运算的数据
二进制、八进制、十进制、十六进制
二进制: 0~1(逢二进1)
基本数据类型
关键字:系统预先定义好的,有特殊含义的,并且都是小写,不能重新定义
一共有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: 防止编译器优化
标识符:程序员自己定义的,一般用来定义变量名,函数名,类型名
命名规范:(见名知意)
- 由数字、字母、下划线组成
- 第一个不能为数字
- 不能和关键字重名
八进制:0~7(逢八进1)
十进制:0~9(逢十进1)
十六进制:0 ~9、a~ f(A~F)(逢16进1)
为了区分不同的进制:八进制前加0,十六进制前0x(0X)(0x7fa 0X7FA)
十进制:76 八进制:076 十六进制:0x76、0X76
基本数据类型
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字节)
有符号数和无符号数
有符号数(signed):有正数有负数(定义一个变量,默认是有符号的)
所有的数据都以补码的形式保存在计算机中
符号位:最高位表示该数据为正数还是负数(0表示正数,1表示负数)
- --------0000 1010
-10-------- 1000 1010
10+(-10) = 0
为了保证计算的正确性:计算机中保存数据时,以补码的形式保存数据的
正数:原码,反码,补码都是一样的
10--------原码:反码:补码:0000 1010
负数:
原码:直接转换为二进制,并且最高位表示符号位
反码:符号位不变,其他位取反(0变1,1变0)
补码:反码+1
-10 -------
原码: 1000 1010
反码: 1111 0101
补码: 1111 0110
无符号数(unsigned):只有正数,并且都是数据位
字符型家族
值域范围:
Char(1字节)
unsigned char:
0000 0000 ------ 1111 1111 (0 - 255)
signed char:
有符号数:最高位要用来表示:符号(0正,1负)
1000 0000------ 0111 1111 (-128~127)
考点!超过这个范围:转圈去数
Unsigned char c = 260;
printf(“%d\n”,c); // 4
Signed char a = 130;
Printf(“%d\n”,a); // -126
整型家族
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)
浮点型家族
Float(单精度浮点数):表示6~7位有效数据
%f(默认输出小数点后6位)
Double(双精度浮点数):表示15~16位有效数据
%lf(默认输出小数点后6位)
如果想要输出小数点后n位(%.nf)
字符常量
‘a’ ’A’ ‘b’
整型常量
二进制:1010
八进制:076
十进制:99 -2
十六进制:0xaf 0X6FC
(默认情况下,为有符号数:int、short、long)
无符号的int:66U
长整型:66L
无符号的长整型:66UL
浮点型常量
小数:3.14 10000(浮点型常量也包括整形常量)
指数:10000 = 1*10的4次方 1e+4 1e-4
//error:(1*10^4)
%g:选择小数或者指数比较短的一种形式进行输出
字符串常量
“hello” “hi”
字符串以‘\0’结尾
标识常量(宏)
宏只是一个单纯的替换!!!
宏:#define 宏名 表达式
注意:
1、宏名一般用大写表示,小写也可以,因为要和普通的变量区分开来,所以用大写
2、宏后没有分号
宏函数:(既有宏的特点,又有函数的特点)
#define 函数名(形参) 函数体
#define ADD(a,b) a+b
变量
如何定义一个变量?
<存储类型> 数据类型 变量名;
存储类型:决定了开辟的空间在内存空间中的哪个分区
数据类型:决定了开辟的内存空间的大小
变量名:开辟的内存空间的名字
局部变量
定义在函数体(任何函数体内)内的变量
全局变量
定义在函数体外的变量
存储类型
存储类型:auto、static、extern、register
auto:修饰局部变量,修饰的变量存储在栈区
extern:修饰全局变量,修饰的变量存储在静态区
static:既可以修饰局部变量,也可以修饰全局变量,修饰的变量存储在静态区
register:修饰局部变量,存储在寄存器中;
初始化
初始化:在定义变量的时候就进行赋值了
1、int a = 10;//初始化
2、int a;
a = 10;//赋值
结
- 全局变量没有进行初始化时,他的值为0
- 局部变量没有进行初始化时,他的值为随机值
(定义变量时,尽量给他一个初始值,避免出现随机值)
auto:修饰局部变量,修饰的变量存储在栈区
register:修饰局部变量,修饰的变量存储在寄存器中,建议将变量存储在寄存器中,提高运行速度,但是寄存器中的内存空间很小,因此,当用register修饰时,如果寄存器中已满,变量就会存储在栈区
extern:修饰全局变量,修饰的变量存储在静态区
程序可以由多个.c构成,但是只能有一个main函数
Static:即可以修饰全局变量,也可以修饰局部变量
- 修饰局部变量时,延长局部变量的生命周期,如果局部变量没有初始化,其值为0;如果初始化了,则只能初始化一次;
(延长了生命周期,但是并没有延长作用域!!)
修饰全局变量时,限制作用域,该变量只能在本文件内使用
生命周期和作用域
生命周期:
从开辟空间一直到释放空间
作用域
使用的范围
局部变量:
生命周期:从定义开始,到模块结束(距离它最近的大括号)释放空间
作用域:大括号内
tatic修饰的局部变量:
生命周期:从定义开始,到程序结束
作用域:大括号内
全局变量:
生命周期:从定义开始,到程序结束
作用域:整个程序
Static修饰的全局变量:
生命周期:从定义开始,到程序结束
作用域:本文件内
数据类型转化
强制类型转化(我们自己去转的)
隐式类型转换(编译器去转的)
横向箭头:
不管有没有进行混合运算,都会进行转换;
运算符
单算移关与,异或逻条赋
单目运算符、算术运算符、左移、右移、关系运算符、按位与、异或、按位或、逻辑运算符、
条件运算符、赋值
术运算符
+ - * / % ++ --
%:取余
注意:不能用于浮点数
++在前:先自加,在赋值
++在后:先赋值,在自加
注意:如果a++或者++a,单独成立一条语句,都相当于给a加1;
关系运算符
> < >= <= == !=
关系运算符:比较两者之间的关系,结果为(真1或者假0)
逻辑运算符
&& || !
&&
表达式1 && 表达式2
&&截断法则:有一个为假,结果就为假;前一个为假,后面就不在进行运算了
||
表达式1 || 表达式2
截断法则:有一个为真,结果就为真,前一个为真,后面就不在进行运算了
sizeof运算符
sizeof:计算所占内存空间的大小:单位:字节
sizeof(数据类型)
sizeof(变量名)
三目运算符
表达式1 ? 表达式2 :表达式3
判断表达式1是否成立,如果成立,就将表达式2的值作为整个表达式的值,否则,就将表达式3的值作为整个表达式的值
逗号运算符
表达式1,表达式2,表达式3,。。。。。,表达式n
从左往右,依次去执行每个表达式,最后将表达式n的值作为整个表达式的值
注意:逗号运算符的优先级是最低的,因此在使用时要加上括号
位运算符
& | ~ ^ << >>
按位与(&)
都为1,才为1,有一个为0,就为0
按位或(|)
都为0,才为0,有一个为1,就为1
按位取反(~)
1变0, 0变1
异或(^)
相同为0,不同为1
左移:
无符号数:高位丢弃,低位补0
有符号数:符号位不变,高位丢弃,低位补零
右移:
无符号数:低位丢弃,高位补0:
有符号数:符号位不变,低位丢弃,高位补(0正,1负)
- 输入输出
函数:有独立功能的模块
标准的输入输出函数:scanf、printf(对输入以及输出的变量的类型没有限制)
输入:将键盘输入数据拷贝到内存中
输出:将内存中的数据打印至终端
-
- 输出
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的值小于实际长度时,原样输出
输入
Scanf(“格式控制串”,地址表);
格式控制串:原样输入的内容+格式化符
&+变量名://获取该变量的地址
注意:
- scanf的格式控制串中不要去加多余的修饰语,如果加了,就要原样输入。
- 如果输入“%d%d”时要给多个变量进行赋值,在格式控制串中没有间隔,那么在输入的时候,以空格、回车、Tab键作为第一个变量输入结束的标志
- 全部输入结束后,必须以回车作为结束符
- 如果以“%c%c”给多个字符变量进行赋值,在输入的时候不能由空格、回车、Tab作为输入结束的标志;因为空格、回车Tab也是一个字符
解决办法
- 在%c和%c中加多余的空格或者,
- %*c *表示抑制符
(抑制n个字符)%*nc
字符的输出和输出
字符的输入:
getchar( );
返回值:获取到的字符的ascii码值
Int a = 0
getchar();//直接使用,不获取返回值,则相当于吃掉一个垃圾字符
字符的输出:
putchar( );
需要的参数:字符的ascii码值;
顺序结构
语句按照一定的先后顺序去执行
选择结构
单分支if选择结构
If(表达式)
{
语句;
}
先判断表达式是否成立,如果成立,就执行语句。
双分支if选择结构
If(表达式)
{
语句1;
}
else
{
语句2;
}
先判断表达式是否成立,如果成立,则执行语句1,否则,执行语句2;
案例:输入一个年份,判断该年为平年还是闰年。
多分支if选择结构
If(表达式1)
{
语句1;
}
Else if(表达式2)
{
语句2;
}
Else if(表达式3)
{
语句3;
}
。。。。
else if(表达式n)
{
语句n;
}
else
{
语句n+1;
}
从上往下,依次去判断表达式是否成立,如果表达式成立,则执行对应的语句
顺序结构
语句按照一定的先后顺序去执行
选择结构
单分支if选择结构
If(表达式)
{
语句;
}
先判断表达式是否成立,如果成立,就执行语句。
双分支if选择结构
If(表达式)
{
语句1;
}
else
{
语句2;
}
先判断表达式是否成立,如果成立,则执行语句1,否则,执行语句2;
案例:输入一个年份,判断该年为平年还是闰年。
多分支if选择结构
If(表达式1)
{
语句1;
}
Else if(表达式2)
{
语句2;
}
Else if(表达式3)
{
语句3;
}
。。。。
else if(表达式n)
{
语句n;
}
else
{
语句n+1;
}
从上往下,依次去判断表达式是否成立,如果表达式成立,则执行对应的语句
循环结构
循环的起始条件
循环的终止条件
循环变量的变化
for循环
for(表达式1;表达式2;表达式3)
{
循环体;
}
表达式1:循环的起始条件
表达式2:循环的终止条件
表达式3:循环变量的变化
先执行表达式1,然后执行表达式2,如果表达式2为真,执行循环体,然后执行表达式3;如此反复,当表达式2为假时,结束循环
while语句
While(表达式)
{
循环体;
}
判断表达式是否成立,如果成立,就执行循环体,反之,跳出循环
do..while语句
do
{
循环体;
}while(表达式);
先去执行循环体,然后判断表达式是否成立,如果成立,就继续去执行循环体内的语句,否则,结束循环
总结区别:
while:先判断,在执行,循环体最少执行0次
do-while:先执行,在判断,循环体至少执行1次
!break和continue的区别:(跳出距离自己最近的循环)
break:1、结束switch,case语句 2、跳出循环(结束循环)
continue:跳出循环(跳出本次循环,进入下一次循环)
Continue跳出for循环时,跳出的是循环体,接下来要执行表达式3
死循环
1、
while(1)
{
循环体
}
2、
for( ; 1 ; )
{
循环体
}
goto语句
goto:无条件跳转语句
goto 标号:
标号:
标号的命名规则:满足标识符的命名规则
数组
- 概念
一组数据类型相同的元素组和在一起
特点:1、数据类型相同 2、地址连续
定义
存储类型 数据类型 变量名;
Int a;
存储类型 数据类型 数组名[ 元素的个数 ];
Int arr[5];
存储类型:auto、static、extern、register
数据类型:数组中元素的数据类型
数组的数据类型:int [5];
数据类型:去掉变量名,剩下的就是数据类型;
数组所占的内存空间的大小 = sizeof(数据类型)* 元素的个数
数组名:1、整个数组
2、数组首元素的地址 arr == &arr[0] (获取一个变量的地址:&+变量名)
初始化
部分初始化
Int arr[5] = {1,2,3};
arr[0] = 1 arr[1] =2 arr[2] = 3 arr[3]= ?arr[4] = ?
当进行部分初始化时:没有初始化的部分为0
因此,我们可以利用此特性给数组进行清零
Int a = 0;
Int arr[100] = {0};//为了避免随机值
全部初始化
Int arr[5] = {1,2,3,4,5};
只有在进行全部初始化时:元素的个数才可以省略:
Int arr[ ] = {1,2,3,4,5,6,7};
总结:
比较规则:从左往右,依次去比较字符串中的每个字符的ascii值,直到遇到不同的ascii码或者遇到‘\0’,结束比较
字符串的拷贝函数
Strcpy(数组1,数组2/字符串);
作用:将数组2中的内容拷贝给数组1,包含‘\0’,相当于完全拷贝
注意:数组1的容量要大于数组2
Strncpy(数组1,,数组2/字符串,n);
作用:将数组2或者字符串中的前n个字符拷贝给数组1
字符串的连接函数
Strcat(数组1,数组2/字符串);
功能:将数组2中的内容连接到数组1中去,数组1中的’\0’会被覆盖
注意:数组1的容量要足够大(字符串1+字符串2)
Strncat(数组1,数组2/字符串,n)
功能:将字符串2的前n个字符连接到字符串1后
字符串的比较函数
Strcmp(数组1/字符串1,数组2/字符串2);
功能:比较字符串1和字符串2的大小
返回值:
大于0:字符串1 > 字符串2
等于0:字符串1 == 字符串2
小于0:字符串1 < 字符串2
比较规则:从左往右,依次去比较字符串中的每个字符的ascii值,直到遇到不同的ascii码或者遇到‘\0’,结束比较
- 数组定义在函数体内,如果没有进行初始化,里面的所有元素是随机值(局部变量)
- 数组定义在函数体外,如果没有进行初始化,里面的所有元素为0(全局变量)
- 数组定义在函数体内,并且用static进行修饰,里面的所有元素为0(静态局部变量)
访问
数组名[下标];
注意:下标从0开始;
冒泡排序
思想:从左往右,两两依次比较,如果前一个数比后一个数大,就交换位置,反之,不变
字符数组
字符数组:保存一组char类型的数据
存储类型 数据类型 数组名[元素的个数];
数据类型:数组中元素的数据类型
定义: char str[10];//定义了一个字符数组str,该数组中可以存放10个char类型的字符
数组所占的内存空间== sizeof(char)*10 = 10
数组的数据类型:char [10];//去掉数组名
给字符数组清零:
Char str[10] = {‘\0’};
字符数组的本质就是字符串;
给字符数组进行赋值:
Char str[10] = { ‘h’,’e’,’l’,’l’,’o’ };
Str[5]----->str[9] ==’\0’;
“hello” = ‘h’,’e’,’l’,’l’,’o’,‘\0
-
Char str[10] = “hello”;
-
//数组名就是数组首元素的地址
//&str[0] == str
字符串的输入输出函数
字符串的输出函数
%s:字符串
Printf(“ %s ”, str);
puts(数组名);
功能:将数组中的内容打印到终端,并且自动换行
注意:打印到‘\0结束
字符串的输入函数
Scanf(“%s”,str);
gets(数组名);
功能:将输入的字符串保存在数组中,并且在末尾自动添加‘\0’
注意:gets不会进行越界检查,如果超出范围,就会操作未申请到的内存空间,段错误
出现段错误的原因:非法操作你没有申请的空间
scanf和gets的区别
Scanf写在gets之上时,会出现异常情况(gets吃掉了‘\n’)
- gets以回车作为结束符,但是scanf以空格,回车TAB作为变量输入结束的标志
-
2、
缓冲区:
Gets在输入结束后,会自动清空缓冲区的内容
Scanf在输入结束后,会在缓冲区中遗留空格、回车、tab
输入:
Gets:进行输入时,回先去检查缓冲区的内容,如果缓冲区有内容,会率先输出缓冲区当中的内容
Scanf:键入,不会检查缓冲区的内容
printf和puts的区别
puts会自动换行,而printf不会
字符串的处理函数
求字符串的长度
Strlen(数组名);
功能:求字符串的长度
返回值:求得的字符串的实际长度,不包含’\0’
strlen和sizeof的区别:
- strlen求到的是字符串的实际长度,而sizeof求到的是申请到的内存空间的大小
- Strlen是一个函数,sizeof是一个运算符
二维数组
概念
元素为一维数组的一维数组
数据类型相同 2、地址连续
(一维数组的元素的类型以及个数必须相同)
定义
存储类型 数据类型 数组名[元素的个数];
Int a[3];
//定义了一个有五个int类型元素的数组
数据类型:元素的数据类型
一维数组的数据类型:int[3];
定义一个二维数组:
存储类型 数据类型 数组名[行数][列数];
Int arr[4][3] ;
//保存了4个一维数组
行数:一维整型数组的个数
列数:一维整型数组中元素的个数
实际的元素的个数:行数*列数
内存空间的大小:sizeof(数据类型)*行数*列数
数据类型:数组最里面的元素的数据类型
部分初始化
Int a[3][4] = {1,2,3};
Int a[3][4] = {{1,2,3},{1},{1,2}};
Int a[3][4] = {0};//清零
全部初始化
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};
//列数不可以省略
二维字符数组
二维字符数组:
存储类型 数据类型 数组名[行数][列数];
Char str[3][10];
//相当于定义了一个二维数组str,数组中有3个元素,每个元素又是一个拥有10个char类型的一维数组
行数:字符串的个数(一维字符数组的个数)
列数:字符串最多可以保存几个字符(一维数组中元素的个数)
函数
概念
具有独立功能的模块
为什么要使用函
数
1、提高代码的复用率
2、让程序变得模块化、简洁
库函数
printf scanf strlen......
引入头文件
#include <stdio.h>
#include <string.h>
调用函数
函数名(参数);
Strlen(参数);
返回值:int(字符串的实际长度)
注意:参数的个数,以及参数的类型;返回值的类型(是否需要接收返回值)
自定义函数
存储类型 数据类型 函数名(形式参数列表)
{
函数体;
}
存储类型:auto、static、extern、register
数据类型: 返回值的数据类型(void)(数据类型省略不写,默认是int类型)
函数名: 见名知意
形式参数列表:(由程序员自己去确定!)要实现的功能需要几个参数,以及每个参数是什么类型
函数体:实现具体的功能
返回值:若没有返回值,void;返回值也可以省略,如果省略,默认int类型(返回有且只能有一个)
调用函数
函数名(实际参数列表);
注意:
- 需要将实参的值拷贝给形参,实参的个数以及数据类型要和形参一致
- 实参,可以是变量,常量,表达式,但是必须是一个确定的值
- 实参和形参是两块独立的空间
- 传参,实际上是将实参的值拷贝给形参
- 形参是局部变量,在函数调用时开辟空间,函数调用结束,立即释放
函数声明
如果函数没有写在main函数之前,就需要声明;
声明:将函数头部直接复制粘贴至main函数之前,然后加上分号
声明的作用:帮助编译器做语法检查
指针
- 概念
-
指针是一种数据类型,它是一种保存地址的数据类型
Int是一种数据类型,它是一种保存整形数的数据类型
Char是一种数据类型,它是一种保存字符的数据类型
- 什么是地址
-
内存分配的最小单元:字节
每一个字节都有一个编号,我们把这个编号就叫做地址
地址的本质:内存单元的编号
指针:指针就是地址
指针的本质:内存单元的编号
- 指针变量
-
Int a ; //a是用来保存整形数 10(整型常量) a(整型变量)
Char b;//b是用来保存字符的 ‘a’
Float c;//c是用来保存浮点数 3.14
指针 p;//p就是用来保存地址的 0x100
P:指针变量
- 定义
-
存储类型 数据类型 * 指针变量名;
Int * p;
//定义了一个指针变量p,p用是用来保存(谁的(int)地址)地址
数据类型:指针指向的数据类型(指针保存的是什么数据类型的变量的地址)
指针的数据类型:int *
- 指针的赋值
-
指针的赋值相当于改变指针的指向
(指针赋值时要注意 指针指向的数据类型必须相同)
在所有的32os操作系统中,所有的指针都占4个字节
空指针
指向零号地址的指针(值为0的指针,就认为该指针没有指向)
注意:零号地址禁止操作
NULL;
- 野指针
-
野指针:不知道指向哪里的指针
局部变量,没有初始化,随机值
局部指针变量,如果没有初始化,就是野指针
如何避免野指针:让她先指向0号地址;
二级
指针
- 概念
-
保存一级指针的地址 //指针指针
- 定义
-
存储类型 数据类型 *指针变量名;
Int * *pp;
数据类型:指针指向的数据类型;(二级指针指向的数据类型:一级指针的数据类型)
(int *)
二级指针的数据类型:int **;
总结:
- 指针的数据类型,去掉变量名就是数据类型
-
Int *p; // int *
Int **p; //int **
Int ***p; // int ***
- 指针指向的数据类型,去掉的一个*和变量名,剩下的就是指针指向的数据类型
-
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;
指针的算术运算
总结:
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(指针指向的数据类型)
总结
- &a、a、&a[0]、a[0]、&a[0][0]的值是一样的,但是表达的含义不一样
-
a:Int (*) [3] :他是一个指向一维数组的指针 a[0]:指向int类型元素的指针
- 为什么说a不是int**类型?
- a指向a[0]、a[0]指向a[0][0]
-
如果a是int**类型,那么他指向的数据类型应该是int * ,那么a+1,应该移动移动4字节,但是a+1,移动了12字节,移动了一个数组,因此a一定不是int**类型
数组指针
概念
指向数组的指针
//保存数组的地址
定义
存储类型 数据类型 (* 变量名) [元素的个数];
Int (*p)[3];
//定义了一个指向数组的指针p,指向的这个数组:有3个int类型的元素
存储类型:auto、static、extern、register
数组类型:指针指向的数组中的元素数据类型
P:数组指针的数据类型: int (*)[3];
p指向的数据类型:int [3] //去掉变量名和一个*
p+1:移动sizeof(指向的数据类型) sizeof(int [3])
数组指针和一维数组的关系
注意:数组指针一般不去操作一维数组。因为p+1,移动一个数组,就会越界,因此数组指针,一般用数组指针去操作二维数组!
指针数组
概念
元素为指针的数组
定义
存储类型 数据类型 * 变量名[元素的个数];
Int * arr[3];
//相当于定义了一个数组,这个数组种有三个元素,每一个元素都是int *类型
数组中元素的数据类型:int *
- const修饰:
-
Const修饰变量
只读:
Const修饰就相当于常量吗?
不是,只是const进行修饰时,不能直接修改变量的值,但是可以通过指针,间接修改a的值
Const修饰指针:
左数右指(const关于*的位置)
const在*的左边时:*p不能被改变;(值)
Const在*的右边时: p 不能被改变;(指向)
Int *p;
Const int *p;
Int const *p;//这两种情况,const都在*的左边,因此,*p不能被改变
-
main函数传参
-
//1.表示字符串的个数
Int argc;
//2.保存你传入的每一个字符串的地址
Char * argv[ ];
Int main(int argc, char * argv[])
-