程序员考试补习Word文件下载.docx
- 文档编号:21106330
- 上传时间:2023-01-27
- 格式:DOCX
- 页数:15
- 大小:27.72KB
程序员考试补习Word文件下载.docx
《程序员考试补习Word文件下载.docx》由会员分享,可在线阅读,更多相关《程序员考试补习Word文件下载.docx(15页珍藏版)》请在冰豆网上搜索。
指针的类型,指针所指向的类型,指针的值或者叫指针所指向的内存区,还有指针本身所占据的内存区。
让我们分别说明.先声明几个指针放着做例子:
例一:
(1)int*ptr;
(2)char*ptr;
(3)int**ptr;
(4)int(*ptr)[3];
(5)int*(*ptr)[4];
如果看不懂后几个例子的话,请参阅我前段时间贴出的文?
lt;
<
如何理解c和c++的复杂类型声明>
>
。
指针的类型。
从语法的角度看,你只要把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。
这是指针本身所具有的类型。
让我们看看例一中各个指针的&
nbsp;
类型:
//指针的类型是int*
//指针的类型是char*
//指针的类型是int**
//指针的类型是int(*)[3]
//指针的类型是int*(*)[4]
怎么样?
找出指针的类型的方法是不是很简单?
指针所指向的类型。
当你通过指针来访问指针所指向的内存区时,指针所指向的类型决定了编译器将把那片内存区里的内容当做什么来看待.从语法上看,你只须把指针声明语句中的指针名字和名字左边的指针声明符*去掉,剩下的就是指针所指向的类型。
例如:
//指针所指向的类型是int
//指针所指向的的类型是char
//指针所指向的的类型是int*
//指针所指向的的类型是int()[3]
//指针所指向的的类型是int*()[4]
在指针的算术运算中,指针所指向的类型有很大的作用.指针的类型(即指针本身的类型)和指针所指向的类型是两个概念。
当你对C越来越熟悉时,你会发现,把与指针搅和在一起的"
类型"
这个概念分成"
指针的类型"
和"
指针所指向的类型"
两个概念,是精通指针的关键点之一。
我看了不少书,发现有些写得差的书中,就把指针的两个概念搅在一起了,所以看起书来前后矛盾,越看越糊涂。
指针的值,或者叫指针所指向的内存区或地址。
指针的值是指针本身存储的数值,这个值将被编译器当作一个地址,而不是一个一般的数值。
在32位程序里,所有类型的指针的值都是一个32位整数,因为32位程序里内存地址全都是32位长.指针所指向的内存区就是从指针的值所代表的那个内存地址开始,长度为sizeof(指针所指向的类型)的一片内存区。
以后,我们说一个指针的值是XX,就相当于说该指针指向了以XX为首地址的一片内存区域;
我们说一个指针指向了某块内存区域,就相当于说该指针的值是这块内存区域的首地址.指针所指向的内存区和指针所指向的类型是两个完全不同的概念。
在例一中,指针所指向的类型已经有了,但由于指针还未初始化,所以它所指向的内存区是不存在的,或者说是无意义的.以后,每遇到一个指针,都应该问问:
这个指针的类型是什么?
指针指向的类型是什么?
该指针指向了哪里?
4。
指针本身所占据的内存区。
指针本身占了多大的内存?
你只要用函数sizeof(指针的类型)测一下就知道了。
在32位平台里,指针本身占据了4个字节的长度。
指针本身占据的内存这个概念在判断一个指针表达式是否是左值时很有用。
第二章。
指针的算术运算
指针可以加上或减去一个整数。
指针的这种运算的意义和通常的数值的加减运算的意义是不一样的。
例二:
chara[20];
int*ptr=a;
...
ptr++;
在上例中,指针ptr的类型是int*,它指向的类型是int,它被初始化为指向整形变量a。
接下来的第3句中,指针ptr被加了1,编译器是这样处理的:
它把指针ptr的值加上了sizeof(int),在32位程序中,是被加上了4。
由于地址是用字节做单位的,故ptr所指向的地址由原来的变量a的地址向高地址方向增加了4个字节。
由于char类型的长度是一个字节,所以,原来ptr是指向数组a的第0号单元开始的四个字节,此时指向了数组a中从第4号单元开始的四个字节。
我们可以用一个指针和一个循环来遍历一个数组,看例子:
例三:
intarray[20];
int*ptr=array;
//此处略去为整型数组赋值的代码。
for(i=0;
i<
20;
i++)
{
(*ptr)++;
ptr++;
}
这个例子将整型数组中各个单元的值加1。
由于每次循环都将指针ptr加1,所以每次循环都能访问数组的下一个单元。
再看例子:
例四:
ptr+=5;
在这个例子中,ptr被加上了5,编译器是这样处理的:
将指针ptr的值加上5乘sizeof(int),在32位程序中就是加上了5乘4=20。
由于地址的单位是字节,故现在的ptr所指向的地址比起加5后的ptr所指向的地址来说,向高地址方向移动了20个字节。
在这个例子中,没加5前的ptr指向数组a的第0号单元开始的四个字节,加5后,ptr已经指向了数组a的合法范围之外了。
虽然这种情况在应用上会出问题,但在语法上却是可以的。
这也体现出了指针的灵活性。
如果上例中,ptr是被减去5,那么处理过程大同小异,只不过ptr的值是被减去5乘sizeof(int),新的ptr指向的地址将比原来的ptr所指向的地址向低地址方向移动了20个字节.
总结一下,一个指针ptrold加上一个整数n后,结果是一个新的指针ptrnew,ptrnew的类型和ptrold的类型相同,ptrnew所指向的类型和ptrold所指向的类型也相同。
ptrnew的值将比ptrold的值增加了n乘sizeof(ptrold所指向的类型)个字节。
就是说,ptrnew所指向的内存区将比ptrold所指向的内存区向高地址方向移动了n乘sizeof(ptrold所指向的类型)个字节.一个指针ptrold减去一个整数n后,结果是一个新的指针ptrnew,ptrnew的类型和ptrold的类型相同,ptrnew所指向的类型和ptrold所指向的类型也相同。
ptrnew的值将比ptrold的值减少了n乘sizeof(ptrold所指向的类型)个字节,就是说,ptrnew所指向的内存区将比ptrold所指向的内存区向低地址方向移动了n乘sizeof(ptrold所指向的类型)个字节。
第三章。
运算?
amp;
和*
这里&
是取地址运算符,*是...书上叫做"
间接运算符"
&
a的运算结果是一个指针,指针的类型是a的类型加个*,指针所指向的类型是a的类型,指针所指向的地址嘛,那就是a的地址。
*p的运算结果就五花八门了。
总之*p的结果是p所指向的东西,这个东西有这些特点:
它的类型是p指向的类型,它所占用的地址是p所指向的地址。
例五:
&
inta=12;
intb;
int*p;
int**ptr;
p=&
a;
//&
a的结果是一个指针,类型是int*,指向的类型是int,指向的地址是a的地址.*p=24;
//*p的结果,在这里它的类型是int,它所占用的地址是p所指向的地址,显然,*p就是变量a。
ptr=&
p;
p的结果是个指针,该指针的类型是p的类型加个*,在这里是int**。
该指针所指向的类型是p的类型,这里是int*。
该指针所指向的地址就是指针p自己的地址。
*ptr=&
b;
//*ptr是个指针,&
b的结果也是个指针,且这两个指针的类型和所指向的类型是一样的,所以用&
b来给*ptr赋值就是毫无问题的了。
**ptr=34;
//*ptr的结果是ptr所指向的东西,在这里是一个指针,对这个指针再做一次*运算,结果就是一个int类型的变量。
第四章。
指针表达式。
一个表达式的最后结果如果是一个指针,那么这个表达式就叫指针表达式。
下面是一些指针表达式的例子:
例六:
inta,b;
intarray[10];
int*pa;
pa=&
a是一个指针表达式。
int**ptr=&
pa;
pa也是一个指针表达式。
//*ptr和&
b都是指针表达式。
pa=array;
pa++;
//这也是指针表达式。
例七:
char*arr[20];
char**parr=arr;
//如果把arr看作指针的话,arr也是指针表达式
char*str;
str=*parr;
//*parr是指针表达式
str=*(parr+1);
//*(parr+1)是指针表达式
str=*(parr+2);
//*(parr+2)是指针表达式
由于指针表达式的结果是一个指针,所以指针表达式也具有指针所具有的四个要素:
指针的类型,指针所指向的类型,指针指向的内存区,指针自身占据的内存。
好了,当一个指针表达式的结果指针已经明确地具有了指针自身占据的内存的话,这个指针表达式就是一个左值,否则就不是一个左值。
在例七中,&
a不是一个左值,因为它还没有占据明确的内存。
*ptr是一个左值,因为*ptr这个指针已经占据了内存,其实*ptr就是指针pa,既然pa已经在内存中有了自己的位置,那么*ptr当然也有了自己的位置。
第五章。
数组和指针的关系
如果对声明数组的语句不太明白的话,请参阅我前段时间贴出的文?
数组的数组名其实可以看作一个指针。
看下例:
例八:
intarray[10]={0,1,2,3,4,5,6,7,8,9},value;
value=array[0];
//也可写成:
value=*array;
value=array[3];
value=*(array+3);
value=array[4];
value=*(array+4);
上例中,一般而言数组名array代表数组本身,类型是int[10],但如果把a
rray看做指针的话,它指向数组的第0个单元,类型是int*,所指向的类型是数
组单元的类型即int。
因此*array等于0就一点也不奇怪了。
同理,array+3是一个
指向数组第3个单元的指针,所以*(array+3)等于3。
其它依此类推。
例九:
char*str[3]={
"
Hello,thisisasample!
Hi,goodmorning."
Helloworld"
};
chars[80];
strcpy(s,str[0]);
//也可写成strcpy(s,*str);
strcpy(s,str[1]);
//也可写成strcpy(s,*(str+1));
strcpy(s,str[2]);
//也可写成strcpy(s,*(str+2));
上例中,str是一个三单元的数组,该数组的每个单元都是一个指针,这些指针各指向一个字符串。
把指针数组名str当作一个指针的话,它指向数组的第0号单元,它的类型是char**,它指向的类型是char*.*str也是一个指针,它的类型是char*,它所指向的类型是char,它指向的地址是字符串"
的第一个字符的地址,即’H’的地址。
str+1也是一个指针,它指向数组的第1号单元,它的类型是char**,它指向的类型是char*.*(str+1)也是一个指针,它的类型是char*,它所指向的类型是char,它指向"
的第一个字符’H’,等等。
下面总结一下数组的数组名的问题。
声明了一个数组TYPEarray[n],则数组名称array就有了两重含义:
第一,它代表整个数组,它的类型是TYPE[n];
第二,它是一个指针,该指针的类型是TYPE*,该指针指向的类型是TYPE,也就是数组单元的类型,该指针指向的内存区就是数组第0号单元,该指针自己占有单独的内存区,注意它和数组第0号单元占据的内存区是不同的。
该指针的值是不能修改的,即类似array++的表达式是错误的。
在不同的表达式中数组名array可以扮演不同的角色。
在表达式sizeof(array)中,数组名array代表数组本身,故这时sizeof函数测出的是整个数组的大小。
在表达式*array中,array扮演的是指针,因此这个表达式的结果就是数组第0号单元的值。
sizeof(*array)测出的是数组单元的大小。
表达式array+n(其中n=0,1,2,....。
)中,array扮演的是指针,故array+n的结果是一个指针,它的类型是TYPE*,它指向的类型是TYPE,它指向数组第n号单元。
故sizeof(array+n)测出的是指针类型的大小。
例十:
int(*ptr)[10];
array;
上例中ptr是一个指针,它的类型是int(*)[10],他指向的类型是int[10],我们用整个数组的首地址来初始化它。
在语句ptr=&
array中,array代表数组本身。
本节中提到了函数sizeof(),那么我来问一问,sizeof(指针名称)测出的究竟是指针自身类型的大小呢还是指针所指向的类型的大小?
答案是前者。
则在32位程序中,有:
n
程序员考试补课笔记-第十三天
今天特别的兴奋,起床也起得特别的早。
在走之前我把电脑开了,那当然是为了做服务器,我不知道我开学后能不能够这样做,因为家里的一些因素。
不过只要能为大家服务我已经很开心了,而且也一种强激的幸福感,这种幸福并不是一般的家庭幸福。
我为坚持做下去的,我也常常问一些网友关于这件事,他们都说只有你自己可以就行了,他们都支持我坚持做下去。
好吧,说远了离题了,我说说今天的补课吧。
今天的课程也令我吃了一惊,是讲数据结构里的树。
为什么队列和堆栈都没有讲就直接讲树呢?
会不会太快了一点,而且我们刚放完假有些人都没有集中精神到课堂来。
不过我会相信老师的选择的,应该有他的理由。
那么就来讲讲树的一些基本概念,大家都知道树是数据结构里的非线性结构之一,和之前说的链表是完全不同的,链表就只有前驱和后继结点,但树就不是了,他可以有很多的结点,称为分支结点,而且他的分支结点又可以有分支结点。
因为树接触到的概念太多了,只好自己看一下书才行。
树运用得很广范,像我们操作系统里文件管理就是了,多级的目录。
二级目录就像树的子树,而且子树里可能还有很多的子树,越往下就越多级。
我们来试试定义一个树的结构,一般树都分得很随意,所有我们这里也随便画一个树来说一下。
看图第十三天图一我们看到圆圈就代表一个结点,而且最顶的那个就是根结点,往下的就是子结点。
子结点的上一个就是父结点,同一级的结点左右都是为兄弟结点。
我们按照这样的结构定义一个,如下:
structtree
{
intdata;
structtree*next;
/*右兄弟结点*/
structtree*pre;
/*左兄弟结点*/
structtree*up;
/*父结点*/
structtree*down;
/*子结点*/
};
下面来看看如何建立一棵树。
structtree*p,*r;
r=(structtree*)malloc(sizeof(structtree));
/*建立根结点空间*/
r->
data=3;
/*根结点赋值*/
next=r->
pre=r->
up=NULL;
p=(structtree*)malloc(sizeof(structtree));
/*建立第二个结点*/
down=p;
/*根结点的子结点连向新的子结点*/
p->
data=5;
/*子结点赋值*/
pre=NULL;
next=(structtree*)malloc(sizeof(structtree));
next->
data=2;
pre=p;
:
因为结点多而无规律性,所有这种建立方法是不能采用的,现在只是拿出来研究一下一棵树是如何建立起来的。
现在说说另一种树“二叉树”。
因为二叉树与一般的树结构比较,二叉树在结构上更规范和更有确定性,因此,应用也比树更为广泛。
二叉树与树不同,首先二叉树可以为空,空的二叉树没有结点;
另外,在二叉树中,结点的子树是有序的,分左、右两棵子二叉树。
二叉树又是如何建立的呢?
这里很简单,因为二叉树有其规律性,下面请看
typedefstructbnode
struct&
nbs
bnode*left,*right;
}btree;
voidcreat(btree*b)
intx;
btree*s;
b=NULL;
do
scanf("
%d"
&
x);
s=(btree*)malloc(sizeof(btree));
s->
data=x;
left=s->
right=NULL;
insert(b,s);
}
voidinsert(btree*b,btree*s)
if(b==NULL)b=s;
elseif(s-data==b->
data)return();
elseif(s-data<
b->
data)insert(b->
left,s);
elseif(s-data>
right,s);
这条程序不单只建立了一个树,而且还给排好了序(左小右大)。
输入相应的数值看看结果,如图第十三天图二。
今天也就是这些了,还有得就是要多看些递归的程序,因为树的建立和操作离不开递归。
还有的就是大家做做如下一题,就是已知有一个无序的二叉树,让我们用中序遍历排列成由大到小的程序。
程序员考试补课笔记-第十四天
今天继续是讲二叉树,树一个重要的操作就是遍历。
所谓遍历就是输出所有的结点,二叉树不同于树只有前序和后序遍历,因为二叉树左右子树木特点,所有还有另一种遍历方法,就是中序。
这些遍历也十分简单,最主要的还是看根遍历的前后来分别是前中后序遍历的。
下面看图第十四天这些颜色圈着代表分别当一个树来看,所有我们知道其规律就可以写出程序来了,程序也十分简单,如下:
out1(btree*t)/*前序遍历*/
printf("
t->
data);
out1(t->
left);
right);
out2(btree*t)/*中序遍历*/
out2(t->
out3(btree*t)/*后序遍历*/
out3(t->
上面三种遍历是不是很简单(这个递归想一想就明白的了),而且他们很像似只是改变了行位置,我们由此可以看出如果是前序的那个输出是最先的,跟着才是进入左树到右树。
看完了遍历就看看二叉查找树,二叉查找树是这样的一种树,他的左结点都小于根,右结点都大于左结点。
有这么一种性质所以他的插入特别好办,用中序遍历的方法设计这个排序算法特别好,因为这个树本来就是这样排序下来的。
下面就来看看程序是如何实现的
insert(btree
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 程序员 考试 补习
