八位十六进制占4字节
一位十六进制代表四位二进制,0x12345678转换成二进制就是0001-0010-0011-0100-0101-0110-0111- 1000而每 八位二进制占一个字节,所以你
8位十六进制数占4字节
存储类型(四种)
auto(自动的) static(静态的) register(寄存器) extern(外部的)
指针格式
<存储类型> <数据类型> * <指针变量名>
·auto int * Name
注:①指针的存储类型是指针变量本身的存储类型;
②指针说明时指定的数据类型不是指针变量本身的数据类型,而是指针目标的数据类型,简称为指针的数据类型
一般形式:
<存储类型> <数据类型> * <指针变量名> = <地址量>;
例如:int a, *pa=&a;()
在上面语句中,把变量a的地址作为初值赋予了刚说明的int型指针pa。
int a=3; //int a; a=3;
int *pa=&a; //int *pa; pa=&a;
注:字符串、数据不需要加&符号。
例如:int a[]={2,3,34,},*q;
char b[]=“good”,*p;
q=a;
p=b;
* + <指针变量名>
可以访问变量名里存储地址的内容。
指针的三种表示方法:p、*p、&p
p:指针变量,它的内容是地址量;
*p:指针所指向的对象,它的内容是数据;
&p:指针变量占用的内存地址,是个常量;
列如:int a=3,*p=&a; //如a、p的内存地址分别为0x......7f、0x......a3
printf(“%p”,&a); //直接打印出a的内存地址:0x......7f
printf(“%p”,p); //打印出p存储(的a)的内存地址:0x......7f
printf(“%d”,*p); //打印出p存储(的a)的内存地址上的内容:3
printf(“%p”,&p); //打印出p的内存地址:0x......a3
指针与数组(数据组中的数组名也相当于地址)
一维数组(数组名为常量,不能++,不能计算,需要依靠指针)
int i,a[]={1,2,3,4,5,6},*p=a;//*p=a 等价于 *p,p=a;
设指针变量p的地址值等于数组指针a(即指针变量p指向数组的首元数),则:
a[i]等价*(a+i)、*(p+i)等价p[i] 四个具有完全相同的功能;
注:①如指针p要取a[0]的地址则要加&(a不要,因为数组名a本身就为地址,a[0]则为内容);
例:p=&a[0];
②int a[]={1,2,3,4},*p=a;
p++;
printf(“%d\n”,p[1]);
输出结果为3.(因为p[1]等价为*(p+1),而前面p++,所以结果应该为*(p+1+1))
二维数组(可看成n个一维数组) L1-D6-7
int a[3][2]={{1,4},{2,5},{6,2}};
int *p;
p=a[0];//p不能直接等于a,因为二维数组a[i]为数组名,a[0][0]为内容
//p=a[0]等价于p=&a[0][0]
printf(%p %p\n”,p,p+1); //输出结果为:0xbfe5c368 0xbfe5c36c 为a[0][0]和a[0][1]的地址
printf(%p %p\n”,a,a+1); //输出结果为:0xbfe5c368 0xbfe5c370 为a[0][0]和a[1][0]的地址
二维数组名代表数组的起始地址,数组名加1,是移动一行元素。因此,二维数组名常被称为行地址。
例:在a[2][2]中:a[0]=*(a+0)
a[1]=*(a+1)
a[2]=*(a+2)
如:
printf(%p %p\n”,a,a+1);
printf(%p %p\n”,a[0],a[0]+1);a[0]等价于*a,a[0]+1和*a+1
结果:0xbfbc1fc8 0xbfbc1fd0 //为a[0][0]和a[1][0]的地址
0xbfbc1fc8 0xbfbc1fcc //为a[0][0]和a[0][1]的地址
在二维数组中,这时*改变了指针的性质,a+1等价为a[1][0]
而*a+1等价为a[0][1]
结论:a为行地址(二维数组中)
a+1等价为a[1][0] //一行一行移动
*a+1等价为a[0][1] //*降级,一个一个移动
行指针(数组指针)
格式:<存储类型> <数据类型> (*<指针变量名>)[];
例:int a[2][3];
int (*p)[3]; //后面的常量表达式必须一样;
方括号中的常量表达式表示指针加1,移动几个数据。
当用行指针操作二维数组时,表达式一般写成1行的元素个数,即列数。
例:int a[3][2]={{1,6},{9,12},{23,83}};
int (*p)[2];
p=a;
printf(%p %p\n”,a,a+1); //结果0xbff353e8 0xbff353f0 为a[1][0]和a[1][0]的地址
printf(%p %p\n”,p,p+1); //结果0xbff353e8 0xbff353f0 为a[1][0]和a[1][0]的地址
printf(%d %d\n”,a[1][1],p[1][1]; //12 12
//a[1][1]等价于*((*a+1)+1)
//p[1][1]等价于*((*p+1)+1)
字符指针与字符串
初始化字符指针是把内存中字符串的首地址赋予指针,并不是把该字符串复制到指针中
·char str[]=“hello world”, *p=str;
char ch=‘a’, *q=&ch;
printf(“%s %s \n”,p,q); //字符型获取内容不需要加*
//str[0]等价*(str+0)等价p[0]等价*(p+0)
在c编程中,当一个字符指针指向一个字符串常量时,不能修改指针指向的对象的值
·char *p=“hello world”;
*p=’h’; //错误,字符串常量不能修改
指针数组
所谓指针数组是指由若干个具有相同存储类型和数据类型的指针变量构成的集合。
格式:<存储类型> <数据类型> *<指针数组名> [<大小>]
例:int *p[3]; //p[0]、p[1]、p[2]
指针数组名表示该指针数组的起始地址。
例:声明一个指针数组:
double * pa[2], a[2][3];
把一维数组a[0]和a[1]的首地址分别赋予指针变量数组的数组元数pa[0]和pa[1]:
pa[0]=a[0]; //等价pa[0]=&a[0][0];
pa[1]=a[1]; //等价pa[1]=&a[1][0];
此时pa[0]指向了一维数组a[0]的第一个元素a[0][0],
而pa[1]指向了一维数组a[1]的第一个元素a[1][0].
初始化: 等价于:
int b[2][3]; int b[2][3];
int *pb[2]; int *pb[]={b[0],b[1]};
pb[0]=b[0];
pb[1]=b[1];
多级指针 L1-D7-5
把一个指向指针变量的指针变量,称为多级指针变量。
对于指向处理数据的指针变量称为一级指针变量,简称为一级指针。
而把指向一级指针,存储一级指针地址的变量的指针变量称为二级指针变量,简称二级指针。
格式:<存储类型> <数据类型> ** <指针名>;
例:int m=10;
int *p;
int **q;
p=&m; \\存储地址为指针,*p,加上m的数据类型int,声明:int *p;
q=&p; \\存储地址为指针,*q,加上p的数据类型 int *,声明:int **q;
printf(“%d %d %d \n”,m,*p,**q);
\\p存储m的地址,加*读出地址m上的内容
多级指针的运算 L1-D7-5
指针变量加1,是向地址大的方向移动一个目标数据。
比如:int **p;p+1移动一个int *变量所占的内存空间。再比如int ***p,p+1移动一个int **所占的内存空间
void指针 L1-D7-7
void指针是一种不确定数据类型的指针变量,它可以通过强制类型转换让该变量指向任何数据类型的变量。
注:void指针在没有强制类型转换之前,不能进行任何指针的算术运算。
格式:void * <指针变量名称>;
例:int m=10;
double n=3.14;
void *p, *q;
p=(void *)&m; \\(void *)也可去掉
printf(“%d %d\n”,m,*(int *)p);
q=(void *)&n; \\(void *)也可去掉
printf(“%.2ld %.2lf\n”,n,*(double *)q);
const变量
一般格式①:const <数据结构> 变量名 = [<表达式>];
常量化变量是为了使得变量的值不能修改。
例:const int m=10;
m++; 报错,此时m不能运算。
变量有const修饰时,若想用指针间接访问变量,指针也要有const修饰。
一般格式②:const <数据类型> * <指针变量名称> [=<指针运算表达式>]
常量化指针目标是限制通过指针改变其目标的数值,但<指针变量>存储的地址值可以修改
例:int m=10;
const int *p;
p=&m;
(*p)++; 报错,不能通过指针p修改m的值。
一般格式③:<数据格式> * const <指针变量名称> [=<指针运算表达式>]
使得<指针变量>存储的地址值不能修改。但可以通过*<指针变量名称>可以修改指针所指向变量的数值。
例:int m=10;
int * const q;
q=&m; 报错,不能赋值,只能在声明处赋值。如int * const q&m;
函数 L1-D8-1
函数是一个完成特定功能的代码模块,其程序代码独立,通常要求有返回值,也可以是空值。
一般形式如下:
<数据类型> <函数名称> (<形式参数说明>){
语言序列;
return[(<表达式>)];
}
例:double Power(double x,int n);
double Power(double,int);
注:<形式参数说明>可以缺省说明的变量名称,但类型不能缺省。
函数的使用也可叫函数的调用,形式如下:
函数名称 (<实际参数>)
注:实参就是在使用函数时,调用函数传递给被调用函数的数据。需要确切的数据。
函数程序举例:
定义求x^n值得函数(x是实数,n为正整数)
函数的参数传递
地址传递方式:按地址传递,实参为变量的地址,而形参为同类型的指针。
被调用函数中对形参的操作,将直接改变实参的值(被调用函数对指针的目标操作,相当于对实参本身的操作)
编写一个函数,统计字符串中小写字母的个数,并把字符串中的小写字母转化成大写字母。
函数的传参-数组 L1-D8-3
①全局数组传递方式
②复制传递方式
实参为数组的指针,形参为数组名(本质是一个指针变量)
③地址传递方式
实参为数组的指针,形参为同类型的指针变量
程序举例
编写函数,计算一个一维整形数组的所有元素的和
程序按例
编写函数,删除字符串中的空格
指针函数 L1-D9-1
指针函数是指一个函数的返回值为地址量的函数
一般形式:
<数据类型> * <函数名称> (<函数说明>){
语句序列
}
注:返回值只能返回全局变量的地址/static变量的地址/字符串常量的地址/堆的地址
在函数中的局部变量只要是返回类似 int[]、char[]、long[] 地址的,都是不正确的做法。
程序按例 L1-D9-2
编写一个指针函数,删除一个字符串中的空格。
编写一个指针函数,实现字符串连接。 L1-D9-2
编写一个指针函数,输入数字后用字符串输出。 L1-D9-3
递归函数
递归函数是指一个函数的函数体中直接或间接调用了该函数自身。
递归函数调用的执行过程分为两个阶段:
递推阶段:从原问题出发,按递归公式递推从未知到已知,最终达到递归终止条件
回归阶段:按递归终止条件求出结果,逆向逐步代入递归公式,回归到原问题求解
程序按例
求5的阶乘。
兔子在出生两个月后,就有繁殖能力,兔子每个月能出一对兔子。如果兔子不死,十个月有多少兔子。
函数指针 L1-D9-5
函数指针用来存放函数的地址,这个地址是一个函数的入口地址
函数名代表了函数的入口地址
函数指针变量说明的一般形式如下
<数据类型> (*<函数指针名称>) (<参数说明列表>);
例:int (*p) (int a,int b); \\a和b可省略
解:<数据类型>是函数指针所指向的函数的返回值类型
<参数说明列表>应该与函数指针所指向的函数的形参说明保持一致
(*<函数指针名称>)中,*说明为指针()不可缺省,表明为函数的指针
函数指针程序按例
函数指针数组
函数指针数组是一个保存若干个函数名的数组
一般形式如下
<数据类型> (*<函数指针数组名称> [<大小>] (<参数说明列表>)
例:int (* p[2]) (int, int);
GCC所支持的后缀
.c c原始程序
.C/.cc/.cxx c++原始程序
.h 预处理文件(头文件)
.i 已经过预处理的c原始程序
.ii 已经过预处理的c++原始程序
.s/.S 汇编语言原始程序
.o 目标文件
.a/.so 编译后的库文件
10.3学完
10.3学完