文档库 最新最全的文档下载
当前位置:文档库 › 关于堆栈的讲解(我见过的最经典的

关于堆栈的讲解(我见过的最经典的

关于堆栈的讲解(我见过的最经典的
关于堆栈的讲解(我见过的最经典的

一、预备知识—程序的内存分配

一个由c/C++编译的程序占用的内存分为以下几个部分

1、栈区(stack)—由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。

2、堆区(heap)—一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。

3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。- 程序结束后有系统释放

4、文字常量区—常量字符串就是放在这里的。程序结束后由系统释放

5、程序代码区—存放函数体的二进制代码。

二、例子程序

这是一个前辈写的,非常详细

//main.cpp

int a = 0; 全局初始化区

char *p1; 全局未初始化区

main()

{

int b; 栈

char s[] = "abc"; 栈

char *p2; 栈

char *p3 = "123456"; 123456\0在常量区,p3在栈上。

static int c =0;全局(静态)初始化区

p1 = (char *)malloc(10);

p2 = (char *)malloc(20);

分配得来得10和20字节的区域就在堆区。

strcpy(p1, "123456"); 123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。

}

二、堆和栈的理论知识

2.1申请方式

stack:

由系统自动分配。例如,声明在函数中一个局部变量int b; 系统自动在栈中为b开辟空间heap:

需要程序员自己申请,并指明大小,在c中malloc函数

如p1 = (char *)malloc(10);

在C++中用new运算符

如p2 = (char *)malloc(10);

但是注意p1、p2本身是在栈中的。

2.2

申请后系统的响应

栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。

2.3申请大小的限制

栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。

堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

2.4申请效率的比较:

栈由系统自动分配,速度较快。但程序员是无法控制的。

堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.

另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活。

2.5堆和栈中的存储内容

栈:在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。

当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。

堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。

2.6存取效率的比较

char s1[] = "aaaaaaaaaaaaaaa";

char *s2 = "bbbbbbbbbbbbbbbbb";

aaaaaaaaaaa是在运行时刻赋值的;

而bbbbbbbbbbb是在编译时就确定的;

但是,在以后的存取中,在栈上的数组比指针所指向的字符串(例如堆)快。

比如:

#i nclude

void main()

{

char a = 1;

char c[] = "1234567890";

char *p ="1234567890";

a = c[1];

a = p[1];

return;

}

对应的汇编代码

10: a = c[1];

00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh]

0040106A 88 4D FC mov byte ptr [ebp-4],cl

11: a = p[1];

0040106D 8B 55 EC mov edx,dword ptr [ebp-14h]

00401070 8A 42 01 mov al,byte ptr [edx+1]

00401073 88 45 FC mov byte ptr [ebp-4],al

第一种在读取时直接就把字符串中的元素读到寄存器cl中,而第二种则要先把指针值读到edx中,在根据edx读取字符,显然慢了。

2.7小结:

堆和栈的区别可以用如下的比喻来看出:

使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。

windows进程中的内存结构

在阅读本文之前,如果你连堆栈是什么多不知道的话,请先阅读文章后面的基础知识。

接触过编程的人都知道,高级语言都能通过变量名来访问内存中的数据。那么这些变量在内存中是如何存放的呢?程序又是如何使用这些变量的呢?下面就会对此进行深入的讨论。下文中的C语言代码如没有特别声明,默认都使用VC编译的release版。

首先,来了解一下C 语言的变量是如何在内存分部的。C 语言有全局变量(Global)、本地变量(Local),静态变量(Static)、寄存器变量(Regeister)。每种变量都有不同的分配方式。先来看下面这段代码:

#i nclude

int g1=0, g2=0, g3=0;

int main()

{

static int s1=0, s2=0, s3=0;

int v1=0, v2=0, v3=0;

//打印出各个变量的内存地址

printf("0x%08x\n",&v1); //打印各本地变量的内存地址

printf("0x%08x\n",&v2);

printf("0x%08x\n\n",&v3);

printf("0x%08x\n",&g1); //打印各全局变量的内存地址

printf("0x%08x\n",&g2);

printf("0x%08x\n\n",&g3);

printf("0x%08x\n",&s1); //打印各静态变量的内存地址

printf("0x%08x\n",&s2);

printf("0x%08x\n\n",&s3);

return 0;

}

编译后的执行结果是:

0x0012ff78

0x0012ff7c

0x0012ff80

0x004068d0

0x004068d4

0x004068d8

0x004068dc

0x004068e0

0x004068e4

输出的结果就是变量的内存地址。其中v1,v2,v3是本地变量,g1,g2,g3是全局变量,s1,s2,s3是静态变量。你可以看到这些变量在内存是连续分布的,但是本地变量和全局变量分配的内存地址差了十万八千里,而全局变量和静态变量分配的内存是连续的。这是因为本地变量和全局/静态变量是分配在不同类型的内存区域中的结果。对于一个进程的内存空间而言,可以在逻辑上分成3个部份:代码区,静态数据区和动态数据区。动态数据区一般就是“堆栈”。“栈(stack)”和“堆(hea p)”是两种不同的动态数据区,栈是一种线性结构,堆是一种链式结构。进程的每个线程都有私有的“栈”,所以每个线程虽然代码一样,但本地变量的数据都是互不干扰。一个堆栈可以通过“基地址”和“栈顶”地址来描述。全局变量和静态变量分配在静态数据区,本地变量分配在动态数据区,即堆栈中。程序通过堆栈的基地址和偏移量来访问本地变量。

├———————┤低端内存区域

│ …… │

├———————┤

│ 动态数据区│

├———————┤

│ …… │

├———————┤

│ 代码区│

├———————┤

│ 静态数据区│

├———————┤

│ …… │

├———————┤高端内存区域

堆栈是一个先进后出的数据结构,栈顶地址总是小于等于栈的基地址。我们可以先了解一下函数调用的过程,以便对堆栈在程序中的作用有更深入的了解。不同的语言有不同的函数调用规定,这些因素有参数的压入规则和堆栈的平衡。windows API的调用规则和ANSI C的函数调用规则是不一样的,前者由被调函数调整堆栈,后者由调用者调整堆栈。两者通过“__stdcall”和“__cdecl”前缀区分。先看下面这段代码:

#i nclude

void __stdcall func(int param1,int param2,int param3)

{

int var1=param1;

int var2=param2;

int var3=param3;

printf("0x%08x\n",?m1); //打印出各个变量的内存地址

printf("0x%08x\n",?m2);

printf("0x%08x\n\n",?m3);

printf("0x%08x\n",&var1);

printf("0x%08x\n",&var2);

printf("0x%08x\n\n",&var3);

return;

}

int main()

{

func(1,2,3);

return 0;

}

编译后的执行结果是:

0x0012ff78

0x0012ff7c

0x0012ff80

0x0012ff68

0x0012ff6c

0x0012ff70

├———————┤<—函数执行时的栈顶(ESP)、低端内存区域│ …… │

├———————┤

│ var 1 │

├———————┤

│ var 2 │

├———————┤

│ var 3 │

├———————┤

│ RET │

├———————┤<—“__cdecl”函数返回后的栈顶(ESP)

│ parameter 1 │

├———————┤

│ parameter 2 │

├———————┤

│ parameter 3 │

├———————┤<—“__stdcall”函数返回后的栈顶(ESP)

│ …… │

├———————┤<—栈底(基地址EBP)、高端内存区域

上图就是函数调用过程中堆栈的样子了。首先,三个参数以从又到左的次序压入堆栈,先压“param3”,再压“param2”,最后压入“param1”;然后压入函数的返回地址(RET),接着跳转到函数地址接着执行(这里要补充一点,介绍UNIX下的缓冲溢出原理的文章中都提到在压入RET后,继续压入当前EBP,然后用当前ESP代替EBP。然而,有一篇介绍windows

下函数调用的文章中说,在windows下的函数调用也有这一步骤,但根据我的实际调试,并未发现这一步,这还可以从param3和var1之间只有4字节的间隙这点看出来);第三步,将栈顶(ESP)减去一个数,为本地变量分配内存空间,上例中是减去12字节(ESP=ESP-3*4,每个int变量占用4个字节);接着就初始化本地变量的内存空间。由于“__stdcall”调用由被调函数调整堆栈,所以在函数返回前要恢复堆栈,先回收本地变量占用的内存(ESP=ESP+3*4),然后取出返回地址,填入EIP寄存器,回收先前压入参数占用的内存(ESP=ESP+3*4),继续执行调用者的代码。参见下列汇编代码:

;--------------func 函数的汇编代码-------------------

:00401000 83EC0C sub esp, 0000000C //创建本地变量的内存空间

:00401003 8B442410 mov eax, dword ptr [esp+10]

:00401007 8B4C2414 mov ecx, dword ptr [esp+14]

:0040100B 8B542418 mov edx, dword ptr [esp+18]

:0040100F 89442400 mov dword ptr [esp], eax

:00401013 8D442410 lea eax, dword ptr [esp+10]

:00401017 894C2404 mov dword ptr [esp+04], ecx

……………………(省略若干代码)

:00401075 83C43C add esp, 0000003C ;恢复堆栈,回收本地变量的内存空间

:00401078 C3 ret 000C ;函数返回,恢复参数占用的内存空间

;如果是“__cdecl”的话,这里是“ret”,堆栈将由调用者恢复

;-------------------函数结束-------------------------

;--------------主程序调用func函数的代码--------------

:00401080 6A03 push 00000003 //压入参数param3

:00401082 6A02 push 00000002 //压入参数param2

:00401084 6A01 push 00000001 //压入参数param1

:00401086 E875FFFFFF call 00401000 //调用func函数

;如果是“__cdecl”的话,将在这里恢复堆栈,“add esp, 0000000C”

聪明的读者看到这里,差不多就明白缓冲溢出的原理了。先来看下面的代码:

#i nclude

#i nclude

void __stdcall func()

{

char lpBuff[8]="\0";

strcat(lpBuff,"AAAAAAAAAAA");

return;

}

int main()

{

func();

return 0;

}

编译后执行一下回怎么样?哈,“"0x00414141"指令引用的"0x00000000"内存。该内存不能为"read"。”,“非法操作”喽!"41"就是"A"的16进制的ASCII码了,那明显就是strcat这句出的问题了。"lpBuff"的大小只有8字节,算进结尾的\0,那strcat最多只能写入7个"A",但程序实际写入了11个"A"外加1个\0。再来看看上面那幅图,多出来的4个字节正好覆盖了RET 的所在的内存空间,导致函数返回到一个错误的内存地址,执行了错误的指令。如果能精心构造这个字符串,使它分成三部分,前一部份仅仅是填充的无意义数据以达到溢出的目的,接着是一个覆盖RET的数据,紧接着是一段shellcode,那只要着个RET地址能指向这段shellcode的第一个指令,那函数返回时就能执行shellcode了。但是软件的不同版本和不同的运行环境都可能影响这段shellcode在内存中的位置,那么要构造这个RET是十分困难的。一般都在RET和shellcode之间填充大量的NOP指令,使得exploit有更强的通用性。

├———————┤<—低端内存区域

│ …… │

├———————┤<—由exploit填入数据的开始

│ │

│ buffer │<—填入无用的数据

│ │

├———————┤

│ RET │<—指向shellcode,或NOP指令的范围

├———————┤

│ NOP │

│ …… │<—填入的NOP指令,是RET可指向的范围

│ NOP │

├———————┤

│ │

│ shellcode │

│ │

├———————┤<—由exploit填入数据的结束

│ …… │

├———————┤<—高端内存区域

windows下的动态数据除了可存放在栈中,还可以存放在堆中。了解C++的朋友都知道,C++可以使用new关键字来动态分配内存。来看下面的C++代码:

#i nclude

#i nclude

#i nclude

void func()

{

char *buffer=new char[128];

char bufflocal[128];

static char buffstatic[128];

printf("0x%08x\n",buffer); //打印堆中变量的内存地址

printf("0x%08x\n",bufflocal); //打印本地变量的内存地址

printf("0x%08x\n",buffstatic); //打印静态变量的内存地址

}

void main()

{

func();

return;

}

程序执行结果为:

0x004107d0

0x0012ff04

0x004068c0

可以发现用new关键字分配的内存即不在栈中,也不在静态数据区。VC编译器是通过windows下的“堆(heap)”来实现new关键字的内存动态分配。在讲“堆”之前,先来了解一下和“堆”有关的几个API函数:

HeapAlloc 在堆中申请内存空间

HeapCreate 创建一个新的堆对象

HeapDestroy 销毁一个堆对象

HeapFree 释放申请的内存

HeapWalk 枚举堆对象的所有内存块

GetProcessHeap 取得进程的默认堆对象

GetProcessHeaps 取得进程所有的堆对象

LocalAlloc

GlobalAlloc

当进程初始化时,系统会自动为进程创建一个默认堆,这个堆默认所占内存的大小为1M。堆对象由系统进行管理,它在内存中以链式结构存在。通过下面的代码可以通过堆动态申请内存空间:

HANDLE hHeap=GetProcessHeap();

char *buff=HeapAlloc(hHeap,0,8);

其中hHeap是堆对象的句柄,buff是指向申请的内存空间的地址。那这个hHeap究竟是什么呢?它的值有什么意义吗?看看下面这段代码吧:

#pragma comment(linker,"/entry:main") //定义程序的入口

#i nclude

_CRTIMP int (__cdecl *printf)(const char *, ...); //定义STL函数printf

/*---------------------------------------------------------------------------

写到这里,我们顺便来复习一下前面所讲的知识:

(*注)printf函数是C语言的标准函数库中函数,VC的标准函数库由msvcrt.dll模块实现。由函数定义可见,printf的参数个数是可变的,函数内部无法预先知道调用者压入的参数个数,函数只能通过分析第一个参数字符串的格式来获得压入参数的信息,由于这里参数的个数是动态的,所以必须由调用者来平衡堆栈,这里便使用了__cdecl调用规则。BTW,Windows 系统的API函数基本上是__stdcall调用形式,只有一个API例外,那就是wsprintf,它使用__cdecl调用规则,同printf函数一样,这是由于它的参数个数是可变的缘故。

---------------------------------------------------------------------------*/

void main()

{

HANDLE hHeap=GetProcessHeap();

char *buff=HeapAlloc(hHeap,0,0x10);

char *buff2=HeapAlloc(hHeap,0,0x10);

HMODULE hMsvcrt=LoadLibrary("msvcrt.dll");

printf=(void *)GetProcAddress(hMsvcrt,"printf");

printf("0x%08x\n",hHeap);

printf("0x%08x\n",buff);

printf("0x%08x\n\n",buff2);

}

执行结果为:

0x00130000

0x00133100

0x00133118

hHeap的值怎么和那个buff的值那么接近呢?其实hHeap这个句柄就是指向HEAP首部的地址。在进程的用户区存着一个叫PEB(进程环境块)的结构,这个结构中存放着一些有关进程的重要信息,其中在PEB首地址偏移0x18处存放的ProcessHeap就是进程默认堆的地址,而偏移0x90处存放了指向进程所有堆的地址列表的指针。windows有很多API都使用进程的默认堆来存放动态数据,如windows 2000下的所有ANSI版本的函数都是在默认堆中申请内存来转换ANSI字符串到Unicode字符串的。对一个堆的访问是顺序进行的,同一时刻只能有一个线程访问堆中的数据,当多个线程同时有访问要求时,只能排队等待,这样便造成程序执行效率下降。

最后来说说内存中的数据对齐。所位数据对齐,是指数据所在的内存地址必须是该数据长度的整数倍,DWORD数据的内存起始地址能被4除尽,WORD数据的内存起始地址能被2除尽,x86 CPU能直接访问对齐的数据,当他试图访问一个未对齐的数据时,会在内部进行一系列的调整,这些调整对于程序来说是透明的,但是会降低运行速度,所以编译器在编译程序时会尽量保证数据对齐。同样一段代码,我们来看看用VC、Dev-C++和lcc三个不同编译器编译出来的程序的执行结果:

#i nclude

int main()

{

int a;

char b;

int c;

printf("0x%08x\n",&a);

printf("0x%08x\n",&b);

printf("0x%08x\n",&c);

return 0;

}

这是用VC编译后的执行结果:

0x0012ff7c

0x0012ff7b

0x0012ff80

变量在内存中的顺序:b(1字节)-a(4字节)-c(4字节)。

这是用Dev-C++编译后的执行结果:

0x0022ff7c

0x0022ff7b

0x0022ff74

变量在内存中的顺序:c(4字节)-中间相隔3字节-b(占1字节)-a(4字节)。

这是用lcc编译后的执行结果:

0x0012ff6c

0x0012ff6b

0x0012ff64

变量在内存中的顺序:同上。

三个编译器都做到了数据对齐,但是后两个编译器显然没VC“聪明”,让一个char占了4字节,浪费内存哦。

基础知识:

堆栈是一种简单的数据结构,是一种只允许在其一端进行插入或删除的线性表。允许插入或删除操作的一端称为栈顶,另一端称为栈底,对堆栈的插入和删除操作被称为入栈和出栈。有一组CPU指令可以实现对进程的内存实现堆栈访问。其中,POP指令实现出栈操作,PUSH 指令实现入栈操作。CPU的ESP寄存器存放当前线程的栈顶指针,EBP寄存器中保存当前线程的栈底指针。CPU的EIP寄存器存放下一个CPU指令存放的内存地址,当CPU执行完当前的指令后,从EIP寄存器中读取下一条指令的内存地址,然后继续执行。

(完整版)初中英语定语从句讲解教师版

初中英语定语从句讲解及练习(教师版) 一.定语从句及相关术语 1.定语从句:修饰一个名词或代词的从句称为定语从句,一般紧跟在它所修饰的先行词后面。 2.关系词:引导定语从句的关联词成为关系词 关系词有关系代词和关系副词。关系代词有that, which, who, whom, whose, as 等; 关系副词有where, when, why等。 关系词常有3个作用:1,引导定语从句。2,代替先行词。3,在定语从句中担当一个成分。 二.关系代词引导的定语从句 1.who指人,在从句中做主语 (1) the boys who are playing football are from class one. (2) yesterday i helped an old man who lost his way. 2. whom指人,在定语从句中充当宾语,常可省略。 (1) mr. liu is the person (whom) you talked about on the bus. (2) mr. ling is just the boy whom i want to see. 注意:关系代词whom在口语和非正式语体中常用who代替,可省略。 (3) the man who/whom you met just now is my friend. 3. which指物,在定语从句中做主语或者宾语,做宾语时可省略 (1) football is a game which is liked by most boys. (2) this is the pen (which) he bought yesterday. 4. that指人时,相当于who 或者whom;指物时,相当于which。在宾语从句中做主语或者宾语,做宾语时可省略。 (5) the number of the people that/who come to visit the city each year rises one million. (6) where is the man that/whom i saw this morning? 5. whose通常指人,也可指物,在定语从句中做定语 (1) he has a friend whose father is a doctor. (2) i once lived in a house whose roof has fallen in. whose指物时,常用以下结构来代替 (3) the classroom whose door is broken will soon be repaired. (4) the classroom the door of which is broken will soon be repaired. (5) do you like the book whose cover is yellow? (6) do you like the book the color of which is yellow? 三.介词+关系代词引导的定语从句 关系代词在定语从句中做介词宾语时,从句常由介词+关系代词引导 (1) the school (that/which) he once studied in is very famous. (2) the school in which he once studied is very famous. (3) tomorrow i will bring here a magazine (that/which) you asked for. (4) tomorrow i will bring here a magazine for which you asked. (5) we'll go to hear the famous singer (whom/that/who) we have often talked about. (6) we'll go to hear the famous singer about whom we have often talked. 注意:1. 含有介词的动词短语一般不拆开使用,如:look for, look after, take care

内存分配 堆栈

一个由C/C++编译的程序占用的内存分为以下几个部分 1、栈区(stack)—由编译器自动分配释放,存放函数的参数值,局部变量的值等。其 操作方式类似于数据结构中的栈。 2、堆区(heap)—一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。 3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后由系统释放。 4、文字常量区—常量字符串就是放在这里的。程序结束后由系统释放 5、程序代码区—存放函数体的二进制代码。 二、例子程序 这是一个前辈写的,非常详细 //main.cpp int a = 0; 全局初始化区 char *p1; 全局未初始化区 main() { int b; 栈 char s[] = "abc"; 栈 char *p2; 栈 char *p3 = "123456"; 123456\0在常量区,p3在栈上。 static int c =0;全局(静态)初始化区 p1 = (char *)malloc(10); p2 = (char *)malloc(20); 分配得来得10和20字节的区域就在堆区。 strcpy(p1, "123456"); 123456\0放在常量区,编译器可能会将它与p3所指向的"123456" 优化成一个地方。 } 二、堆和栈的理论知识 2.1申请方式 stack: 由系统自动分配。例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间 heap: 需要程序员自己申请,并指明大小,在c中malloc函数 如p1 = (char *)malloc(10); 在C++中用new运算符 如p2 = new char[10]; 但是注意p1、p2本身是在栈中的。

(完整版)定语从句超详细讲解

定语从句 一学习目标 1.熟练掌握定语从句 二考点解析 ⊙定从的功能—解释说明 This is the factory that/which can produce such machines 这就是能制造这种机器的工厂This is the factory that/which we visited last week 这就是我们上周参观的工厂 ⊙定语从句 定义:一个简单句跟在名词或代词后(先行词)进行修饰限定,就叫做定语从句。这个简单句在主句中充当定语成分。 I bought a cow that looked like a horse. ⊙定语从句怎么考? 语法 22.I live next door to a couple children often make a lot of noise.(2016高考北京卷) A.whose B.why C.where D.which 完形 Balto put his nose to the ground, 52 to find the smell of other dogs that had traveled on the trail. (2016高考北京卷) 阅读&写作 A nurse who understands the healing(治愈) value of silence can use this understanding to assist in the care of patients from their own and from other cultures.(2016高考全国卷D篇) Last year, I spent all my time looking for a job where, without dealing with the public , I could work alone, but still have a team to talk to. (2016高考北京卷阅读A篇) ⊙定从原理:把两个句子合为一个,两个句子有相同的部分,此时可以把其中一个句子作为另一个句子的修饰限定部分。

堆栈及静态数据区详解

堆、栈及静态数据区详解 五大内存分区 在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。 栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区。里面的变量通常是局部变量、函数参数等。 堆,就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。 自由存储区,就是那些由malloc等分配的内存块,他和堆是十分相似的,不过它是用free 来结束自己的生命的。 全局/静态存储区,全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。 常量存储区,这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改,而且方法很多) 明确区分堆与栈 在bbs上,堆与栈的区分问题,似乎是一个永恒的话题,由此可见,初学者对此往往是混淆不清的,所以我决定拿他第一个开刀。 首先,我们举一个例子: void f() { int* p=new int[5]; } 这条短短的一句话就包含了堆与栈,看到new,我们首先就应该想到,我们分配了一块堆内存,那么指针p呢?他分配的是一块栈内存,所以这句话的意思就是:在栈内存中存放了一个指向一块堆内存的指针p。在程序会先确定在堆中分配内存的大小,然后调用operator new分配内存,然后返回这块内存的首地址,放入栈中,他在VC6下的汇编代码如下: 00401028 push 14h 0040102A call operator new (00401060) 0040102F add esp,4 00401032 mov dword ptr [ebp-8],eax 00401035 mov eax,dword ptr [ebp-8]

仓库储位管理的方法与步骤详解

仓库储位管理的方法与步骤详解 1 什么是储位管理 现代仓储管理与传统的仓储管理相比,更加注重仓储的时效性,是一种动态的管理,重视商品在拣货出库时的数量位置变化,从而配合其他仓储作业。储位管理就是利用储位来使商品处于“被保管状态”并且能够明确显示所储存的位置,同时当商品的位置发生变化时能够准确记录,使管理者能够随时掌握商品的数量、位置,以及去向。 2 储位管理的对象 储位管理的对象,分为保管商品和非保管商品两部分。 1、保管商品 保管商品是指在仓库的储存区域中的保管商品,由于它对作业、储放搬运、拣货等方面有特殊要求,使得其在保管时会有很多种的保管形态出现,例如托盘、箱、散货或其它方式,这些虽然在保管单位上有很大差异,但都必须用储位管理的方式加以管理。 2、非保管商品 1)包装材料。包装材料就是一些标签、包装纸等包装材料。由于现在商业企业促销、特卖及赠品等活动的增加,使得仓库的贴标、重新包装、组合包装等流通加工比例增加,对于包装材料的需求就愈大,就必须对这些材料加以管理,如果管理不善,欠缺情况发生,影响到整个作业的进行。 2)辅助材料。辅助材料就是一些托盘、箱、容器等搬运器具。目前由于流通器具的标准化,使得仓库对这些辅助材料的需求愈来愈大,依赖也愈来愈重。为了不影响商品的搬运,就必须对这些辅助材料进行管理,制订了专门的管理办法。 3)回收材料。回收材料就是经补货或拣货作业拆箱后剩下的空纸箱。虽然这些空纸箱都可回收利用,但是这些纸箱形状不同,大小不一,若不保管起来,很容易造成混乱,而影响其它作业,就必须划分一些特定储位来对这些回收材料进行管理。 3 储位管理的范围 在仓库的所有作业中,所用到的保管区域均是储位管理的范围,根据作业方式不同分为:预备储区、保管储区、动管储区。现分别介绍如下: 1、预备储区 预备储区是商品进出仓库时的暂存区,预备进入下一保管区域,虽然商品在此区域停留的时间不长,但是也不能在管理上疏忽大意,给下一作业程序带来麻烦。

(完整版)高中英语定语从句讲解及练习

高中英语定语从句讲解及练习 定语从句是高中重点知识,也是高考常考点,大家也不容易掌握,这篇文章主要教你关系代词引导的定语从句 关系副词引导的定语从句判断关系代词与关系副词限制性和非限制性定语从句等内容,有例题讲解定语从句在句中做定语,修饰一个名词或代词,被修饰的名词词组或代词即先行词。定语从句通常出现在先行词之后,由关系词(关系代词或关系副词)引出。 关系代词有:who, whom, whose, that, which等。 关系副词有:when, where, why等。 18.1 关系代词引导的定语从句 关系代词所代替的先行词是人或物的名词或代词,并在句中充当主语、宾语、定语等成分。关系代词在定语从句中作主语时,从句谓语动词的人称和数要和先行词保持一致。 1)who, whom, that 这些词代替的先行词是人的名词或代词,在从句中作主语和宾语。例如: Is he the man who/that wants to see you? 他就是你想见的人吗?(who/that在从句中作主语) He is the man whom/ that I saw yesterday. 他就是我昨天见的那个人。(whom/that在从句中作宾语) 2)whose 用来指人或物,(只用作定语, 若指物,它还可以同of which互换)。例如: They rushed over to help the man whose car had broken down.那人车坏了,大家都跑过去帮忙。 Please pass me the book whose (of which)cover is green.请递给我那本绿皮的书。 3)which, that所代替的先行词是事物的名词或代词,在从句中可作主语、宾语等。例如: A prosperity which / that had never been seen before appears in the countryside. 农村出现了前所未有的繁荣。(which / that在句中作宾语) The package (which / that)you are carrying is about to come unwrapped. 你拿的包快散了。(which / that在句中作宾语) 18.2 关系副词引导的定语从句 关系副词可代替的先行词是时间、地点或理由的名词,在从句中作状语。 1)关系副词when, where, why的含义相当于\"介词+ which\"结构,因此常常和\"介词+ which\"结构交替使用。例如: There are occasions when (on which)one must yield.任何人都有不得不屈服的时候。 Beijing is the place where(in which)I was born.北京是我的出生地。 Is this the reason why (for which)he refused our offer?这就是他拒绝我们帮助他的理由吗? 2)that代替关系副词,可以用于表示时间、地点、方式、理由的名词后取代when, where, why和\"介+which\"引导的定语从句,在口语中that常被省略。例如: His father died the year (that / when / in which)he was born.他父亲在他出生那年逝世了。 He is unlikely to find the place (that / where / in which)he lived forty years ago. 他不大可能找到他四十年前居住过的地方。 18.3 判断关系代词与关系副词 方法一:用关系代词,还是关系副词完全取决于从句中的谓语动词。及物动词后面无宾语,就必须要求用关系代词;而不及物动词则要求用关系副词。例如: This is the mountain village where I stayed last year. 这是我去年呆过的山村。 I'll never forget the days when I worked together with you.我永远不会忘记与你共事的日子。 判断改错: (错)This is the mountain village where I visited last year. (错)I will never forget the days when I spent in the countryside. (对)This is the mountain village (which)I visited last year. (对)I'll never forget the days (which)I spent in the countryside. 习惯上总把表地点或时间的名词与关系副词where, when联系在一起。此两题错在关系词的误用上。 方法二:准确判断先行词在定语从句中的成分(主、谓、宾、定、状),也能正确选择出关系代词/关

关于堆栈的讲解(我见过的最经典的

一、预备知识—程序的内存分配 一个由c/C++编译的程序占用的内存分为以下几个部分 1、栈区(stack)—由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。 2、堆区(heap)—一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。 3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。- 程序结束后有系统释放 4、文字常量区—常量字符串就是放在这里的。程序结束后由系统释放 5、程序代码区—存放函数体的二进制代码。 二、例子程序 这是一个前辈写的,非常详细 //main.cpp int a = 0; 全局初始化区 char *p1; 全局未初始化区 main() { int b; 栈 char s[] = "abc"; 栈 char *p2; 栈 char *p3 = "123456"; 123456\0在常量区,p3在栈上。 static int c =0;全局(静态)初始化区 p1 = (char *)malloc(10); p2 = (char *)malloc(20); 分配得来得10和20字节的区域就在堆区。 strcpy(p1, "123456"); 123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。 } 二、堆和栈的理论知识 2.1申请方式 stack: 由系统自动分配。例如,声明在函数中一个局部变量int b; 系统自动在栈中为b开辟空间heap: 需要程序员自己申请,并指明大小,在c中malloc函数 如p1 = (char *)malloc(10); 在C++中用new运算符 如p2 = (char *)malloc(10); 但是注意p1、p2本身是在栈中的。

高一英语定语从句讲解精华版

定语从句 一、基本概念: 定语: 定语从句: Do you know the man who spoke at the meeting just now That is the house where he lived ten years ago. 引导词:关系词 关系代词有:that, who, whom, whose, which; 在从句中充当: 关系副词有:when, where, why. 在从句充当: 先行词: 定语从句中引关系词的作用: 二、关系词的用法: (一)关系代词的用法: 1. He is the man lives next door. The train has just left is for Shenzhen. 2. The man ________ we have just seen is a famous writer. Where is the book ___________I bought last week (二)关系副词的用法: 1. I still remember the time ________I first became a college student. Do you know the date __________Lincoln was born

(三) 使用关系副词应注意下列几点: 1.这三个关系副词在意义上都相当于一定的介词+which结构: when = on (in, at, during…) + which; where = in (at, on…) + which; why = for which. 如: I was in Beijing on the day when (=on which) he arrived. The office where (=in which) he works is on the third floor. This is the chief reason why (=for which) we did it. 2.当先行词是表时间的time, day等和表地点的place, house等时,一定要注意分析从句的结构,如果缺少主语或宾语时,关系词应该用which或that, 缺少时间状语或地点状语时,才能用when或where,试比较: I’ll never forget the day _________ my hometown was liberated. I’ll never forget the days____________we spent together last summer. His father works in a factory____________radio parts are made. His father works in a factory______________makes radio parts. 三.限制性定语从句与非限制性定语从句 1.限制性定语从句 This is the telegram which he refers to. Is there anything (that) I can do for you 2.非限制性定语从句 This note was left by Tom, who was here a moment ago. As a boy, he was always making things, most of which were electric.

堆栈详解(数据与内存中的存储方式)

堆栈详解(数据与内存中的存储方式) char* r = "hello word!";char b[]="hello word!"*r = 'w';*b='w';其实应该是语法错误,可是VC++6.0没有警告或者错误,r指向的是文字常量区,此区域是编译的时候确定的,并且程序结束的时候自动释放的,*r = 'w';企图修改文字常量区引起错误,b的区别在于其空间是在栈上分配的,因此没有错误。const char* r = "hello word!";*r = 'w';一个由 c/C++编译的程序占用的内存分为以下几个部分1、栈区(stack)—由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。2、堆区(heap)—一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。- 程序结束后有系统释放4、文字常量区—常量字符串就是放在这里的。程序结束后由系统释放5、程序代码区—存放函数体的二进制代码。二、例子程序//main.cppint a = 0; 全局初始化区char *p1; 全局未初始化区main(){int b; 栈char s[] = "abc"; 栈char *p2; 栈char *p3 = "123456"; 123456\0在常量区,p3

在栈上。static int c =0;全局(静态)初始化区p1 = (char *)malloc(10);p2 = (char *)malloc(20);分配得来得10和20字节的区域就在堆区。strcpy(p1, "123456"); 123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。}二、堆和栈的理论知识2.1申请方式stack:由系统自动分配。例如,声明在函数中一个局部变量int b; 系统自动在栈中为b开辟空间heap:需要程序员自己申请,并指明大小,在c中malloc函数如p1 = (char *)malloc(10);在C++中用new运算符如p2 = (char *)malloc(10);但是注意p1、p2本身是在栈中的。 2.2申请后系统的响应栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。2.3申请大小的限制栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的

高中定语从句详细讲解精编版

高中定语从句详细讲解 精编版 -CAL-FENGHAI-(2020YEAR-YICAI)_JINGBIAN

高中定语从句详细讲解 (一)定义及相关术语 1.定语从句:修饰某一名词或代词的从句叫定语从句。定语从句一般紧跟在它所修饰的先行词之后。 2.先行词:被定语从句修饰的词叫先行词。 3.关系词:引导定语从句的词叫关系词。 关系词有关系代词和关系副词。关系代词有that, which, who, whom, whose, as等;关系副词有when, where, why等。 关系词通常有下列三个作用:A、引导定语从句;B、代替先行词;C、在定语从句中担当一个成分。例如: The man who is shaking hands with my father is a policeman. 该句中,who is shaking hands with my father 是定语从句,修饰先行词the man,“who”是引导定语从句的关系词,代替先行词the man,在定语从句中作主语。 (二)关系代词引导的定语从句 1.who 指人,在定语从句中作主语。 The boys who are playing football are from Class One. 正在踢足球的男孩是一班的。 Those who want to go to the museum must be at the school gate at 7 tomorrow morning. 想去博物馆的人必须在明晨7点到大门口集合。Yesterday I helped an old man who had lost his way. 昨天我帮助了一位迷路的老人。 That is the teacher who teaches us physics. 那就是教我们物理的老师。 2.whom 指人,在定语从句中做宾语,常可省略。 Mr Liu is the person ( whom ) you talked about on the bus. 刘先生就是你们在公共汽车上谈论的那个人。 Li Ming is just the boy ( whom ) I want to see. 李明正是我想要见的男孩。 The professor ( whom ) you are waiting for has come. 你正在等的教授已经来了。 The girl ( whom ) the teacher often praises is our monitor. 老师经常表扬的那个女孩是我们的班长。 注意:关系代词whom 在口语或非正式文体中常可用who 来代替,也可省略。 The man ( whom / who )you met just now is my old friend. 3.Which 指物,在定语从句中做主语或宾语,做宾语时常可省略。 Football is a game which is liked by most boys. 足球是大多数男孩所喜欢的运动。 The factory which makes computers is far away from here. 制造计算机的那家公司离这儿很远。 He likes to read books which are written by foreign writers. 他喜欢外国作家写的书。

局部变量、全局变量、堆、堆栈、静态和全局

局部变量、全局变量、堆、堆栈、静态和全局【】 预备知识—程序的内存分配 一个由C/C++编译的程序占用的内存分为以下几个部分 ?栈区(stack)—由编译器自动分配释放,存放函数的参数值,局部变量的值等。 其操作方式类似于数据结构中的栈。 ?堆区(heap)—一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。 ?全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量、未初始化的静态变量在相邻的另一块区域。- 程序结束后有系统释放 ?文字常量区—常量字符串就是放在这里的。程序结束后由系统释放 ?程序代码区—存放函数体的二进制代码。 一个正常的程序在内存中通常分为程序段、数据端、堆栈三部分。程序段里放着程序的机器码、只读数据,这个段通常是只读,对它的写操作是非法的。数据段放的是程序中的静态数据。动态数据则通过堆栈来存放。 在内存中,它们的位置如下: +------------------+ 内存低端 | 程序段| |------------------| | 数据段| |------------------| | 堆栈| +------------------+ 内存高端 堆栈是内存中的一个连续的块。一个叫堆栈指针的寄存器(SP)指向堆栈的栈顶。堆栈的底部是一个固定地址。堆栈有一个特点就是,后进先出。也就是说,后放入的数据第一个取出。它支持两个操作,PUSH和POP。PUSH是将数据放到栈的顶端,POP是将栈顶的数据取出。 在高级语言中,程序函数调用、函数中的临时变量都用到堆栈。为什么呢?因为在调

定语从句讲解方法

定语从句 定语从句是用来修饰、描述或提供有关名词、代词或整个主句信息的从句。它在整个句子中起形容词的作用。被修饰的名词,语法上称作先行词。从句由关系代词或关系副词引导。关系代词和关系副词不仅起引导定语从句、连接先行词的作用,同时还充当定语从句中的一个成分,如:主语、宾语、介词宾语、表语、定语或状语等。定语从句由下列关系代词和关系副词引导: (1) who, whom, that(2) which, that(3) whose(4) when, Where(5)why 1. 关系代词who,that ,which在从句中修饰、指代人或事物,作主语。 例句: I thank the woman. She helped me. a. b. 例句: Did you hear about the earthquake? It happened in San Francisco last week. 你听说上星期在旧金山发生的地震了吗? 关系代词that / which引导的定语从句修饰名词earthquake。在从句that / which happened in San Francisco last week 中作句子的主语。“” 注意:当关系代词在从句中作主语时不能 ..省略。a. b. 两例句意思一样. Which 要比that正式一些。 2.关系代词who(whom),that ,which在从句中修饰、指代人或事物,在从句中作宾语. Whom 是宾格形式,常用于较正式的英语中。who和that,which 常用于口语和非正式的英语中。在口语和非正式英语中更多的情况下,作动词宾语的关系代词常被省略。 例句:The man told me to come back. I saw him in the office. a. b. The man who I saw in the office told me to come back. c. The man that I saw in the office told me to come back. d. The man I saw in the office told me to come back. 我在办公室见到的那为男士叫我回去。 例句: The movie wasn’t very good. wasn’t very good. c. The movie we saw last night wasn’t very goo d. 我们昨晚看的那部电影不怎么样。 关系代词that / which 引导的从句修饰名词The movie。在从句that we saw last night 中,that/ which 作动词saw的宾语。关系代词作动词宾语的时候可以省略。 注意:a. 引导从句的关系代词一定要放在从句的最前面,例如:从句whom I saw in the office,虽然关系代词whom 在句子中作动词的宾语,也应放在从句的最前面。 b. 从句应尽可能地紧跟在所修饰的名词后面。从句whom I saw in the office是用来修饰the man, 所以应放在the man 后面。

堆栈、栈(stack)和堆(heap)三者的区别

一、预备知识(程序的内存分配) 一个由C/C++编译的程序占用的内存分为以下几个部分: 1、栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。 2、堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,其分配方式倒是类似于链表。 3、全局区(静态区static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后有系统释放。 4、文字常量区:常量字符串就是放在这里的。程序结束后由系统释放。 5、程序代码区:存放函数体的二进制代码。 看看下面的例子程序,这是一个前辈写的,非常详细。 //main.cpp int a = 0; 全局初始化区 char *p1; 全局未初始化区 main() { int b; 栈 char s[] = "abc"; 栈 char *p2; 栈 char *p3 = "123456"; 123456\0在常量区,p3在栈上。 static int c =0;全局(静态)初始化区 p1 = (char *)malloc(10); p2 = (char *)malloc(20); 分配得来得10和20字节的区域就在堆区。 strcpy(p1, "123456"); 123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。 } 二、堆和栈的理论知识 2.1、申请方式 stack:由系统自动分配。例如:声明在函数中一个局部变量int b,系统自动在栈中为b开辟空间。heap:需要程序员自己申请,并指明大小,在c中用malloc函数,如p1 = (char *)malloc(10); 在C++中用new运算符:如p2 = (char *)malloc(10); 但是注意p1、p2本身是在栈中的。 2.2 、申请后系统的响应 stack:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报错提示栈溢出。heap:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小。这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。 2.3、申请大小的限制 stack:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是

定语从句讲解总结

定语从句讲解总结 Prepared on 24 November 2020

定语从句讲解 一.定语从句 1.注意英汉差异:汉语的定语无论多长都放在被修饰词的前面,而英语中的定语则不然,是一个词时,放在被修饰词的前面, 如:①.a beautiful girl ②.a lovely boy 是两个以上的词组、短语或从句则放在被修饰词的后面, 如:③.She is the girl in red. 她就是穿红衣的女孩。 ④.The lady carried a bag full of money. 那位女士背了个装满钱的包。 ⑤.He is the man who you are looking for. 她就是你在找的人。 2.分清主句与从句,看究竟哪个句子缺少成分。 如上面第5:主句:He is the man 从句:who you are looking for 在从句中,looking for 的宾语是the man.因此选用关系代词 who(whom)放置于句首,便是定语从句。 3.从句中做宾语的关系代词可以省略,故第5题可以写成: He is the man you are looking for. 二.定语从句(从句部分) 1、功能:相当于形容词,修饰名词或代词,在句中作定语 2、位置:定语从句置于被修饰词之后 Those who are willing to attend the party, sign here please. 3、先行词:被定语从句修饰的词称为先行词 (1)先行词一般是名词和不定代词, 如:some-, any-, every-和no与-boy, -thing的合成词;或all、none、any、some、that、those等代词。 数词也可以作先行词,人称代词也同样可作先行词。 (2)先行词与关系词是等量关系。必须注意两点: ①先行词在从句中作主语时,从句谓语动词的数由先行词而定。 This is the place which is worth visiting. ②关系词在从句句子中充当了成分,其意思就是先行词的意义,所以在从句中不能重复其意。 There are many places we can visit(them)in China. 4、关系词:引导定语从句的都称关系词 关系代词:which, that, who, whom, whose, as。 关系副词:when, where, why。that偶尔也作关系副词。 5、确定关系词的步骤 (1)先找关系词,看先行词指的是什么。 (2)看关系词在从句中所充当的成分。 一.关系代词which的用法 1.English is a language.

定语从句讲解及练习(含答案)

定语从句讲解与练习 一.定义:在复合句中修饰某一名词或代词的从句叫定语从句。 二.特点:1.先行词:定语从句所修饰的名词或代词 2. 关联词: 1)引出定语从句,并作从句的一个成分。可作主语、宾语、定语、状语,作宾语可省略。 2)关联词包括关系代词和关系副词。关联词位于先行词和定语从句之间。 关系代词:that, which, who, whom, whose代指先行词。 关系副词:when, where, why作时间状语。 三.基本结构:先行词+关联词+定语从句剩余部分 四.关系代词的用法: 1. that 和which that指人或物,作主语或宾语,作宾语可省略,主语不能。 Which指物,不指人,作主语或宾语,作宾语可省略,主语不能。 His father works in a factory that/which makes TV sets. Who was hurt in the accident that/which happened yesterday? The coat (which/that) I put on the desk is black. 注意:The room in which I live is very big. (在介词后面不能用that) 2.只能用that不能用which引导的定语从句: 1) 先行词被形容词最高级修饰时,定语从句只能用that This is the most interesting story (that) I have ever heard. 2)先行词被序数词修饰时,定语从句只能用that The children like the second lesson that is about “The Football Match”. 3)先行词被the only,the very 或the same等修饰,定语从句只能用that引导。It is the only word (that) I know in the passage. Where is the very book (that) I bought just now? This is the (same) bicycle (that) I lost. 4)先行词为everything,something,anything,all,none,much,little,few 等不定代词时,定语从句只能用that I want everything (that) I want. I am writing to tell you about something very strange that happened to me last week. 5)先行词被不定代词all, any, no, every, little, much, many修饰时,只能用that Here is all the money (that) I have. 6)先行词是同时含有“人和物”的名词时,定语从句只能用that I can remember well the persons and some pictures (that) I see in the room.

相关文档
相关文档 最新文档