关于堆栈和指针
堆栈是一种执行“后进先出”算法的数据结构。
设想有一个直径不大、一端开口一端封闭的竹筒。有若干个写有编号的小球,小球的直径比竹筒的直径略小。现在把不同编号的小球放到竹筒里面,可以发现一种规律:先放进去的小球只能后拿出来,反之,后放进去的小球能够先拿出来。所以“先进后出”就是这种结构的特点。
堆栈就是这样一种数据结构。它是在内存中开辟一个存储区域,数据一个一个顺序地存入(也就是“压入——push”)这个区域之中。有一个地址指针总指向最后一个压入堆栈的数据所在的数据单元,存放这个地址指针的寄存器就叫做堆栈指示器。开始放入数据的单元叫做“栈底”。数据一个一个地存入,这个过程叫做“压栈”。在压栈的过程中,每有一个数据压入堆栈,就放在和前一个单元相连的后面一个单元中,堆栈指示器中的地址自动加1。读取这些数据时,按照堆栈指示器中的地址读取数据,堆栈指示器中的地址数自动减1。这个过程叫做“弹出pop”。如此就实现了后进先出的原则。
堆栈是计算机中最常用的一种数据结构,比如函数的调用在计算机中是用堆栈实现的。
堆栈可以用数组存储,也可以用以后会介绍的链表存储。
下面是一个堆栈的结构体定义,包括一个栈顶指针,一个数据项数组。栈顶指针最开始指向-1,然后存入数据时,栈顶指针加1,取出数据后,栈顶指针减1。
#define MAX_SIZE 100
typedef int DATA_TYPE;
struct stack
{
DATA_TYPE data[MAX_SIZE];
int top;
};
堆栈是系统使用是临时存储区域。它是后进先出的数据结构。
C++主要将堆栈用于函数调用。当函数调用时,各种数据被推入堆栈顶部;函数终止后的返回地址、传递给函数的参数、函数返回的结果以及函数中声明的局部变量等等。因此当函数A调用函数B调用函数C,堆栈是增长了,但调用完成后,堆栈又缩小了。
堆是一种长期的存储区域。程序用C++的new操作符分配堆。对new的调用分配所需的内存并返回指向内存的指针。与堆栈不同,你必须通过调用new明确的分配堆内存。你也必须通过调用C++的delete 操作符明确的释放内存,堆不会自动释放内存。
如果C++中的一个类是定义在堆栈上的,就使用"."开访问它的成员。如果是定义在堆上的,就使用"->"指针来开访问。但在,"->"操作符也可以用在堆栈上的类。
什么是指针?
和其它变量一样,指针是基本的变量,所不同的是指针包含一个实际的数据,该数据代表一个可以找到实
际信息的内存地址。这是一个非常重要的概念。许多程序和思想依靠指针作为他们设计的基础。
开始
怎样定义一个指针呢?除了你需要在变量的名称前面加一个星号外,其它的和别的变量定义一样。举个例子,以下代码定义了两个指针变量,它们都指向一个整数。
int* pNumberOne;
int* pNumberTwo;
注意到两个变量名称前的前缀?p?了么?这是一个惯例,用来表示这个变量是个指针。
现在,让我们将这些指针实际的指向某些东西:
pNumberOne = &some_number;
pNumberTwo = &some_other_number;
…&?符号应该读作”什么什么的地址”,它返回一个变量在内存中的地址,设置到左侧的变量中。因此,在这个例子中,pNumberOne设置和some_number的地址相同,因此pNumberOne现在指向some_number。
现在,如果我们想访问some_number的地址,可以使用pNumberOne。如果我们想通过pNumberOne 访问some_number的值,那么应该用*pNumberOne。这个星号表示解除指针的参照,应该读作“什么什么指向的内存区域”。
到现在我们学到了什么?举个例子
哟,有许多东西需要理解。我的建议是,如果你有哪个概念没有弄清楚的话,那么,不妨再看一遍。指针是个复杂的对象,可能需要花费一段时间来掌握它。
这儿有一个例子示范上面所将的概念。这是用C写的,没有C++扩展。
#include
void main()
{
// 申明变量
int nNumber;
int *pPointer;
//赋值
nNumber = 15;
pPointer = &nNumber;
// 输出nNumber的值
printf("nNumber is equal to : %d\n", nNumber);
// 通过pPointer修改nNumber的值
*pPointer = 25;
// 证明nNumber已经被改变了
// 再次打印nNumber的值
printf("nNumber is equal to : %d\n", nNumber);
}
通读一遍,并且编译样例代码,确信你理解了它为什么这样工作。如果你准备好了,那么继续。一个陷阱!
看看你能否发现下面这段程序的毛病:
#include
int *pPointer;
void SomeFunction();
{
int nNumber;
nNumber = 25;
//将pPointer指向nNumber
pPointer = &nNumber;
}
void main()
{
SomeFunction(); //用pPointer做些事情
// 为什么会失败?
printf("Value of *pPointer: %d\n", *pPointer);
}
这段程序先调用SomeFunction函数,该函数创建一个叫做nNumber的变量,并将pPointer指向它。那么,问题是,当函数退出时,nNumber被删除了,因为它是一个局部变量。当程序执行到局部变量定义的程序块以外时,局部变量总是被删除了。这就意味着,当SomeFunction函数返回到main函数时,局部变量将被删除,因此pPointer将指向原先nNumber的地址,但这个地址已经不再属于这段程序了。如果你不理解这些,那么重新阅读一遍关于局部变量和全局变量的作用范围是明智的选择。这个概念也是非常重要的。
那么,我们如何解决这个问题呢?答案是使用大家都知道的一个方法:动态分配。请明白C和C++的动态分配是不同的。既然现在大多数程序员都使用C++,那么下面这段代码就是常用的了。
动态分配
动态分配可以说是指针的关键所在。不需要通过定义变量,就可以将指针指向分配的内存。也许这个概念看起来比较模糊,但是确实比较简单。下面的代码示范如何为一个整数分配内存:
int *pNumber;
pNumber = new int;
第一行申明了一个指针pNumber,第二行分配一个整数内存,并且将pNumber指向这个新内存。下面是另一个例子,这次用一个浮点数:
double *pDouble;
pDouble = new double;
动态分配有什么不同的呢?当函数返回或者程序运行到当前块以外时,你动态分配的内存将不会被删除。因此,如果我们用动态分配重写上面的例子,可以看到现在能够正常工作了。
#include
int *pPointer;
void SomeFunction()
{
// make pPointer point to a new integer
pPointer = new int;
*pPointer = 25;
}
void main()
SomeFunction(); // make pPointer point to something
printf("Value of *pPointer: %d\n", *pPointer);
}
通读一遍,编译上面的代码,确信你已经理解它是如何工作的。当调用SomeFunction时,分配了一些内存,并且用pPointer指向它。这次,当函数返回时,新内存就完整无缺了。因此pPointer仍旧指向有用的东西。这是因为使用了动态分配。确信你已经理解它了。那么继续向下看,了解为什么上面的程序还会有一系列的错误。
内存分配和内存释放
这里有一个问题,可能会变得十分严重,虽然它很容易补救。这个问题就是,虽然你用动态分配可以方便的让内存完整无缺,确实不会自动删除,除非你告诉计算机,你不再需要这块内存了,否则内存将一直被分配着。因此结果就是,如果你不告诉计算机你已经使用完这块内存,那么它将成为被浪费的空间,因为其它程序或者你的应用程序的其它部分不能使用这块内存。最终将导致系统因为内存耗尽而崩溃。因此这个问题相当重要。内存使用完后释放非常容易:
delete pPointer;
需要做的就是这些。但是你必须确定,你删除的是一个指向你实际分配的内存的指针,而不是其它任何垃圾。尝试用delete已经释放的内存是危险的,并且可能导致程序崩溃。
这里再次举个例子,这次修改以后就不会有内存浪费了。
#include
int *pPointer;
void SomeFunction()
{
// make pPointer point to a new integer
pPointer = new int;
*pPointer = 25;
}
void main()
{
SomeFunction(); // make pPointer point to something
printf("Value of *pPointer: %d\n", *pPointer);
delete pPointer;
}
只有一行不同,但这行是要点。如果你不删除内存,就会导致“内存泄漏”,内存将逐渐减少,除非应用程序重新启动,否则将不能再生。
向函数传递指针
传递指针给函数非常有用,但不容易掌握。如果我们写一个程序,传递一个数值并且给它加上5,我们也许会写出如下的程序:
#include
void AddFive(int Number)
{
Number = Number + 5;
}
void main()
int nMyNumber = 18;
printf("My original number is %d\n", nMyNumber);
AddFive(nMyNumber);
printf("My new number is %d\n", nMyNumber);
}
但是,程序中函数AddFive的参数Number只是变量nMyNumber的一个拷贝,而不是变量本身,因此,Number = Number + 5只是为变量的拷贝增加了5,而不是最初的在main()函数中的变量。当然,你可以运行程序,以证明这一点。
为了将值传递出去,我们可以传递这个变量的指针到函数中,但我们需要修改一下函数,以便传递数值的指针而不是数值。因此将void AddFive(int Number)修改为void AddFive(int *Number),增加了一个星号。下面是修改了的函数,注意,我们必须确认传递了nMyNumber的地址,而不是它本身。这通过增加&符号来完成,通常读作“什么什么的地址”。
#include
void AddFive(int* Number)
{
*Number = *Number + 5;
}
void main()
{
int nMyNumber = 18;
printf("My original number is %d\n", nMyNumber);
AddFive(&nMyNumber);
printf("My new number is %d\n", nMyNumber);
}
大家可以试着自己做个例子来实验一下。注意在AddFive函数中Number变量前那个重要的星号。只是必须的,用来告诉编译器我们想将5加到变量Number指向的数值,而不是将5加到指针本身。
关于函数最后需要注意的是你也可以返回一个指针。比如:
int * MyFunction();
在这个例子中,MyFunction函数返回一个指向整数的指针。
类的指针
关于指针还有两个需要注意的问题。其中一个是结构或者类。你可以如下定义一个类:
class MyClass
{
public:
int m_Number;
char m_Character;
};
然后,你可以如下方式定义一个类变量:
MyClass thing;
你应该已经知道这些了,如果还不知道的话,那么再将上面的内容读一遍。定义MyClass的指针应该这么写:
MyClass *thing;
然后你需要分配内存,并将指针指向这个内存
thing = new MyClass;
问题来了,你如何使用这个指针呢?一般的,我们写thing.m_Number,但你不能对指针用?.?操作,因为thing 不是一个MyClass对象。只是指向一个MyClass对象的指针。因此,指针thing不包含m_Number这个变量。只是它指向的结构中包含这个变量。因此,我们必须使用一个不同的协定,用->取代?.?。以下是一个例子:
class MyClass
{
public:
int m_Number;
char m_Character;
};
void main()
{
MyClass *pPointer;
pPointer = new MyClass;
pPointer->m_Number = 10;
pPointer->m_Character = 's';
delete pPointer;
}
数组的指针
你也可以构造一个指向数组的指针,如下:
int *pArray;
pArray = new int[6];
将创建一个叫做pArray的指针,指向一个包含6个元素的数组。另一种构造的方法是使用动态分配,如下:
int *pArray;
int MyArray[6];
pArray = &MyArray[0];
注意,你这里也可以不用&MyArray[0],而直接使用&MyArray取代。当然,这仅仅适用于数组。
使用指向数组的指针
一旦你有了指向数组的指针,那么如何使用它呢?现在假设你有一个指向整数数组的指针,那么指针开始时将指向第一个整数。举例如下:
#include
void main()
{
int Array[3];
Array[0] = 10;
Array[1] = 20;
Array[2] = 30;
int *pArray;
pArray = &Array[0];
printf("pArray points to the value %d\n", *pArray);
}
将指针移到指向数组的下一个值,可以用pArray++。也许你也可以猜出来了,我们可以用pArray+2的方式将指针向后移动两个位置。要注意的问题是,你自己必须知道数组的上限是多少(例子中是3),因为编译器不能检查你是否将指针移到了数组以外,因此你可以很容易的将系统搞崩溃了。以下是个例子,显示我们设置的三个值:
#include
void main()
{
int Array[3];
Array[0] = 10;
Array[1] = 20;
Array[2] = 30;
int *pArray;
pArray = &Array[0];
printf("pArray points to the value %d\n", *pArray);
pArray++;
printf("pArray points to the value %d\n", *pArray);
pArray++;
printf("pArray points to the value %d\n", *pArray);
}
你也可以使用pArray-2这样的方式来向前移动2个位置。不管是加或者减,你必须保证不是对指针所指向的数据的操作。这种操作指针和数组的方式在循环中是最常用的。例如for和while循环。
另外要提的是,如果你有一个指针比如int pNumberSet,你也可以把它当成数组。例如pNumberSet[0]等于*pNumberSet,并且pNumberSet[1]等于*(pNumberSet+1)。
对于数组,还有一点要注意的,如果你用new为数组分配内存,比如:
int *pArray;
pArray = new int[6];
你必须用以下方式进行删除:
delete[] pArray;
注意delete后的[],它告诉编译器,这是删除整个数组,而不仅仅是第一个元素。对于数组你必须使用这种方法,否则就会有内存泄漏。
总结
一条要注意的:你不能删除不是用new分配的内存。比如以下例子:
void main()
{
int number;
int *pNumber = number;
delete pNumber; // wrong - *pNumber wasn't allocated using new.
}
方法 指针函数和函数指针的区别 关于函数指针数组的定义 为函数指针数组赋值 函数指针的声明方法为: 数据类型标志符 (指针变量名) (形参列表); 注1:“函数类型”说明函数的返回类型,由于“()”的优先级高于“*”,所以指针变量名外的括号必不可少,后面的“形参列表”表示指针变量指向的函数所带的参数列表。例如: int func(int x); /* 声明一个函数 */ int (*f) (int x); /* 声明一个函数指针 */ f=func; /* 将func函数的首地址赋给指针f */ 赋值时函数func不带括号,也不带参数,由于func代表函数的首地址,因此经过赋值以后,指针f就指向函数func(x)的代码的首地址。 注2:函数括号中的形参可有可无,视情况而定。 下面的程序说明了函数指针调用函数的方法: 例一、 #include
C++指针函数习题 一、选择题 1.以下程序的运行结果是()。 sub(int x, int y, int *z) { *z=y-x; } void main() { int a,b; sub(10,5,&a); sub(7,a,&b); cout< #include<>
指向函数的指针 函数指针是指指向函数而非指向对象的指针。像其他指针一样,函数指针也指向某个特定的类型。函数类型由其返回类型以及形参表确定,而与函数名无关: bool (*pf)(const string &,const string &); 这个语句将pf声明为指向函数的指针,它所指向的函数带有两个const string &类型的形参和bool 类型的返回值。 注意:*pf两侧的括号是必需的。 1.typedef简化函数指针的定义: 函数指针类型相当地冗长。使用typedef为指针类型定义同义词,可将函数指针的使用大大简化: Typedef bool (*cmpfn)(const string &,const string &); 该定义表示cmpfn是一种指向函数的指针类型的名字。该指针类型为“指向返回bool类型并带有两个const string 引用形参的函数的指针”。在要使用这种函数指针类型时,只需直接使用cmpfcn即可,不必每次都把整个类型声明全部写出来。 2.指向函数的指针的初始化和赋值 在引用函数名但又没有调用该函数时,函数名将被自动解释为指向函数的指针。假设有函数: Bool lengthcompare(const string &,const string &); 除了用作函数调用的左操作数以外,对lengthcompare的任何使用都被解释为如下类型的指针:
bool (*)(const string &,const string &); 可使用函数名对函数指针初始化或赋值: cmpfn pf1=0; cmpfn pf2=lengthcompare; pf1=legnthcompare; pf2=pf1; 此时,直接引用函数名等效于在函数名上应用取地址操作符: cmpfcn pf1=lengthcompare; cmpfcn pf2=lengthcompare; 注意:函数指针只能通过同类型的函数或函数指针或0值常量表达式进行初始化或赋值。 将函数指针初始化为0,表示该指针不指向任何函数。 指向不两只函数类型的指针之间不存在转换: string::size_type sumLength(const string &,const string &); bool cstringCompare(char *,char *); //pointer to function returning bool taking two const string& cmpFcn pf;//error:return type differs pf=cstringCompare;//error:parameter types differ pf=lengthCompare;//ok:function and pointer types match exactly 3.通过指针调用函数 指向函数的指针可用于调用它所指向的函数。可以不需要使用解引用
④学生用毛细现象解释酒精灯燃烧、树枝插在红色水中插久了变色的原因。 “科学是探求意义的过程”(爱因斯坦)。作为一种学生的学习方式,探究活动关注的重点是围绕解决问题,采用一定的方法问题进行学习。学生的探究是需要方法引导的,这种引导将经历 究”的过程,逐步放开。 一位外国教育专家观看了这堂课后,兴奋地说:“我终于看到了儿童真实的探究。这里真是课堂改进的天堂。” 照片:外国专家在课堂上 如果文章要分两部分的话,下面为第二部分,题目不变。 3. 在“变式”体验中建构原理 ----中学物理《杠杆》 杠杆是一种简单的机械,形状各异,但都绕一个点转动,这个点称为支点。杠杆受的力分为动力和阻力,支点到动力或阻力的作用线的距离叫做力臂,杠杆平衡的条件是:动力×动力臂=阻力×阻力臂。 杠杆是阿基米德发现力学规律的得意之作,他得出了著名的杠杆原理。让学生在过程体验中建构概念、原理,是当前理科课程改革的主要思想之一。可是一到现实的课堂,杠杆原理与认知建构理论就怎么也不能相映成趣: ①力臂的定义比较抽象,总是由教师给出、学生记住; ②杠杆平衡的条件还是教师演示,学生验证。 那么能否通过适当的教学处理,让学生能生动地体验知识的发生过程,有效地建构物理概念呢?物理研究小组对杠杆这堂课的教学内容做了如下的调整。 ● 从“扁担挑物”到水平杠杆的平衡条件 最简单的杠杆是水平杠杆。学生早就有了扁担挑东西的生活经验,只要稍作概括,就可以简化成如图所示的水平杠杆。 扁担挑物 水平杠杆:支点、水平力臂、重力
在水平杠杆模型中,力臂是“具体”的,与生活经验完全一致,因此不会成为学习的难点。这样,学生就可以避开难点,集中探索支点两侧力臂、重力这4个物理量的关系,下面是学生在课堂上做物理实验填写的记录单: 实验序次 重力F1力臂L1重力F2力臂L2 ① 3 2 ② 2 3 ③ ④ ⑤ ⑥ 学生经过亲自实验,获得一批数据,然后相互合作探讨这些数据之间的关系,得出水平杠杆平衡的条件,即重力与力臂之间两两乘积相等( F1 L1=F2 L2)或反比例(F1 :L2 = F2 :L1)。 在新设计的教学过程中,师生行为出现了明显的变化。改进前,先是由教师口头讲解或实验演示,得出上述平衡条件,然后让学生根据实验手册的要求验证这个规律。改进后,学生变得主动起来,从直觉感知出发,通过简化设计了的实验,变验证为自觉探求,亲身体验了科学家(如阿基米德)发现客观规律的过程,这样的科学加工的方法(图6),在自然科学的学习与研究中很具普遍意义和思想的价值。 扁担挑物 水平杠杆 符号表征 (生活经验) (因素简约化) F1 L1=F2 L2 图6 体验科学家发现规律的过程 ● 杠杆原理与力臂定义的修正 水平杠杆是个简单的模型,把其中一端的重物换为弹簧秤竖直往下拉,结果仍然符合前述的杠杆原理。改变弹簧秤的方向,如下图所示斜拉。这时学生会
生活中常见的毛细现象 摘要:毛细作用,是液体表面对固体表面的吸引力。毛细管插入浸润液体中,管内液面上升,高于管外,毛细管插入不浸润液体中,管内液体下降,低于管外的现象。毛巾吸水,地下水沿土壤上升都是毛细现象。在洁净的玻璃板上放一滴水银,它能够滚来滚去而不附着在玻璃板上。把一块洁净的玻璃板浸入水银里再取出来,玻璃上也不附着水银。生活中有很多这种毛细现象。 关键词:毛细;生活;应用 一、毛细现象及其相关概念 1.1毛细现象 毛细现象,又称毛细管作用,是指液体在细管状物体内侧,由于内聚力与附着力的差异、克服地心引力而上升的现象。植物根部吸收的水分能够经由茎内维管束上升,即是毛细现象最常见的例子。当液体和固体或管壁之间的附着力大于液体本身内聚力时,就会产生毛细现象。液体在垂直的细管中时液面呈凹或凸状、以及多孔材质物体能吸收液体皆为此现象所致。 1.2 浸润液体 在洁净的玻璃上放一滴水,它会附着在玻璃板上形成薄层。把一块洁净的玻璃片浸入水中再取出来,玻璃的表面会沾上一层水.这种液体附着在固体表面上的现象叫做浸润。对玻璃来说,水是浸润液体。同一种液体,对一种固体来说是浸润的,对另一种固体来说可能是不浸润的。水能浸润玻璃,但不能浸润石蜡.水银不能浸润玻璃,但能浸润锌。
1.3 毛细现象产生原因 产生毛细现象原因之一是由于附着层中分子的附着力与内聚力的作用,造成浸润或不浸润,因而使毛细管中的液面呈现弯月形。原因之二是由于存在表面张力,从而使弯曲液面产生附加压强。由于弯月面的形成,使得沿液面切面方向作用的表面张力的合力,在凸弯月面处指向液体内部;在凹弯月面处指向液体外部。由于合力的作用使弯月面下液体的压强发生了变化——对液体产生一个附加压强,凸弯月面下液体的压强大于水平液面下液体的压强,而凹弯月面下液体的压强小于水平液面下液体的压强。根据在盛着同一液体的连通器中,同一高度处各点的压强都相等的道理,当毛细管里的液面是凹弯月面时,液体不断地上升,直到上升液柱的静压强抵消了附加压强为止;同样,当液面呈凸月面时,毛细管里的液体也将下降。 1.4 水和汞的毛细现象 由于表面张力与附着力的差异,水在毛细管中,中央较四周凹下;汞在毛细管中,中央较四周凸起。毛细管常被用来说明毛细现象,当垂直的细玻璃管底部臵于液体中(例如水)时,管壁对水的附着力便会使液面四周稍比中央高出一些;直到液体表面张力已经无法克服其重量时,才会停止继续上升。在毛细管中,液柱重量与管径的平方成正比,但是液体与管壁的接触面积只与管径成正比;这使得较窄的毛细管吸水会比较宽的毛细管来得高。例如,一根管径0.5毫米的玻璃细管,理论上能够将水抬升2.8厘米,但实际观察时其高度会略低些。 在某些液体与固体的组合中,与毛细管吸水的状况略为不同,例如细玻璃管与汞,汞柱本身的原子内聚力大于汞柱与管壁之间的附着力,故汞柱液面中央会稍比四周凸起,这和毛细管吸水的状况恰为相反。
指针函数与函数指针的区别 一、 在学习arm过程中发现这“指针函数”与“函数指针”容易搞错,所以今天,我自己想一次把它搞清楚,找了一些资料,首先它们之间的定义: 1、指针函数是指带指针的函数,即本质是一个函数。函数返回类型是某一类型的指针 类型标识符 *函数名(参数表) int *f(x,y); 首先它是一个函数,只不过这个函数的返回值是一个地址值。函数返回值必须用同类型的指针变量来接受,也就是说,指针函数一定有函数返回值,而且,在主调函数中,函数返回值必须赋给同类型的指针变量。 表示: float *fun(); float *p; p = fun(a); 注意指针函数与函数指针表示方法的不同,千万不要混淆。最简单的辨别方式就是看函数名前面的指针*号有没有被括号()包含,如果被包含就是函数指针,反之则是指针函数。来讲详细一些吧!请看下面 指针函数: 当一个函数声明其返回值为一个指针时,实际上就是返回一个地址给调用函数,以用于需要指针或地址的表达式中。 格式: 类型说明符* 函数名(参数) 当然了,由于返回的是一个地址,所以类型说明符一般都是int。 例如:int *GetDate(); int * aaa(int,int); 函数返回的是一个地址值,经常使用在返回数组的某一元素地址上。 int * GetDate(int wk,int dy); main() { int wk,dy; do { printf(Enter week(1-5)day(1-7)\n); scanf(%d%d,&wk,&dy); } while(wk<1||wk>5||dy<1||dy>7); printf(%d\n,*GetDate(wk,dy));
毛细现象大班18人 活动目标: 1.知道带缝隙的物体使水向上走是毛细现象原理,体验和探究发现的乐趣(感知毛细现象原理) 2.能与同伴合作探究,乐于与他人交流自己的猜想、探究和发现。 3.能够探索可以发生毛细现象的物体,学习记录和描述自己的实验过程和结果。 重点:能够探索可以发生毛细现象的物体, 难点:观察出让水移动的物体都有细缝 活动准备: 物质准备:毛巾,清水,容器,尼龙绳,筷子,报纸,棉布,卫生纸,记录表,带颜色的水 经验准备:有记录表格的经验 场地准备: 活动过程: (一)创设问题情境,鼓励幼儿大胆猜想 经验迁移:“我们平时看到的水都是往哪个方向流的呢?谁能够给我举出几个例子(洗手、喝水、下雨)” 引发幼儿猜想:“水会往低处流,还会往其他方向移动吗?” 现象演示:将毛巾的下端浸在水中,一段时间后,为什么毛巾的上端也湿了?那是不是所有的东西都能够让水往上移动呢? 你们觉得有哪些东西可以让水往上移动?出示材料,让幼儿猜想,并在白板上画出表格,用“正”字记录数据,最后进行验证。 (二)引导幼儿进行试验验证,并记录自己的观察和发现 “每个人都说出了不一样的看法,现在我们三个人为一组,到身后的材料台拿材料,然后去操作台进行实验,在实验的过程当中有个要求,你们组的成员要自行分配好任务,有做记录的,有做观察,还有人一会要说出来你们组都发现了什么,每个人都有自己的任务哦!” 幼儿实验操作,进行个别指导。(在实验过程当中注意容器的水和记录表) (三)鼓励幼儿进行交流分享,梳理提升经验
实验结束后让孩子拿着记录表坐到椅子上,“你们谁看见水往上移动了?你们都选取的哪些材料,有哪些可以让水移动呢?”,与实验之前记录的表格相对比,看看猜想与实验结果是否一致。 提升:“你们刚才都做实验了,那能让水移动的物品都有什么共同点,或者说和其他的相比有什么不同点?”拿出材料,让幼儿仔细观察,发现物品特征,“能让水向上移动的物品摸起来和看起來有什么不同?” 结论:原来带缝隙的物品能让水往上移动。 提出问题,猜想与假设,观察、实验与制作,搜集、记录信息,思考、解释与得出结论,表达、分享与交流 对身边的科学现象感兴趣,学习用多种方法进行探究和实验,常使用语言、图表等多种方式表达探索的过程和结果,并乐于与同伴分享探索和发现的乐趣。 产生疑问猜想假设实验验证
生活中常见的毛细现象 欧阳家百(2021.03.07) 摘要:毛细作用,是液体表面对固体表面的吸引力。毛细管插入浸润液体中,管内液面上升,高于管外,毛细管插入不浸润液体中,管内液体下降,低于管外的现象。毛巾吸水,地下水沿土壤上升都是毛细现象。在洁净的玻璃板上放一滴水银,它能够滚来滚去而不附着在玻璃板上。把一块洁净的玻璃板浸入水银里再取出来,玻璃上也不附着水银。生活中有很多这种毛细现象。 关键词:毛细;生活;应用 一、毛细现象及其相关概念 1.1 毛细现象 毛细现象,又称毛细管作用,是指液体在细管状物体内侧,由于内聚力与附着力的差异、克服地心引力而上升的现象。植物根部吸收的水分能够经由茎内维管束上升,即是毛细现象最常见的例子。当液体和固体或管壁之间的附着力大于液体本身内聚力时,就会产生毛细现象。液体在垂直的细管中时液面呈凹或凸状、以及多孔材质物体能吸收液体皆为此现象所致。 1.2 浸润液体 在洁净的玻璃上放一滴水,它会附着在玻璃板上形成薄层。把一块洁净的玻璃片浸入水中再取出来,玻璃的表面会沾上一层水.这种液体附着在固体表面上的现象叫做浸润。对玻璃来说,水是浸
润液体。同一种液体,对一种固体来说是浸润的,对另一种固体来说可能是不浸润的。水能浸润玻璃,但不能浸润石蜡.水银不能浸润玻璃,但能浸润锌。 1.3 毛细现象产生原因 产生毛细现象原因之一是由于附着层中分子的附着力与内聚力的作用,造成浸润或不浸润,因而使毛细管中的液面呈现弯月形。原因之二是由于存在表面张力,从而使弯曲液面产生附加压强。由于弯月面的形成,使得沿液面切面方向作用的表面张力的合力,在凸弯月面处指向液体内部;在凹弯月面处指向液体外部。由于合力的作用使弯月面下液体的压强发生了变化——对液体产生一个附加压强,凸弯月面下液体的压强大于水平液面下液体的压强,而凹弯月面下液体的压强小于水平液面下液体的压强。根据在盛着同一液体的连通器中,同一高度处各点的压强都相等的道理,当毛细管里的液面是凹弯月面时,液体不断地上升,直到上升液柱的静压强抵消了附加压强为止;同样,当液面呈凸月面时,毛细管里的液体也将下降。 1.4 水和汞的毛细现象 由于表面张力与附着力的差异,水在毛细管中,中央较四周凹下;汞在毛细管中,中央较四周凸起。毛细管常被用来说明毛细现象,当垂直的细玻璃管底部置于液体中(例如水)时,管壁对水的附着力便会使液面四周稍比中央高出一些;直到液体表面张力已经无法克服其重量时,才会停止继续上升。在毛细管中,液柱重量与管径的平方成正比,但是液体与管壁的接触面积只与管径成