第一篇:Windows编程知识点总结
1、基于MFC对话框程序的框架代码主要由一下几个部分组成:
A.应用程序类
B.对话框类
C.资源文件
D.预编译文件
2、Windows是建立在消息驱动机制上的。
3、模态对话框运行机制?
当模态对话框产生后,应用程序没有处理消息,唯一的解释就是模态对话框产生后会屏蔽其他窗体消息。事实也正是如此,创建模态对话框后,应用程序只会响应该对话框的消息,知道应用收到结束模态对话框窗体的消息后,才会把控制权交还给应用程序。
4、非模态对话框
与模态对话框不同,非模态对话框不会垄断用户的输入,用户任然可以使用其他窗体。
5、属性对话框主要分为两个部分:
A.属性页
B.属性对话框架
6、属性页只是对话框的一种形式。
7、控件的逻辑顺序决定着软件中需要使用TAB进行焦点切换时的顺序排列。
8、控件按钮有四种基本类型:
A.下压按钮
B.复选按钮
C.单选按钮
D.自绘按钮
9、按钮控件会向父窗口发出控件通知消息
A.BN_CLICKED:鼠标单击消息
B.BN_DOUBLECLICKED:鼠标双击击消息
C.BN_SETFOCUS:获取用户输入焦点
D.BN_KILLFOCUS:失去用户输入焦点
10、在MFC环境下,除了使用CButton类本身的成员函数来操作按钮控件,还可以使用窗体相关类的成员函数,使用这些函数可以根据按钮ID直接进行操作。
11、MFC的CEdit类封装了编辑框控件的基本操作。
12、UPPERCASES设置大写,lowerCase设置小写,Number设置只能接受数字,Password设置显示为*。
13、MFC的CListBox类封装了列表框控件的基本操作。
14、AddString:添加字符串列表项
DeleteString:删除字符串列表项
Dir:从当前目录向列表框添加文件名
FindString:在列表框中查找包含指定前缀的第一个列表项
FindStringExact:在列表框中查找与指定字符串匹配的列表项
InsertString:向列表框中插入一个列表项
ResetContentp:清空编辑框和列表框的所有内容
Selectstring:在列表框中查找字符串
15、组合框有三种模式:
简易式
下拉式
下拉列表式
16、组合框有两种形式:
Dropdown样式
Drop List样式
17、MFC的CProgressCtrl类封装了进度条控件的基本操作。
18、tist->SetTimer(1,100,NULL)
设置计时器ID为1,每100ms触发一次
19、tist->KillTimer(1)
关闭计时器120、列表控件有四种呈现方式:
图标视图
小图标视图
列表视图
报表视图
21、文档视图结构是使用MFC开发基于文档的应用程序的基本框架,最主要的思想是数据的管理与显示分离。
22视图类CView23、使用AppWizard创建SDI和MDI的过程相似,主要区别是创建SDI时不生成CChildFrame类,CMainFrame的基类为CMainWnd;而创建MDI时会生成两个框架类,一个是CMainFrame类,由CMDIFrameWnd类派生而来,另一个是CChildFrame类,由CMDIChildWnd类派生而来
24、文档与视图体系
一个文档可以对应多个视图,而一个视图只能对应一个文档
文档与视图的结构的优势在于数据的管理与显示分离,在开发文档/视图体系开发应用过程时,涉及到:文档模板、文档、视图、框架窗口
25、MFC的CView类是所有视图类的基类,主要有两大工能:
将与其相关联文档的数据呈现给用户
接受用户对数据的修改,并反馈给文档
26、建立MFC单文档应用程序,实例项目名称为“single”框架会自动生成4个类:
CSingleApp类:应用程序类
CMainFrame类:框架类
CSingleDoc文档类
CSingleView类:视图类
27、在MFC中使用GDI 进行绘画操作一般会涉及两类对象:
设备上下文对象
GDI对象
28、设备上下文,是一种windows数据结构,它包含与设备绘制属性相关的信息。
29、主要有一下几种GDI 对象:
CPen对象:用来绘制线条
CBrush对象:用来填充绘制对象的内部
CBitmap对象:用来操作位图对象
CFont对象:用来绘制文本
CPalette对象:用于应用程序和色彩输出设备之间的接口
30、使用GDI进行图形绘制的一般流程:
创建GDI对象
创建获取得设备上下文对象
使用SelectObject把GDI对象选入设备上下文
使用图形输出函数在指定上下文中绘制图形
31、画刷其实是一个像素大小为8*8的位图,用多个相同的位图对封图形的内部进行填充
32、位图
位图是描述图形最简单直观的一种形式,把图像横向分为等间距的W列,纵向分为等间距的H列,于是这个图形的大小被定义为分辨率W*H33、键盘上的每一个健都对应一个唯一的扫描码,在windows系统中为实现设备无关的要求,需要使用虚拟键值
34、当有键盘事件发生时,设备驱动器首先获取健的扫描码,并转换为虚拟键值
35、在应用程序中响应键盘消息有两种方式:
响应本进程的键盘消息
响应系统的键盘消息
36、keybd_event只是用于产生键盘事件,至于由谁来处理他并不关心。系统捕捉到键盘事件后,会转化为键盘消息的形式派发给当前系统中拥有键盘输入焦点的应用程序。SendMessage和PostMasseage的区别在于,PostMasseage首先把消息发到指定句柄所在线程的消息队列再由线程派发。SendMessage是把消息直接发送的指定句柄的窗体或控件。而往往很多情况下。指定句柄是个控件。而对控件的消息消息处理一般都是定义在主对话框上的。除非对其进行子类化,如果使用SendMessage,消息就无法到达主对话框因而无法达到预期的效果。
37、TCP协议是一个面向连接的、可靠的协议,UDP协议是一个不可靠的、无连接的协议
38、因特网控制报文协议(Internet Control Message Protocol,ICMP)
39、套接字是一种网络编程接口,提供了一种网络数据发送和接受机制,套接字是网络通信的基础,一个套接字表示通信的一端,使用套接字可以实现数据包在网络上的传输。
40、soket函数,用来根据指定的地址协议簇、套接字类型和协议类型创建一个套接字。
listen函数,监听远程连接
accept函数,用来接受客户端连接。
sendto函数,用来向指定地址发送数据。
recv函数,用来在已建立连接的套接字上接收数据。
recvfrom函数,用来在指定套接字上接收数据。
setsockopt函数,用来设置套接字属性。
41、进程是一个正在运行的程序的实例,有两部分组成:
一个操作系统用来管理进程的内核对象。
创建时系统所分配的资源,主要是内存地址单元。
41、进程地址空间作为一个载体。包含进城的所有数据和代码以及堆和栈。为线程的运行提供保障。
42、进程是静态的43、线程也有两个部分组成:
线程内核对象;线程堆栈。
44、线程是动态的、可执行的、它总是在某个进程的环境中创建的。
45、每个线程都是运行在其所属进程的地址空间,因此线程只能访问本进程的地址空间,而其他进程对其是不可见的46、所谓‘页’,只是操作系统为了更好的管理地址空间所产生的一个逻辑上的概念,把一个固定长度的地址空间作为一个页,通常为4kb,系统在在对地址空间进行管理时,把每4kb的空间作为一个单位,最终形成内存管理的多级索引结构。
47、物理存储器和进程虚拟地址空间的映射是无序的,每一个进程虚拟地址空间也只能由一个物理存储器页来映射。
48、“地址转换机构”就是负责他们彼此之间的关联。
49、虚拟内存也有三种基本状态:
空闲:地址空间没有被占用,不能使用
保留:地址空间没有被占用,但还没有与物理存储器相关联,不能使用。
提交:且已经与物理存储器相关联,可以使用。
50、内存映射文件
内存映射文件可以在进程中保留一个地址空间区域,并把磁盘文件提交给该区域。一旦映射成功,就可以在内存中直接操作文件,而不再需要使用readfile、writefile等文件操作API。
51、情况下会使用内存映射文件:
系统使用内存映射文件加载可执行模块(.exe)和动态链接(DDL)
操作数据文件
共享内存
52、消息传递
消息传递机制并不以进程为界限,处理消息的是窗体,而与是否在同一进程无关。因而在进程间使用消息传递作为通信手段有个前提,即都是窗体应用程序。
53、共享内存的原理
使用内存共享机制,在任何一个进程内创建内存映射,却能够在其他多个进程中使用。这些进程共享的是物理内存器的同一个页面,把这些物理内存映射到虚拟内存时各个进程的虚拟地址不一定相同。当一个进程将数据写入共享内存时,其他进程可以立即获取数据变更情况,显然这种共享内存的方式是完全可以满足在进程间进行大数据快速传输任务要求的。
54、与内存映射磁盘文件一样,共享内存的本质也是内存映射机制。
55、使用系统页文件支持的内存映射文件,及共享内存。
56、进程间通信的三种基本方法:匿名管道、命名管道、邮槽
57、管道是用于进程间通信的共享内存区域。创建管道的进程称为管道服务器,而连接这两个管道的进程称为管道客户端,一个进程向管道写入信息,另外一个进程从管道读取信息
58、匿名管道
匿名管道是基于字符和半双工的,一般用于程序输入输出的重定向。如果需要获取一个基于控制台窗口应用程序的输出,此时就可以是用匿名管道,首先使用CreatePipe函数创建匿名管道。
59、命名管道的特征:
命名管道是双向的,进程间可以使用同一管道进行交互
命名管道不但可以面向字节流,还可以面向消息。所以读取进行可以读取写进程发送的不同长度的消息
多个独立的管道实例可以用同一个名称来命名。
命名管道可以用于网络间两个进程的通信,而其实现过程与本地进程通信完全一致
60、创建命名管道使用CreateNamedPipe函数
61、邮槽是实现单通道的进程间通信的通信方式。创建邮槽的进程称为邮槽服务器,向邮槽发送消息的进程称为邮槽客户端
60、创建邮槽使用CreateMailslot函数
61、windows剪贴板是一种比较简单同时也是开销比较小的进程间通信方式。
62、剪贴板通信机制
windows系统支持剪贴板IPC的基本机制室友系统预留的一块全局共享内存,可用于被各个进程暂时存储数据。写入进程首先穿件一个全局内存块,并将数据写到该内存块;接受数据的进程通过剪贴板机制获取此内存块的句柄,并完成对该内存块数据的读取。
63、剪贴板通信有5种基本情况:
文本剪贴板
位图剪贴板
自定义格式
延迟提交
多项数据
63、进程同步可分为两大类:
访问共享资源,多个进程访问进程共享资源时,需要确保资源不受破坏。
事件通知,一个线程完成某项任务后通知其他线程。
64、原子访问,是指线程对共享资源的独占式访问。
65、关键代码段,是指在执行前首先去的对共享资源的访问权,然后让代码以原子操作方式执行来访问共享资源的一种方法。
66、内核对象等待函数,其所等待的也正是内核对象的受信状态。
67、内核对象本质上只是一个内存块。
68、内核对象是操作系统对资源进行管理的单位。
69、内核对象有两种状态:已通知状态、未通知状态
70、在所有内核对象中,事件内核对象是最基本的对象,事件内核对象有两种状态:已通知状态、未通知状态。在多线程环境先经常使用事件内核对象的这种特性实现线程同步。
71、事件内核对象有两种基本类型:手动重置事件、自动重置事件。
72、等待定时器内核对象是可以在某个指定时间或者以规定的间隔发出通知信号的内核对象,一般在某个线程需要定时执行某项功能时用这种内核对项
73、信标内核对项常用于在多线程环境下控制某类资源的使用,使用信标内核对象可以让系统自动地维护资源的数量,并合理的控制线程对资源的访问情况。
74、信标的出色之处在于它们能够以原子操作方式来执行测试和设置操作,当向信标申请一个资源时,操作系统就要检验是否有这个资源可供使用,同时将可用资源的数量递减,而不让另一个线程加以干扰。只有当资源数量递减后,系统才允许另一个线程申请对资源的访问权。
75、如果线程需要访问该资源就要先获取互斥对象,所有线程都应遵循这个规则。
76、动态链接库(DLL)是Windows操作系统的基础,所有API函数都包含在DLL中。应用程序并不是只有一个可执行程序,而是由一个可执行模块和若干个DLL模块组成。当执行应用程序时,系统会把与可执行模块相链接的DLL模块加载到当前进程地址空间。
77、动态链接库(DLL)的最大特性是支持动态载入。
78、要产生可执行文件有两个步骤:
1)编译过程。编译源码,为每个C/C++源文件生成一个.obj模块,由编译器完成。
2)链接过程。把应用程序的各个.obj模块链接起来产生.exe文件,有链接器完成。
79、DLL隐式链接,是指在链接过程中,把应用程序所需要DLL模块的名字和输入符号都记录下来,使得应用程序在运行时可以动态载入该DLL。
80、与隐式链接相比,显示加载DLL主要有以下几个特性:
1)显示加载的DLL并不会在应用程序初始化时就加载,而是在运行时根据需要调用LoadLibrary或LoadLibraryEx函数来加载。
2)在应用程序输入表中没有记录。
3)隐式链接的前提是需要有DLL所对应的lib文件,如果没有lib文件就无法进行隐式链接。显示加载就没有这个限制。
81、DllMain函数是DLL的可选入口。
82、线程本地存储器(TLS)的主要作用是可以避免多个线程同时访问同一全局或者静态变量时导致的冲突。
83、TLS有两种使用方法:静态TLS和动态TLS。
84、结构异常处理有三种基本的使用方法,分别是结束异常程序、异常处理程序和顶层异常处理。
85结构化异常处理(SEH)是被作为一种系统机制引入到操作系统中的。
86、可执行文件格式(PE),其格式中得分数据结构通常定义在winnt.h中。
第二篇:Windows编程教案
Windows编程教案
第一课
最简单的Windows程序(2学时)
Windows编程是一个很大的主题,涉及的方面也非常的多。Windows始于90年代,至今Windows编程的发展已经非常成熟了,而单独直接使用API的开发也是越来越少了。因此,市面上很少有泛泛的简单入门级的Windows程序设计了。一个是系统级的Windows编程介绍,如Windows核心编程。一个是方向级的Windows编程介绍如Windows图形编程,Windows网络编程等等。我们这次课的主要参考用书是Windows核心编程,同时也参考了一些其他内容。鉴于教材的价格较贵,同时也需要考虑我们自身的学习内容不一定很多以及学时的原因,就没有定教材。看我的教案吧。
(1)Win32 API API : Application Program Interface。应用程序接口。API就是在进行Windows编程时使用的函数库。本课就是
Windows编程=API+C语言(或者C++语言)(2)开发环境
我校机器上安装了VC++ 6.0。相信这是大家一直以来学习C,C++使用的开发环境。但VC60离我们实在太远了,它是一款90年代的产品,已经近20年的历史了。我们机器里还有VS2005 或 VS2008,那里面的C环境要比VC60强太多了,强烈建议大家使用更高级的平台。本次授课的开发环境有两个。一个是轻量级的DEV C++,一个是重量级的VS2010.简单程序我们都将用DEV C++来实现。
DEV C++是一个非常小的C环境,但性能要优于VC60,调试环境不如VC60。这个环境在我们的共享资源里有,大家可以下载安装。安装过程非常简单,一直下一步即可。
这是其主界面。
(3)最简单的Windows程序
提到最简单的程序,几乎所有的人都会想起经典的HelloWorld。
这不是Windows程序,如果在以前这叫DOS程序,现在叫Windows控制台应用程序。它不算Windows程序,但它很简单的就把Helloword显示到屏幕上了。而Windows程序要想把HelloWorld显示在屏幕上就确实不容易了。
3.1 访问Helloworld网站,因为把Helloworld显示在屏幕上并不容易,我们可以一点一点来,先让Helloworld以文字形式出现在其他地方,这里我们通过访问网站www.xiexiebang.comE,HINSTANCE,LPSTR,int nShow)DefWindowProc(HWND,UINT,WPARAM,LPARAM)GetMessage(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax).如果得到WM_QUIT返回0 TranslateMessage(&MSG)DispathMessage(&MSG)BeginPaint(&PAINTSTRUCT)TextOut(HDC,INT,INT,LPSTR,INT)EndPaint(HWND,&PAINTSTRUCT)作业:
自己建立应用,在窗口100,100位置显示HelloWorld 第三课 坐标位置及大小(4学时)
在我们写控制台应用的时候,不能自由的控制输出显示的位置。因此,没有学习过这方面的内容,现在我们创建了窗口,并且在窗口上显示了Hello World。这个过程涉及到很多涉及位置和大小的因素,如窗口的大小,显示的位置,文字显示的位置。说到位置,就涉及定位,说到定位就要说坐标系。在屏幕上显示内容涉及到坐标空间的知识。在Windows应用中坐标空间分如下几部分内容
1、物理坐标空间
物理坐标空间,指的是物理设备上对应的坐标系。如显示器
坐标原点在左上角。如下是一个1024*768的屏幕物理坐标(0,0)(1024,0)
(0,768)
2、设备坐标空间
基于设备上下文指定的坐标空间。如窗口内显示的文本,使用的坐标就是基于窗口内上下文的坐标。
可以看到设备空间是物理空间体系的一个子空间。设备空间可以依赖于一个窗口。换句话可以把设备空间理解为在物理空间上显示的一个对象,其子空间。下面我们通过一个小例子理解物理空间和设备空间
在窗口的标题条,以设备坐标,和物理坐标的形式显示鼠标在窗口内的位置
WndProc处理消息循环
WM_MOUSEMOVE,鼠标移动时消息标识,是个整数。其参数lParam,的第16位代表设备坐标中的X,高16位代表设备坐标的Y。POINT 是结构体。只有x,y两个成员 ClientToScreen,将设备坐标转换为屏幕坐标(物理坐标)sprintf:格式化字符串
SetWindowText:设Window标题
3、页面坐标空间(逻辑坐标空间的一种)
作用,可以任意指定坐标原点,坐标轴方向,比例尺等信息。可以用来与设备无关的大小如厘米,毫米等。
页面坐标叫窗口,其表示有原点(X,Y),宽度,高度组成(WIDTH,HEIGHT)设备坐标叫视口,其表示有原点(x,y),宽度,高度组成(width,height)
页面坐标和设备坐标的变换关系,大写为设备坐标,小写为页面坐标
PX=X+(px-x)*WIDTH/width PY=Y+(py-y)*HEIGHT/height
px=x+(PX-X)*width/WIDTH py=y+(PY-Y)*heigh/HEIGHT
GDI函数使用页面坐标,显示出来时是设备坐标
通过对窗口,是否对应的四个参数的设置,可以实现特殊的变换。页面坐标是逻辑坐标的一种。在这个例子中我们一直使用 MoveToEx(ps.hdc,0,0,NULL);
LineTo(ps.hdc,30,30);划线,MoveToEx是把画笔移动到指定位置(页面坐标),LineTo是从画笔所在位置到目标位置画一条线。
在这个例子中,每次划线前通过设置视口,窗口结果使划线的结果不同。这种形式的坐标转换无法实现旋转
4、世界坐标空间(逻辑坐标空间的另一种)功能:比页面坐标空间方便,可以实现旋转 结构体 XFORM{ FLOAT eM11, FLOAT eM12, FLOAT eM21, FLOAT eM21, FLOAT eDx, FLOAT eDy, } 世界坐标到设备坐标的变换。小写到大写。PX=eM11*px+eM21*py+eDx;PY=eM12*px+eM22*py+eDy;默认为{1,0,0,1,0,0} 和设备坐标相同 {1001dxdy} {mx00my00}缩放 {-100-100}映像
旋转{cos(a),sin(a),-sin(a),cos(a),0,0}顺时针旋转a度 {cos(a),-sin(a),sin(a),cos(a),0,0}逆时针旋转a度
我们下面的例子通过Rectangle(ps.hdc,0,0,50,50);绘制50*50的矩形,用循环配合世界坐标变换绘制特殊的图形
循环20次,每次旋转坐标轴的方向,绘制正方形。总结:
物理坐标指的是屏幕坐标,不能改变坐标轴 设备坐标指的是窗口坐标,不能改变坐标轴
页面坐标和世界坐标均是逻辑坐标,可以改变坐标轴,世界坐标功能更强,可以旋转。理解这些概念的绘图是很重要的。
相关函数
BOOL ClientToScreen(HWND hWnd, LPPOINT lpPoint);设备坐标转屏幕坐标
BOOL ScreenToClient(HWND hWnd,LPPOINT lpPoint);屏幕坐标转设备坐标 int MapWindowPoints(HWND hWndFrom, HWND hWndTo, LPPOINT lpPoints, UINT cPoints);
各个窗口设备坐标之间的转换
BOOL SetWindowOrgEx(HDC hdc, int X,int Y,LPPOINT lpPoint);设置窗口的原点
SetViewportOrgEx(HDC hdc,int X,int Y,LPPOINT lpPoint);设置视口的原点
BOOL SetViewportExtEx(HDC hdc, int nXExtent, int nYExtent,LPSIZE lpSize);设置视口的width,height BOOL SetWindowExtEx(HDC hdc, int nXExtent,int nYExtent, 设置窗口的width,height SetMapMode设置页面坐标的映射模式 SetGraphicsMode设置世界坐标的映射模式 Rectangle绘制矩形,并填充内部 SetWorldTransform设置世界坐标变换 LineTo:换线
MoveToEx:移动画笔
SetWindowText设置窗口标题
LPtoDP(hdc,LPPOINT,int)把逻辑坐标点转换为设备坐标点 作业:
使用movetoex,lineto,LPtoDP及世界坐标变换,绘制正六边形
LPSIZE lpSize);
提示:
画一条水平线后,将坐标原点移动到线的末尾,并将坐标轴旋转60度*n,重复上步 要将坐标移动到线尾需要使用LPtoDP
第四课 色彩及绘制(6学时)
(1)画点
像素:计算机屏幕上的一个点。是计算机屏幕显示的最小单位。点的个数取决于计算机的分辨率。如1024*768,则屏幕由1024*768个点组成。每个点都可以独立的显示一个颜色。计算机能够表示的颜色有256*256*256=16777216种。颜色的表示 COLORREF。定义颜色RGB COLORREF color=RGB(红,绿,蓝)随机绘制颜色点
需要#include
GetTickCount(): API函数,得到系统开机后到现在的滴答数,特点就是每次返回的结果不重复。
两者的配合得到不重复的随机数序列
rand得到函数
SetPixel设置某点的颜色
(2)画线
在以前的例子里我们一直用1个像素宽的黑色实现来画线。现在我们学习创建画笔,用画笔来画线。
步骤
1、创建画笔CreatePen(画笔类型,宽度,颜色)
2、将画笔选入设备上下文SelectObject
3、用画笔绘制
4、将画笔选出设备
5、删除创建的画笔对象
SelectObject是将GDI对象画笔选入设备上下文,并将当前的选出返回。因此我们两次使用SelectObject,最后一个将以前的画笔选入,返回我们创建的,并在下一步删除画笔。
虚线只能支持宽度1.画线函数
Polygon(HDC,LPPOINT,INT).连接指定点,画多边形,封闭。如果画4边形则确认3个点即可。
Polyline(HDC,LPPOINT,INT).连接指定点,画多边,不封闭 MoveToEx:移动画笔
LineTo:用当前的画笔划线
Arc:画圆弧 BOOL Arc(HDC hdc, int nLeftRect, int nTopRect, int nRightRect,int nBottomRect, int nXStartArc,int nYStartArc,int nXEndArc,int nYEndArc);前4个是画圆弧的矩形,后四个指定了弧开始和结束的位置 作业:画一条正弦曲线
使用SexPixel,LineTo,MoveToEx实现
(3)画面
画面就是用画刷来填充 步骤
1、创建画刷CreateSolidBrush(颜色)
2、将画刷选入设备上下文SelectObject
3、用画刷填充
4、将画刷选出设备
5、删除创建的画刷对象
用蓝色画刷填充矩形,矩形的边框是黑色。CreateSolidBrush:创建颜色画刷
Rectangle:绘制矩形,用当前的Pen绘制边框,用当前的Brush来填充矩形内部 FillRect:画刷填充矩形。FillRect(hdc,&RECT,HBRUSH)
使用FillRect不绘制边框,因为参数中有画笔,也不用SelectObject了。Ellipse:椭圆,圆。画边框,填充 Pie:圆饼(4)位图
将文件系统中的位图显示到窗口中。绘制位图步骤
1、根据现有的设备上下文创建兼容的设备上下文
2、加载位图
3、绘制图像
4、删除加载的位图
5、删除兼容的设备上下文
BitBlt是在设备上下文之间拷贝图像的函数,非常常用
在上一个列子的基础上,得到位图的大小并绘制实际大小的位图 作业:
在一个窗口上显示一副位图文件(*.bmp)。(5)字体和文本
创建逻辑字体并显示文本 步骤
1、创建逻辑字体
2、选入字体
3、输出文本
4、选出字体
5、删除字体
另一个与文本绘制有关的功能更强的函数是DrawText 总结:本课介绍了一些基本的绘图操作,其中涉及了较多的函数,这里只是介绍了基本的使用方式和原理。函数 srand rand GetClientRect SetPixel LineTo MoveToEx CreatePen CreateSolidBrush CreateFontIndirect BitBlt SelectObject DeleteObject CreateCompatibleDC LoadImage Rectangle FillRect DeleteDC 等等。
第五课 常用控件的使用(6学时)
在上面的几节课程中我们学习了如何建立Windows 应用,并在图形环境下绘制图形。这些操作都是控制台应用中没有的。本章我们介绍如何在窗口中加入按钮等常规控件,并且处理它们。
一般控件种类,按钮,列表组合,编辑,列表,滚动条,静态文本。控件是一种特殊的窗口。这些特殊窗口的类已经由Windows系统注册了,不需要我们注册。这些类的名字分别为。
BUTTON,COMBOBOX,EDIT,LISTBOX,SCROLLBAR,STATIC(1)创建
任何时候均可,但通常在WM_CREATE事件中处理
WM_CREATE是在窗口创建时触发 WM_DESTORY是在窗口销毁时触发
控件用CreateWindow创建,返回控件窗体的句柄,窗体的类型一定为WS_CHILDWINDOW。附加的类型以或关系叠加。具体要参见MSDN(2)操控
控制这些控件是通过向这些控件的窗体句柄发送特点消息来实现的 如 SendMessage(控件句柄,消息指,参数1,参数2)具体设置参见MSDN 在上面的例子,我们处理下拉列表的时候使用了SendMessage发送消息(3)反馈
我们操作控件会触发控件的事件得到一些反馈,下面介绍如何得到这些反馈。总体上,我们把这些反馈过程叫通知。通知的过程是将反馈发送给父窗体,一般父窗体有两个事件接收控件的反馈
WM_NOTIFY,WM_COMMAND。WM_COMMAND HIWORD(wParam)通知消息号 LOWORD(wParam)控件标识 WM_NOTIFY wParam :控件标识 lParam:NHMDR的指针
比如按钮的单机对应的事件是BN_CLICKED。该事件通过WM_COMMAND通知。
我们把上个例子补充完整,并且为每个控件指定ID,指定的方式是在(HMENU)的后面写个整数,原则上应该不同。
HIWORD,得到一个字的高字节。LOWORD得到一个字的低字节。(4)通用控件
我们上面介绍的是基本的控件,除了这些基本控件外还有一些通用控件。这些控件的使用和处理和基本的控件差不多,但功能更强大。ANIMATE_CLASS : 动画控件,播放AVI动画 DATETIMEPICK_CLASS :日期时间下拉控件 HOTKEY_CLASS :定义热键的控件 MONTHCAL_CLASS : 月份选择控件 PROGRESS_CLASS :进度条控件 REBARCLASSNAME :rebar控件 STATUSCLASSNAME:状态条控件 TOOLBARCLASSNAME :工具条 TOOLTIPS_CLASS :提示控件 TRACKBAR_CLASS :轨迹条 UPDOWN_CLASS :上下箭头
WC_COMBOBOXEX :组合框扩展 WC_HEADER :头控件
WC_IPADDRESS :IP地址控件 WC_LISTVIEW :listview控件
WC_PAGESCROLLER :页滚动控件 WC_TABCONTROL :tabControl控件 WC_TREEVIEW :树视图控件
通用控件在使用前使用InitCommonControlsEx初始化。使用这些通用控件要include
头部
这些控件和IE有关系,根据IE版本不同,控件的外观和功能有区别。
(5)创建菜单
CreateMenu:创建一个菜单
CreatePopupMenu:创建一个子菜单 AppendMenu:向菜单增加项目 SetMenu:将菜单联系到窗口
第六课 进程及线程(2学时)
进程:是一个正在运行的程序的实例。由两个部分组成
1、一个是操作系统用来管理进行的内核对象。内核对象是系统用来存放关于进程信息的地方。
2、地址空间,每个进行都有自己的地址空间
进程本身不执行代码,进程要至少拥有一个线程,由线程来执行代码。每个线程都拥有自己的CPU寄存器和堆栈。当创建一个进程时系统会自动创建一个主线程。
CreateProcess创建进程
内部执行细节:1 创建一个小的结构存放进程信息分配地址空间
创建一个小的结构存放线程信息
执行C/C++启动代码,最终会调用WinMain或main。结束一个进程 TerminateProcess
TerminateProcess 1 使用ToolHelp遍历系统进程
列举系统全部的进程
需要
#include
线程
线程由两个部分组成 内核对象 线程堆栈,用于维护执行代码时所有的函数参数和局部变量 进程是活波的,进程不执行任何东西,它是线程的容器。线程在进程的地址空间中执行代码。如果一个进程拥有多个线程则这些线程共享进程地址空间内的代码和数据。进程的地址空间要比线程占用更多的系统资源,因此要更多的使用线程。每个线程必须有个入口点函数,主线程是main,WinMain。如果要创建一个线程,则这个线程的函数原型是这样的。DWORD WINAPI ThreadProc(PVOID pvParm){
return value;} 因为线程会共享全局变量,因此多线程应该少使用全局变量 1 线程创建
线程的创建不能直接使用CreateThread API函数。而要使用C编译环境自带的创建进程函数。
#include
unsigned uThreadid=0;uintptr_t hThread=
_beginthreadex(NULL, 0,ThreadProc,NULL,CREATE_SUSPENDED,&uThreadid);第3个参数是线程函数地址,第4个参数是传递到线程的LPVOID,第5个参数为0线程马上运行、CREATE_SUSPENDED需要激活才能运行。最后一个保存线程的ID 进程和线程ID是一个标识。不重复。进程和线程对象是系统对象,关闭这些对象对进程和线程的运行没有影响。
第7课 线程的调度和同步(6学时)线程暂停:
创建时使用CREATE_SUSPENDED创建一个暂停的线程
使用SuspendThread暂停线程
长时间不使用窗体 恢复线程:
ResumeThread
ResumeThread和SuspendThread使用次数要对应。
休眠线程 Sleep(毫秒)线程的同步是比较容易出错的地方,要多多实践和理解。参见线程冲突的例子。
每个线程对变量g累加10000次,创建6个线程,这是其中一次的运行结果。可以看到结果不是60000.对线程冲突问题的解释
一条C的g++对应的汇编指令为3条 mov eax,[g] inc eax mov [g],eax
如果我们创建两个线程,这两个线程将共享上面的代码。如果只有一个CPU的话,那同一时刻只能志执行一条汇编指令。但Windows的调度机制可以保证代码按顺序执行,但不能保证不被打断。举例 g=0 mov eax,[g] //1 eax=0 inc eax
//1 eax=1 mov [g],eax //1 g=1 eax=1 mov eax,[g] //2 eax=1 inc eax
//2 eax=2 mov [g],eax //2 g=2 eax=2 1和2两个线程分别执行上面的3行代码,则g被加了两次,得到2。但实际上这是多线程的特例。真实的情况是CPU下条要执行那个线程的代码是随机的。如下
g=0 mov eax,[g] //1 eax=0 inc eax
//1 eax=1 mov eax,[g] //2 eax=0 inc eax
//2 eax=1 mov [g],eax //2 g=1 eax=1 mov [g],eax //1 g=1 eax=1
线程1在增加后没有及时赋值给g,然后线程2执行。最后g为1。这就是线程没有同步导致的问题,也是我们程序中出现的问题。解决方法(1)原子操作函数
使用InterlockedExchangeAdd,加减
InterlockedExchange 赋值
InterlockedCompareExchange 比较赋值
使用这些函数加减变量,保证只有执行完后其他进程才能进入。
结果是60000了,但是按理应该输出六次“线程运行了结束了”。但只显示两次,其实每次的结果多不会一样。这也是并发带来的问题。
解决方法(2)关键代码段
在使用关键段之前使用该函数
输出了6次,但每次对应的g值不一定以10000递增。如果把进入关键段的位置提前到最前面可以得到常规的理解
这时这6个进程某种意义上没有并发执行。
局限:关键代码段只能在一个进程内使用,没有等待时长的限制容易死锁。解决方法(3)内核对象 具备通知状态的内核对象 进程 线程 作业
文件修改通知 事件
可等待定时器 文件 信标
控制台输入 互斥对象 举个例子
取消注释后,一次显示一个。体现了该函数对线程的控制。
(1)事件控制
尽管WaitForSingleObject可以等待很多对象的反应,但其主要还是用来处理事件等对象。事件是一种内核对象,有两个状态,一个用于表示该事件是自动重置事件还是人工重置事件。人工重置事件等待该事件的线程都会得到通知,自动重置事件只有一个线程会得到通知。另一个是事件的通知状态。一是未通知状态线程等待,一个是已通知状态,线程运行。CreateEvent(NULL,自动(false)还是手工(true),通知(true)未通知(false)。HANDLE CreateEvent(LPSECURITY_ATTRIBUTES lpEventAttributes,BOOL bManualReset,BOOL bInitialState,LPTSTR lpName);最后一个是为事件起个名字,同名事件不能建立两次。保证同名事件只能建立一次,可以为空。SetEvent:设为已通知状态 ResetEvent:设为未通知状态
OpenEvent:打开一个已经存在的时间,返回Handle
创建自动通知,立即通知事件
对自动通知事件SetEvent有意义,对手工通知事件无意义。手工通知同时显示6个窗口,自动通知一次显示1个(2)信标内核对象
使用信标可以确定让几个线程同时运行
CreateSemaphore(NULL,初始数,最大数,名称)OpenSemaphore
最多同时有3个线程运行。(3)互斥对象
互斥对象和关键代码段的作用相同,效率比关键代码段低。但运行不同进程间使用互斥对象,同时可以设置最大的等待时长。互斥对象和其他内核对象的区别,互斥对象可以记录调用的线程ID,一旦线程得到该对象同线程的其他地方的等待将不会等待。CreateMutex(NULL,初始等待,名称)OpenMutex(0,NULL,名称)ReleaseMutex(HANDLE),只能是否本线程得到的对象
(4)
第三篇:编程入门基础知识点总结
一、常量
数字常量
i.普通数字:1,35,2.7 ii.指数形式:2.45e-2等价于2.45*10-2 注意e大小写皆可,e前面的数字不能省,就算是1也不能省,后面的数字一定要是整数
iii.长整型,单精度浮点型:3235L,32.5F 分别表示3235是长整型数据,32.5是单精度浮点型左,若不写上L,F则表示3235是整型,32.5是双精度浮点型,L,F大小写皆可
字符常量
i.普通字符常量:用单引号把一个字符括起来,如‟A‟,‟@‟
ii.转义字符常量:一对单引号括起来并以“”开头的字符序列,如‟n‟(回车)、‟123‟(8进制123对应的字符), ‟x23‟(16进制23对应的字符) 字符串常量
用一对双引号把一个字符序列括起来,如“ABCef”,系统存放字符串常量,每个字符分配一个字节,各字符所占字节紧邻,并且字符串末尾会给再开一个字节里面放一个’ ’做为结束标志。
符号常量
定义格式 #define 符号常量名 符号常量值,如#define N 20则定义了符号常量N,其值为20,注意符号常量名和符号常量值之间是用空格隔开,而不是写上=号,#define和符号常量名之间也有空格的。
题目:P7—1,5,6,7,9,10
二、标识符
命名规则
以数字,字母,下划线这三类字符组成,但只能以字母或下划线开头,而不能也数字开头,另外不能将关键字做为标识符。32个关键字表在P365附录B 变量名,函数名,符号常量名全都是标识符 题目:P7—2,3,4
三、变量
变量的定义格式
类型名 变量名;如 int a;定义了一个整型常量a。变量名是由人类随便定义的,符合命名规则的前提下,爱写啥就写啥。所以什么flag,cc,y1或者函数名fun,find等全部是自定的用来做为名字而已,没有更特别的意义。
类型名
int 整型,long 长整型: 用于存放整数,只是数值范围不同
float 单精度浮点型 double 双精度浮点型:用于存放实数,数值范围,精度不同
char字符型:用于存放字符
变量赋值,初始化
int a=3;定义的同时初始化
a=6*9;定义后在程序中进行赋值
变量的值
只有在赋值操作时才会被改变,即将其放在等号左边时才会改变它的值,或自增自减操作:a=5,a++,a--,像a+3并未改变a的值,只是使用了a的值而已. 自增自减运算
变量++,++变量,变量--,--变量
使变量的值自增1或自减1 等价于 变量=变量+1 变量=变量-1 ++,--放于变量前后效果的区别:
当自增自减运算做为表达式的一部分时,++,--放在变量前面是先自增自减再使用变量的值,放在变量后面则是先使用变量的值,再自增自减。如x=3;printf(“%d”,++x);则相当于执行了++x;printf(“%d”,x);这样的操作所以打印出4 再如x=3;printf(“%d”,x++);则相当于执行了printf(“%d”,x);x++;这样的操作,则打印出3,当然最后x的值还是4。
四、表达式
运算符和运算对象
一个运算符都有若干个运算对象,如 + 必然要跟两个运算对象才能进行加法运算:3+5。C语言里称需要跟n个运算对象的运算符为n元运算符。一元运算符有:!,(类型名)二元运算符有:+,-,*,/,%(求余), =,+=,-=,*=,/=,%=,< , > , <=, >=, = =(等于),!=(不等于),&&(且), ||(或)多元运算符有:, 运算符的优先级和结合性
i.优先级:同一个运算对象左右两边若同时有两个运算符,则这两个运算符优先级高的先进行运算。
ii.结合性:若同一个运算对象左右两边的两个运算符优先级相同,则根据结合性判断先进行哪个运算,自左自右结合性的先算左边的运算符,自右自左的先算右边的运算符。
iii.各运算符的优先级和结合性见P365附录C 强制类型转换
格式:(类型名)表达式。将后跟的表达式的值的数据类型转换为与圆括号内的类型名一致的类型。注意类型名一定要用()括起来。
算术表达式
i.算术运算符:+,-,*,/,%(求余)ii.由算术运算符加上运算对象构成算术表达式,如3+3*6-9/2 iii.值:跟我们小学时学的一样,就是表达式的计算结果 iv.整数除以整数结果取整数部分,故1/3得到的值是0 v.5%3 结果为2,想想小学除法,求余得到的是余数不是商。 赋值表达式
i.赋值运算符:=,+=,-=,*=,/=,%= ii.赋值表达式:变量=表达式,如x=3+6,x+=6-9,x+=x*=3+4 注意等号左边只能是变量
iii.复合赋值运算符的运算:以/=为例:x/=表达式 等价于 x=x/(表达式)iv.值:=号左边的变量最终的值 关系表达式
i.关系运算符:< , > , <=, >=, = =(等于),!=(不等于)ii.由关系运算符加上运算对象构成关系表达式,如3>=4, 2==a iii.值:满足相应运算符所指定的关系的值为1,否则为0 逻辑表达式
i.逻辑运算符:&&(且), ||(或),!(非)ii.由逻辑运算符加上运算对象构成逻辑表达式,如3&&4, x||!y iii.值:满足相应运算符所指定的关系的值为1,否则为0 iv.进行 ||或 运算时,若||左边的表达式值为1,则不再对右边的表达式v.进行运算。进行 &&且 运算时,若&&左边的表达式值为0,则不再对右边的表达式进行运算。 逗号表达式
i.逗号运算符:,ii.用逗号将各种表达式连续起来构成逗号表达式,如3+4,a=9,8*a iii.值:组成逗号表达式的各个表达式中的最后一个的值,如上例为8*a 题目:P7—11~17 P8—18~33
五、输入输出函数
scanf(“格式控制串”,变量地址表列);如scanf(“%d%c%d”,&a,&ch,&b);
scanf(“%4f”,&x);注意:
i.格式控制串可控制截取用户输入的前几个字符给变量,但不能控制输入几位小数给变量,如不能写成scanf(“%4.2f”,&x);ii.第二个参数给的是地址,即要么是&+变量名或数组元素名的形式,要么就是一个数组名或指针变量名,如int *p,a;p=&a;scanf(“%d”,p);iii.考试时注意看题目给你写好的scanf的格式 1.若其格式控制串内各格式符用“,”隔开如scanf(“%d,%c,%d”,&a,&ch,&b);那输入时也要用逗号隔开,如此例输入时应:3,+,5 2.若是这种格式scanf(“%d %d”,&a,&b);则输入时应:3 5;3.若是这种格式scanf(“%d%c%d”,&a,&ch,&b);则输入时应3+5,若写成3 + 5则a=3,ch=‘ ’(空格),b=任意值
(自己上机运行看看结果)
printf(“格式控制串”,输出项表列);如float x=7.5;printf(“%8.2f”,x);此处的意思是将x打印出来,且占8列,保留两位小数。自己上机运行看看效果。
常用格式符汇总:
i.%d:输入输出整型数据,%ld:输入输出长整型数据 ii.%c:输入输出字符型数据
iii.%f:输出单(双)精度浮点型数据,输入单精度型数据。
%lf:输入双精度型数据
iv.%s:输入输出一个字符串,用printf输出字符串时,输出项书写时可
为字符串常量,或字符数组名。如printf(“%s”,”hello”);或char str[10]=”hello”;printf(“%s”,str);v.%u:输入输出无符号整型,%o:输入输出八进制数,%x:输入输出十六进制数
getchar();函数调用后返回用户输入的一个字符,故需再定义一个变量来存放这个字符,即使用时应 char c;c=getchar();意思就是接收用户输入的一个字符,并将其赋值给变量c。
putchar(字符常量或字符变量名);
如char c=‟A‟;putchar(c);或putchar(„A‟);都会向屏幕输出字符A。
六、C语言的语句
表达式语句:由表达式末尾加上分号构成。
函数调用语句:由函数调用表达式加上分号构成。空语句: ;
选择结构语句:if语句 switch语句
循环语句:for语句 while语句 do while语句
复合语句:用花括号{}将以上任意语句括起来构成一条复合语句。
七、C程序的基本结构
void main(){
声明部分:用来定义变量和声明自定义函数的原型,需以“;”结尾,如int x;
执行语句部分:第六点里介绍的各种语句,如x=3;printf(“%d”,x);} main函数外可写自定义函数。如 int max(){
return 0;}
八、选择结构语句
if(表达式)语句1 else 语句2
如果if语句的圆括号内的表达式值为非0,则执行语句1,值为0则执行语句2。
i.表达式可为任意表达式,if语句执行的实质是判断表达式的值是否为0来决定执行语句1还是语句2。另外请在此处表达严重关切,不管是高ii.手还是菜鸟经常会把判断两个数相等的符号“==”写成了一个等号“=”成为了赋值运算,这样的写法不会引发编译错误,但结果会与原意大大不同,所以考试前请再三提醒自己。
语句1和语句2都只能是一个语句,若要跟多条语句,切记用一对{}括起来,构成复合语句;也不要随便在圆括号后加“;”,因“ ;”构成一条空语句,这会使后面跟的语句1不再属于if语句的组成部分。
iii.if语句的三种结构
1.单边: if(表达式)语句
2.双边:if(表达式)语句1 else 语句2 3.多层(重点掌握): if(表达式1)语句1 else if(表达式2)语句2 else if(表达式3)语句3 …
else 语句n 条件运算符 表达式1? 表达式2 : 表达式3
若表达式1的值非0,则取表达式2的值做为整个表达式的值,否则取表达式3的值为整个表达式的值。如 3>4? 1:2 该表达式的值为2 switch语句
switch(表达式){ case 表达式1:语句
case 表达式2:语句
…
case 表达式n:语句
default: 语句 } 语句执行过程:先计算表达式的值,然后判断该值与表达式1到表达式n中的哪个相等,若与表达式i的值相等,则执行表达式i后的所有语句,当遇到break;语句时结束整个switch语句的执行。表达式1到表达式n的值都不相等的情况下执行default后跟的语句。每个case后可跟多条语句。
九、循环结构
for循环语句
for(表达式1;表达式2;表达式3)循环体语句 语句执行过程: 1.计算表达式1 2.判断表达式2的值是否为0,若为0,语句执行结束,若不为0,进入步骤3 3.执行循环体语句(需注意的是循环体语句只能有一个语句,若要包含多个语句要用一对{}括起来,构成一条复合语句,此处也不要随便加上 “;”,因一个“;”可构成一条空语句,这会使得后面真正的循环体语句不属于for循环语句的部分)。进入步骤4 4.计算表达式3,然后重新进入步骤2 while循环语句 do while循环语句
i.while(表达式)循环体语句 执行过程:
1.判断表达式的值是否为非0,若是进入步骤2,否则结束语句执行。2.执行循环体语句,重新回到步骤1。ii.do 循环体语句
while(表达式); 执行过程:
1.执行循环体语句,进入步骤2
2.判断表达式的值是否为非0,若是重新回到步骤1,否则结束语句执行。
这里要注意的地方跟for语句一样,即循环体语句只能有一个语句,若要包含多个语句要用一对{}括起来,构成一条复合语句,此处也不要随便加上 “;”,因一个“;”可构成一条空语句,这会使得后面真正的循环体语句不属于while循环语句的部分,另外do while循环的while(表达式)后是要加“;”的。 break语句:放在循环体内实现的功能是结束其所在的那层循环的执行。
十、数组
定义格式:数据类型
数组名[整型常量];如 int a[10];定义了一个整型数组,数组名为a,这个数组含有10个元素。
引用数组元素: 格式:数组名[下标]
切记下标值从0开始。下标可为常量,表达式,变量等,如int i=3; a[0]=5;a[3*2]=9; a[i]=7;
初始化:数据类型
数组名[整型常量]={数据表列};将数据表列的各个值依次赋值给数组的各个元素。如int a[5]={0,1,2,3,4};则数组a各元素a[0]到a[4]的值分别为0,1,2,3,4 遍历数组元素
数组定义后,我们不能对数组进行整体的操作,如int a[10];不能用a=3这样的操作将数组的各元素都赋值为3;而只能一个一个元素的进行赋值,如a[0]=3;a[1]=3;a[2]=3…a[9]=3; 当然此时我们就可以借助于一个for循环来控制下标的变化从而对数组的各个元素进行赋值 for(i=0;i<10;i++)a[i]=3;
当然这只是用for循环遍历数组各元素的最简单的例子,一般考试考的是找出数组元素的某种特性的极值,比如最大值,最小值,或对数组各元素进行排序,这时我们就可以使用for循环来遍历数组的各元素,然后在当前循环中得到一个元素再对其进行处理。如i=2时访问到的元素是a[2],你就可以问问它,你是不是最小值啊。 整型数组
int a[10];整型数组里的各个元素存放的是整数。a[3]=3; 字符型数组
char str[20];字符型数组里的各个元素存放的是字符。
str[3]=‟A‟;
十一、字符串函数
gets(字符数组名或字符指针变量);
如char str[10],* str2;str2=str;则gets(str);或gets(str2);都是接收用户输入的字符串如“ABC”存入到字符数组str中
puts(字符数组名或字符指针变量或字符串常量);
如char str[10]=”china”;char *str2;str=str2;则puts(str);或puts(str2);或 puts(“china”);都会在屏幕上打印出 china strlen(字符数组名或字符指针变量);字符串测长函数
char str[20]=”hello world!”;
int len;len=strlen(str);得出的结果是len的值为12 strcat(字符串1的地址,字符串2的地址);
将字符串2的内容连接到字符串1的尾部。char str1[20]=”ABC”,str2[20]=”xyz”;strcat(str1,str2);
则程序运行的结果是str1内存放的字符串变为ABCxyz,当然str2存放的字符串还是xyz。
strcmp(字符串1的地址,字符串2的地址);
比较串1和串2哪个比较大。比较大小的依据是,两个字符串从左往右相应位置上第一个不相等的字符ASCII码值之差。char str1[20]=”ABCE”,str2[20]=”ABDE”;int i;i=strcmp(str1,str2);第一个不相等的字符为str1的‘C’和str2的‘D’,而二者相差-1,故-1做为strcmp函数执行的结果返回到被调用的位置,该位置位于赋值表达式内,故将其值赋值给i,即此时i的值就是-1. strcpy(字符串1的地址,字符串2的地址);
将字符串2的内容复制到字符串1内。char str1[20]=”ABC”,str2[20]=”xyz”;strcpy(str1,str2);此时str1的内容为”xyz”,当然str2的内容没变 strcpy(str1,”uvw”);此时str1的内容又变成了“uvw“。
十二、函数
函数定义
函数类型
函数名(形式参数列表){
内部变量定义和声明部分
执行语句
} 如:
int max(int x , int y){ int z;
z= x > y ? x : y;
return(z);} 注意点:
1.函数类型是指返回值的类型,即要与return语句后跟的表达式的值的类型一致。若函数类型为void则说明该函数无返回值,即函数体里不能出现return 语句。2.形式参数列表里定义的变量要记得给它们指定类型,而且如果同时要定义多个,应在每个前面都分别指定类型名,而不能写成int x,y;3.函数体里能写的语句跟main函数一样,在开头可定义所需要的变量,后面跟上一堆执行语句。 函数调用流程
以上面的函数为例,在main函数进行调用: void main(){ int a,b,c;
scanf(“%d%d”,&a,&b);printf(“%d”,max(a,b));或 c=max(a,b);printf(“%d”,c)以上两种方法都会在屏幕中打印出a,b间的较大值。
调用函数的格式 函数名(实际参数列表);调用的时候像什么函数类型,形式参数的类型就不要加上去了。max(a,b)中max就是函数名,写上变量名a,b是实际参数列表,执行这个调用语句时,会先把a,b的值给相应位置的形式参数即执行了x=a,y=b这样的操作,然后开始执行max函数的函数体的语句。当max函数体里执行到一个return语句时,则max函数结束执行,将return后的表达式的值返回给main函数调用max函数的那个位置,即若上面a=3,b=5则max(a,b)return后的表达式的值应该是5也就是说执行完max后把5返回到调用max的位置可看成printf(“%d”,5);或另一种解法的c=5。}
十三、指针
指针变量的声明: 类型名 * 指针变量名; 通过指针变量访问它所指向的普通变量的值
先将普通变量的地址赋值给指针变量,再通过指针运算符* 得到普通变量的值。int *p,x,y;x=3;p=&x;则printf(“%d”,*p);会打印出3即x的值 y=*p;则y的值变为3 *p=5;则x的值变为5 指针变量加上(减去)一个位移的效果
若指针变量存入的是数组元素的地址,则其加一减一得到的是那个数组元素下一个或前一个元素的地址。int a[10];p=&a[3];*p得到的是a[3]的值。
若p++;此时p存放的是a[4]的地址&a[4];*p得到的就是a[4]的值。或p--;此时p存放的是a[2]的地址&a[2],*p得到的就是a[2]的值。
行指针
i.主要是对于二维数组来说的,二维数组每行都有自己的地址,第0行地址用 数组名 表示,第i行地址为 数组名+i;而想要得到二维数组里一个元素的地址,必需先得到其所在行的地址,然后再由那个地址得到元素的地址,比如说 int a[3][4];定义了一个二维数组,该二维数组第0行的地址为a,第1行的地址为a+1,第2行的地址为a+2,想从行的地址得到元素的地址,需在行地址前加上指针运算符“*”,即*a就是第0行首个元素的地址即a[0][0]的地址,而a[0][2]的地址就是在a[0][0]的地址基础上加上位移量2,即*a+2,然后想得到a[0][2]这个元素的值呢就再加上一个指针运算符“*”,即*(*a+2),类似地,想得到a[2][2]这个元素的值呢就是*(*(a+2)+2)ii.定义行指针变量: 类型名
(*变量名)[数组长度];
如int(*p)[4],a[3][4];p=a;此时就可把p当成a来用,用法同上所述。
判断是否合法访问数组元素:若是指针法访问,判断指针后跟的是否地址;若是下标法访问,判断下标有无越界。
函数指针:函数名即为函数的地址(指针)
i.函数指针变量的定义: 类型名(*变量名)(形参列表);如 int(*p)();ii.赋值:指针变量=函数名;设有个函数其函数名为max,则要将该函数的地址给p的话只要执行如下语句即可 p = max;
指针数组:指针数组的数组元素都是指针变量,是用来存放变量的地址的,定义格式为 类型名 * 变量名[数组长度];如int * p[10]; 指向指针的指针:指针变量也是一种变量,故在内存中也有对应的一个地址,而要存放指针变量的地址,就要求助于用来存放指针变量的地址的指针变量,定义格式
类型名 ** 变量名;如 int *p1;int **p2;int a=3;可进行赋值p1=&a;p2=&p1;则a、*p1和 **p2的值都是3.十四、宏定义
无参宏定义 #define 标识符
值
定义后,出现所定义的标识符的地方都将以定义时指定的值来代替。
#define M 2+3 main(){ int x;
x=M*M;则x的值为2+3*2+3=11若想得到的结果是(2+3)*(2+3)则定义时也写成这样 #define M(2+3)} 注意#define、标识符、值之间都要用空格隔开,且宏定义结尾不需加分号。 带参宏定义
#define 标识符(参数表)值
#define S(x,y)x*y main(){ int a=3,b=4,c=5,d=6;
printf(“a*b=%dn”, S(a,b));此时会打印出 a*b=12
printf(“a+b*c+d=%dn” , S(a+b,c+d));此时会打印出a+b*c+d=29,带参宏定义执行时是将a+b这样一个表达式代替x,c+d这样一个表达式代替y,所以S(a+b,c+d)进行的是a+b*c+d的运算,而不是将a+b的值给x,c+d的值给y然后再做x*y,这点跟函数调用传递参数是不一样的。}
自定义类型名typedef:对已存在的类型名取一个外号。
i.基本格式:typedef 原类型名
新类型名;ii.typedef int INTEGER;则int a,b;等价于INTEGER a,b;iii.typedef int NUM[10];则 int a[10];等价于 NUM a;a即为一个有10个元素的数组的数组名。
iv.typedef int * INTEGER;则int *a,*b;等价于INTEGER a,b;
十五、结构体,共用体,枚举类型
结构体
i.结构体类型的定义及变量的定义
struct 结构体名
{类型 成员1;
类型 成员2;
……
类型 成员n;
}变量名;如
struct student { char name[10];long num;int score[4];}st1;定义类型时同时定义变量
struct student st2;定义类型后,用类型名定义变量 还有一种 struct
{ char name[10];long num;int score[4];}st3;不给类型名,直接定义变量
ii.结构体变量所占字节数:各成员各占字节数之和,如以上st1,st2,st3的字节数皆为10+4+2*4=22 iii.结构体数组的定义及初始化
struct student a[3]={{ “zhang”,20030001,89,90,91,92},{“liu”,20030002,68,69,70,71},{“li”,20030003,57,58,59,60} } iv.结构体成员的访问
1.结构体变量名.成员名 如st1.name[2] 2.通过指针访问:struct student *st;st=&st1;(*st).num 或 st->num 共用体
i.共用体类型的定义及变量的定义
union 共用体名 { 类型
成员名1;
…
类型
成员名n;
};
变量的定义与结构体类似,也有三种方法。union data {
int i;char ch;float f;}d1;定义类型时同时定义变量
union data d2;定义类型后,用类型名定义变量
union {
int i;char ch;float f;}d3;不给类型名,直接定义变量
ii.共用体变量所占字节数:各成员所占字节数的最大值,如上d1,d2,d3所占字节数皆为4.(单精度浮点型变量所占字节数最多为4).iii.共用体成员的访问
1.共用体变量名.成员名 如d1.f 2.通过指针访问:union student *d;d=&d1;(*d).num 或 d->num 枚举类型
i.枚举类型的定义:
enum 枚举名{枚举元素名1,枚举元素名2,…,枚举元素名n}; ii.枚举元素的值:
默认值分别为0、1、…、n-1。枚举元素的值也可在定义时重指定,对于没有指定值的元素,按顺序加1
如enum weekday{sun=7,mon=1,tue,wend,thur,fri,sat};则sun值为7,mon值为1,tue值为2,wend值为3,thur值为4,fri值为5,sat值为6
十六、Turbo C的使用
菜单激活: F10
菜单切换:左右方向键在不同菜单间切换,上下方向键在同一个菜单不同选项间切换。
载入文件:两种方法:1.找到源文件所在位置,直接将其拉到Turbo C快捷方式上;2.F3 运行程序: ctrl+F9
看程序运行结果:alt+F5 进入编辑状态:菜单Edit 保存: F2
插入状态切换: Insert键
第四篇:Windows编程_实验2指导
Windows编程/附件资料2
实验2MFC 框架程序的分析认知与编程实践(4学时)
一、实验目的:
熟悉在Visual C++ 6.0 IDE中编辑、编译、调试和运行一个MFC应用程序的基本思路;理解并掌握利用MFC开发应用程序的一般步骤和过程;加深对MFC框架程序的特性认识,掌握其应用方法。了解构件式的软件开发思想;提高实际动手编制WinApp的能力和分析问题、解决问题的能力。
二、实验内容:
1、分析理解题:利用MFC AppWizard分别创建最基本的基于对话框的应用程序,单文档应用程序和多文档应用程序;并从类/文件/资源等视图角度分析比较它们各自所自动拥有的类(基类)/文件(主要是.cpp文件)/资源的异同,回答其后(即四所列)思考题;要求在实验报告中反应分析比较情况及你的认知理解点滴。(必做)
2、程序设计题:以MFC编程方式,编写并实现一个简易计算器功能的应用程序。其界面架构形式和具体内容自我设计,原则:架构美观、布局合理,内容实用,具有可计算特性。
3、以MFC编程方式,编写并实现一个SDI界面的“奥运五环”绘图应用程序。(提高)提示:编写在窗口客户区上“绘制一张笑脸”的WinApp。
1)若用SDK API方式编程,则其WM_PAINT消息的响应代码为:
case WM_PAINT:
hdc=BeginPaint(hwnd,&ps);
hPen=CreatePen(PS_SOLID,5,RGB(255,0,0));
SelectObject(hdc,hPen);
Ellipse(hdc,275,170,425,320);
Arc(hdc,360,215,410,240,410,225,360,225);
Arc(hdc,290,215,340,240,340,225,290,225);
Arc(hdc,320,240,380,300,320,270,380,270);
EndPaint(hwnd,&ps);
return 0;
2)若以MFC方式编程,则可利用MFC AppWizard建立一个SDI界面的应用程序框架,然后在其视类的OnDraw()中加入如下代码也可。
CPen pen,*oldpen;
pen.CreatePen(PS_SOLID,2,RGB(255,0,0));
计算机科学系XYP编制2011-5-18第1 页
oldpen=pDC->SelectObject(&pen);
pDC->Ellipse(275,170,425,320);
pDC->Arc(360,215,410,240,410,225,360,225);
pDC->Arc(290,215,340,240,340,225,290,225);
pDC->Arc(320,240,380,300,320,270,380,270);
pDC->SelectObject(oldpen);
三、实验要求:
通过本次实验,要求同学们能对利用MFC AppWizard、ClassWizard等实用工具编写WinApp的方法、步骤有一个较为全面的了解,并注意理解由MFC AppWizard所生成的WinApp框架的组织架构和作用;深刻理解在此基础上开发WinApp的主要工作是“填充框架和添加必要的实现代码”的含义,切实做到用理论指导实践,以实践促进理论,提高实际动手能力和再学习的能力。具体要求如下:
1、实验前认真准备、仔细计划,查找相关资料,写出预做报告,促进理性思维能力;
2、实验中以理性实践的态度,积极思考,认真领悟实验过程出现的各种实验现象,注意总结积累经验,完成实验要求,达到实验目标,提高应对问题、解决问题的能力;
3、实验后按要求及时、认真地完成实验报告,按时提交。
特别强调,注意实验报告内容的完整性、真实性和个异特点,使我们的两个能力:动手和持续学习能力真正得到提高。
四、思考题:
1.在MFC应用程序中,至少必须包含几个类?它们分别是什么类?
2.由MFC AppWizard生成的应用程序,都有哪些主要文件?包含哪些类及相关类的对应功能和它们之间的关系怎样?
3.控件使用中应特别注意哪些问题?
4.在使用编辑框时,应注意哪几点?
5.ClassWizard使用中,应关注的主要问题是什么?注意哪些问题?
温馨小贴示:
1.MFC应用程序必须包含的两个基本类是CWinApp类和CFrameWnd类。CWinApp类替代了API应用程序中的主函数WinMain()功能,封装了与应用程序相关的程序初始化InitApplication()和InitInstance()、消息循环Run()和程序结束ExitInstance()等功能;CFrameWnd类替代了窗口函数WndProc()的功能,封装了消息处理和窗口销毁等功能。
2.MFC应用程序消息处理的路径为:应用程序从CWinApp派生对象,其成员函数Run()调用
CWinThread::Run(),通过GetMessage(),TranslateMessage()和DispatchMessage()进行消息循环。每个窗口对象都使用相同的称为AfxWndProc()的全局函数,AfxWndProc()调用OnWndMsg()处理消息。OnWndMsg()负责将收到的消息分为三大类:窗口消息、命令消息和控件消息,再分发给不同的消息处理函数去处理。
3.MFC应用程序的启动顺序:①建立、初始化CWinApp对象,该对象是全局的且只能有一个,名为theApp;②在InitInstance()函数中,创建文档模板,执行MFC框架默认的命令行参数,根椐分解的命令行信息,启动不同类型的任务,动态建立文档、视图、框架,并对文档、视图、框架进行初始化;③显示与更新窗口;④启动消息循环。
五、参考书籍:
1.《Visual C++ 应用教程》·郑阿奇,丁有和 编著·人民邮电出版社2008.10
2.《Visual C++ 实用教程》·周进等 编著·人民邮电出版社2008.5
3.《Windows 程序设计教程》·杨祥金等 编著·清华大学出版社·2007.4
4.《Windows可视化程序设计》·刘振安主编·机械工业出版社·2007.1
5.《Visual C++ 程序设计—基础与实例分析》·朱晴婷等 编著·清华大学出版社2004.3
6.《Visual C++ 6.0实用教程》·扬永国 主编·清华大学出版社·2004.1
7.《C++及Windows可视化程序设计》·刘振安编著·清华大学出版社·2003.7
8.《Windows C程序设计入门与提高》·柳永新等 编著·清华大学出版社·1999.7
肖云萍编写
第五篇:数控编程知识点整理
1. 右手螺旋法则—右手笛卡尔坐标系;定则——回转方向。
2. 坐标轴确定的方法及步骤:Z轴:取产生切割力的主轴轴线X轴:一般位于平行工
件装夹面的水平面内Y轴:根据确定的XZ轴,按右手笛卡尔坐标系确定。ABC:根据XYZ轴,用右手螺旋定则确定,3. 机床坐标系=机械,用来确定编程坐标系的基本坐标系;编程坐标系=工件,供编程用。
4. 加工程序:程序开始部分、若干个程序段、程序结束部分;程序段:程序段号、若干
个字;字:地址符和数字FGLMNOST
5. 手工变成步骤:确定工艺过程、计算刀具轨迹的坐标值、编写加工程序、将程序输入数
控机床、程序检验、首件试加工。
6. 进给功能F:第一次用直线或圆弧插补,必须编写进给率F;F功能为模态指令。
7. M00和M01:程序停止、计划停止
8. M02或M30:该指令表主程序结束,机床停止自动运行。M30还可以使控制返到开头。
9. 编程零点的原则:编程零点应选在零件图的尺寸基准上、对称零件,应设在对称中心、一般零件,应设在工件外轮廓的某一角上、Z轴方向上零点设在工件上表面。顺铣:刀具与工件切进方向相同,精加工。
11.绝对值编程与增量:加工中心用G90、G91区分;车床用坐标表达式 绝xz增UW
12.圆弧插补:0<X<=180,用+R;180<X<360,用—R整圆编程不用R。
13.导程:X-Y-I-J-Z-K-F没有Z,故导程为K
14.G43G44(建立刀具长度正负补偿)G49取消刀具长度补偿G40 取消刀具半径补。
15.G96—r|minG97—m|min代码G98-mmminG99-mmr
16.绝对值编程:G54,G28Z0,M06T01,M03S1000,G00X20Y20Z2,G01Z-3F50,Y50F100,X60,Y20,X20,G00Z100,X0Y0M05,M02
17.增量植编程:G54,G28Z0,M06T01,M03S1000,G00X20Y20Z2,G91G01Z-5F50,Y30F100,X40,Y-30,X-40,G90G00Z100,X0Y0M05,M02