第一篇:GDI+编程小结(二)
http://www.xiexiebang.com/
二、GDI+编程
本部分简单介绍GDI+编程中的一些概念与技巧,具体的编程细节请参考《精通GDI+编程》、陈宝楷《GDI+编程》等书籍。
1、Point、浮点数点类PointF;Size、浮点数大小类SizeF;Rect、浮点数矩形类RectF等。
浮点数版的几何对象和绘图函数,是GDI+新增的功能,这些在各种工程技术领域都非常有用。因为一般的实际图形设计,都是基于实数坐标的。包括机械(机床/汽车/轮船/飞机等)、建筑(房屋/桥梁/道路/堤坝等)和图形动画设计(形状/物体/人物/背景/轨迹等)等设计,都必须使用浮点参数和坐标系。
2、Color:在GDI+中,色彩是通过Color(色彩)类来描述的。Color类的构造函数分别为: Color();Color(BYTE a,BYTE r,BYTE g,BYTE b);Color(ARGB argb);Color(BYTE r,BYTE g,BYTE b);参数:
a:色彩的透明度(0~255)r、g、b:红、绿、蓝3种色彩分量值(0~255)不同于GDI,GDI+在对色彩支持方面主要体现在对色彩的透明度支持。从本质上讲,透明度是像素之间的一种合成运算。它的计算公式是:
输出色彩=前景色*Alpha/255 + 背景色*(255-Alpha)/255
3、Graphics(图形)
图形类Graphics是GDI+的核心,它提供绘制图形、图像和文本的各种方法(操作/函数)(似GDI中的CDC类),还可以存储显示设备和被画项目的属性(到图元文件)。Graphics类及其成员函数都被定义在头文件Gdiplusgraphics.h中。Graphics类的构造函数有如下4种: Graphics(Image* image);// 用于绘制图像 Graphics(HDC hdc);// 用于在当前窗口中绘图
Graphics(HDC hdc, HANDLE hdevice);// 用于在指定设备上绘制图形
Graphics(HWND hwnd, BOOL icm = FALSE);// 用于在指定窗口中绘图可以进行颜色调整 其中,最常用的是第二种——在当前视图窗口中绘图的图形类构造函数。
注意,该构造函数的输入参数,是设备上下文的句柄,而不是CDC类对象的指针。一般可以由CDC对象得到(CDC类含有公用数据成员HDC m_hDC;)6种绘制直线和折线的函数:(前三个为整数版,后三个为对应的浮点数版)// 画折线DrawLines Status DrawLine(const Pen* pen, INT x1, INT y1, INT x2, INT y2);Status DrawLine(const Pen* pen, const Point& pt1, const Point& pt2);Status DrawLines(const Pen* pen, const Point* points, INT count);// 画折线 Status DrawLine(const Pen* pen, REAL x1, REAL y1, REAL x2, REAL y2);Status DrawLine(const Pen* pen, const PointF& pt1, const PointF& pt2);Status DrawLines(const Pen* pen, const PointF* points, INT count);6种绘制矩形和矩形组的函数:(也是前三个为整数版,后三个为对应的浮点数版)// Rectangle = rect angle
http://www.xiexiebang.com/
Status DrawRectangle(const Pen* pen, const Rect& rect);Status DrawRectangle(const Pen* pen, INT x, INT y, INT width, INT height);Status DrawRectangles(const Pen* pen, const Rect* rects, INT count);Status DrawRectangle(const Pen* pen, const RectF& rect);Status DrawRectangle(const Pen* pen, REAL x, REAL y, REAL width, REAL height);Status DrawRectangles(const Pen* pen, const RectF* rects, INT count);绘制椭圆的函数,如果输入参数所确定的外接矩形的宽高相等,则画圆。(也是前两个为整数版,后两个为对应的浮点数版)
Status DrawEllipse(const Pen* pen, const Rect& rect);Status DrawEllipse(const Pen* pen, INT x, INT y, INT width, INT height)Status DrawEllipse(const Pen* pen, const RectF& rect);Status DrawEllipse(const Pen* pen, REAL x, REAL y, REAL width, REAL height);绘制椭圆弧的函数,如果输入参数所确定的外接矩形的宽高相等,则画圆弧。(也是前两个为整数版,后两个为对应的浮点数版)
Status DrawArc(const Pen* pen, INT x, INT y, INT width, INT height, REAL startAngle, REAL sweepAngle);// sweep 掠过
Status DrawArc(const Pen* pen, const Rect& rect, REAL startAngle, REAL sweepAngle);Status DrawArc(const Pen* pen, REAL x, REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle);Status DrawArc(const Pen* pen, const RectF& rect, REAL startAngle, REAL sweepAngle);
画弧函数的输入参数 // 注意:顺时钟方向 该函数的功能与GDI的Arc相同:
BOOL Arc(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4);BOOL Arc(LPCRECT lpRect, POINT ptStart, POINT ptEnd);但是也有区别,主要是,最后的参数不再是弧的终角,而是弧段所对应的扫描角。这倒是与另一个GDI画圆弧函数类似(其中(x, y)为圆心、nRadius为半径、fStartAngle为起始角、fSweepAngle也为弧段跨角):
BOOL AngleArc(int x, int y, int nRadius, float fStartAngle, float fSweepAngle);当然,GDI+确定矩形的后两个参数也不再是右下角坐标,而改成宽高了,这已经是老问题了。另外要注意的是,角度的单位是度(不是弧度,C++的三角函数采用的是弧度单位),而且都必须是实数。零度角为x轴方向,顺时针方向为正(这与数学上反时针方向为正刚好相反)。// 如上图所示。
绘制多边形的函数,第一个为整数版,后一个为对应的浮点数版: Status DrawPolygon(const Pen* pen, const Point* points, INT count);Status DrawPolygon(const Pen* pen, const PointF* points, INT count);其中,各参数的含义同画折线函数DrawLines的,只是DrawPolygon函数会将点数组中的起点和终点连接起来,形成一个封闭的多边形区域。该函数的功能与GDI的Polygon相同:
BOOL Polygon(LPPOINT lpPoints, int nCount);
注意:GDI+中没有提供,与GDI函数RoundRect(圆角矩形)和Chord(弓弦),具有类似功
http://www.xiexiebang.com/
能的绘图函数。可以利用矩形+椭圆和弧+直线等函数自己来实现。在GDI+中画填充图,不需像GDI那样得先将刷子选入DC,而是与GDI+画线状图的函数类似,将刷子作为画填充图函数的第一个输入参数。画填充矩形[组] FillRectangle[s] Status FillRectangle(const Brush* brush, const Rect& rect);Status FillRectangle(const Brush* brush, INT x, INT y, INT width, INT height);Status FillRectangles(const Brush* brush, const Rect* rects, INT count);Status FillRectangle(const Brush* brush, const RectF& rect);Status FillRectangle(const Brush* brush, REAL x, REAL y, REAL width, REAL height);Status FillRectangles(const Brush* brush, const RectF* rects, INT count);用指定刷子Brush,填充rect的内部区域,无边线,填充区域包括矩形的左边界和上边界,但不包括矩形的右边界和下边界。功能与GDI的FillRect类似: void FillRect(LPCRECT lpRect, CBrush* pBrush);但是,GDI中没有同时填充一个矩形数组的函数。不过GDI却有GDI+没有的画填充圆角矩形的函数FillSolidRect。画填充[椭]圆FillEllipse Status FillEllipse(const Brush* brush, const Rect& rect);Status FillEllipse(const Brush* brush, INT x, INT y, INT width, INT height);Status FillEllipse(const Brush* brush, const RectF& rect);Status FillEllipse(const Brush* brush, REAL x, REAL y, REAL width, REAL height);GDI中没有类似函数,但可以用(采用当前刷填充的)Ellipse来代替。画饼图DrawPie // pie馅饼
DrawPie与FillPie Status DrawPie(const Pen* pen, const Rect& rect, REAL startAngle, REAL sweepAngle);Status DrawPie(const Pen* pen, INT x, INT y, INT width, INT height, REAL startAngle, REAL sweepAngle);Status DrawPie(const Pen* pen, const RectF& rect, REAL startAngle, REAL sweepAngle);Status DrawPie(const Pen* pen, REAL x, REAL y, REAL width, REAL height, REAL startAngle, REAL sweepAngle);与GDI的下列函数类似,但是部分输入参数的含义有所不同:
BOOL Pie(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4);BOOL Pie(LPCRECT lpRect, POINT ptStart, POINT ptEnd);
画填充多边形FillPolygon Status FillPolygon(const Brush* brush, const Point* points, INT count);Status FillPolygon(const Brush* brush, const Point* points, INT count, FillMode fillMode);Status FillPolygon(const Brush* brush, const PointF* points, INT count);Status FillPolygon(const Brush* brush, const PointF* points, INT count, FillMode fillMode);前面讲的各种画线状图或填充图的GDI+函数,虽然在形式上与GDI的有所不同(函数名前加了Draw或Fill、将笔或刷作为第一个输入参数、部分位置输入参数改成了大小参数、并增加了浮点数版),但是在功能上却是相同的。
现在要讲的曲线绘制,则是GDI+新增加的内容。曲线在机械设计、工程建筑和图形动画等领域,都有十分广泛应用。
常用的曲线有Bezier(贝塞尔)曲线和样条(spline)曲线。贝塞尔曲线比较简单,适合于
http://www.xiexiebang.com/
画控制点少的曲线。当控制点太多时,要不曲线的次数(比点数少1)太高,要不拼接比较困难,而且没有局部性(即修改一点影响全局),性能不太好。而样条曲线则可以画任意多个控制点的曲线,曲线的次数也可以指定(一般为二次或三次,如TrueType字体采用的是二次B样条曲线),并且具有局部性。贝塞尔曲线特别是样条曲线有很多变种。常见的贝塞尔曲线有普通贝塞尔曲线和有理贝塞尔曲线。常用的样条曲线有:B样条、β样条、Hermite(厄密)样条、基数样条、Kochanek-Bartels样条和Catmull-Rom样条等。
GDI+中所实现的是普通贝塞尔曲线(不过控制点,位于控制多边形的凸包之内)和基数样条曲线(过控制点)。
基数样条曲线(cardinal spline curve)
// DrawCurve与DrawClosedCurve Status DrawCurve(const Pen* pen, const Point* points, INT count);// tension = 0.5f Status DrawCurve(const Pen* pen, const Point* points, INT count, REAL tension);Status DrawCurve(const Pen* pen, const Point* points, INT count, INT offset, INT numberOfSegments, REAL tension = 0.5f);// 只画部分点
Status DrawCurve(const Pen* pen, const PointF* points, INT count);Status DrawCurve(const Pen* pen, const PointF* points, INT count, REAL tension);Status DrawCurve(const Pen* pen, const PointF* points, INT count, INT offset, INT numberOfSegments, REAL tension = 0.5f);Status DrawClosedCurve(const Pen* pen, const Point* points, INT count);Status DrawClosedCurve(const Pen *pen, const Point* points, INT count, REAL tension);Status DrawClosedCurve(const Pen* pen, const PointF* points, INT count);Status DrawClosedCurve(const Pen *pen, const PointF* points, INT count, REAL tension);其中:
参数tension(张力)指定曲线的弯曲程度,tension = 0.0(直线)~ 1.0(最弯曲)无张力版的函数的 tension = 0.5(缺省值)第3/6个DrawCurve,只画从points[offset]开始的numberOfSegments个点组成的部分曲线段 DrawClosedCurve函数(连接首尾点)画封闭的基数样条曲线 贝塞尔曲线(Bezier curve)DrawBezier Status DrawBezier(const Pen* pen, INT x1, INT y1, INT x2, INT y2, INT x3, INT y3, INT x4, INT y4);Status DrawBezier(const Pen* pen, const Point& pt1, const Point& pt2, const Point& pt3, const Point& pt4);Status DrawBeziers(const Pen* pen, const Point* points, INT count);Status DrawBezier(const Pen* pen, REAL x1, REAL y1, REAL x2, REAL y2, REAL x3, REAL y3, REAL x4, REAL y4);Status DrawBezier(const Pen* pen, const PointF& pt1, const PointF& pt2, const PointF& pt3, const PointF& pt4);Status DrawBeziers(const Pen* pen, const PointF* points, INT count);填充封闭基数样条曲线
FillClosedCurve Status FillClosedCurve(const Brush* brush, const Point* points, INT count);Status FillClosedCurve(const Brush* brush, const Point* points, INT count, FillMode fillMode, REAL tension = 0.5f);Status FillClosedCurve(const Brush* brush, const PointF* points, INT count);Status FillClosedCurve(const Brush* brush, const PointF* points, INT count, FillMode fillMode, REAL tension = 0.5f);
http://www.xiexiebang.com/
GDI中没有用于清屏的专门函数,得自己用背景色画窗口大小的填充矩形,或者调用窗口类的Invalidate和UpdateWindow函数。现在,GDI+有了清屏函数Clear: Status Clear(const Color &color);其中的输入参数color,为用户指定的填充背景色。例如:
Graphics graph(GetDC()->m_hDC);
graph.Clear(Color::White);// 使用Graphics类之对象调用
4、Pen 与GDI中的一样,GDI+中的笔(pen钢笔/画笔)也是画线状图的工具,但是功能更加强大。例如:透明笔、图案笔、自定义虚线风格、线帽、笔的缩放和旋转、笔的连接点属性等。GDI+中的笔对应于Pen类,被定义在GdiplusPen.h头文件中。笔的构造函数主要有两个:
Pen(const Color &color, REAL width = 1.0);// 单色笔
Pen(const Brush *brush, REAL width = 1.0);// 纹理图案笔
其中,最常用的是第一个,它构造一个颜色为color,宽度为width(缺省为1)的单色笔。如果颜色的α值<255,则所创建的笔就是带透明度的笔。
5、Brush 与GDI中的一样,GDI+中的刷(brush画刷/画笔)也是画填充图的工具,GDI+中也有与GDI相对应的实心刷(单色刷)、条纹刷(影线刷)和纹理刷(图像刷)。不过,GDI+又新增加了功能强大的线性渐变刷和路径渐变刷,而且还为所有这些刷各自建立了对应的类,基类是Brush(功能少)。
GDI+刷类的层次结构 //(1)SolidBrush实心刷 //(2)HatchBrush 条纹刷 //(3)TextureBrush 纹理刷
//(4)LinearGradientBrush 线性渐变刷
// gradient倾斜的,梯度 //(5)PathGradientBrush 路径渐变刷
所有刷类都被定义在头文件GdiplusBrush.h中。
6、文字
GDI+的文本排版和字体处理的功能比GDI的更加强大。特别是Windows XP提供了对LCD(液晶)显示器的特殊优化功能,GDI+也提供了对应的ClearType(清晰活字)文字处理技术,以增强字体的清晰度。另外,GDI+还提供了构造专用字体集的功能,可以包含私有的临时字体(不需预先安装到系统中)。Windows中使用的字体,一般是TrueType(真实活字)字体(TTF = TrueType Font),它是1991年Apple 和Microsoft 联合开发的一种字体技术,采用二次B样条曲线来描述字符的轮廓。在GDI+中,与文字相关的类有:字体族类FontFamily、字体类Font和字体集类FontCollection及其两个派生类InstalledFontCollection(已安装字体集)和PrivateFontCollection(专用字体集)。(在GDI中只有CFont一个字体类)这些类的层次结构为:
在GDI中,我们用CDC类的成员函数TextOut、DrawText和ExtTextOut等来输出文本串。在GDI+中,我们则是利用Graphics类的重载成员函数DrawString来绘制文本。
http://www.xiexiebang.com/
7、路径
路径(path)是一系列相互连接的直线和曲线,由许多不同类型的点所构成,用于表示复杂的不规则图形,也叫做图形路径(graphics path)。路径可以被画轮廓和填充,也可以用于创建区域和路径渐变刷等。
在GDI中也有路径(我们没有讲),但是它只是作为DC的一种状态才能存在。独立的路径对象,则是GDI+的新特点。
8、区域
区域(region)由若干几何形状所构成的一种封闭图形,主要用于复杂图形的绘制、图形输出的剪裁和鼠标击中的测试。最简单也是最常用的区域是矩形,其次是椭圆和多边形以及它们的组合。这些也正是GDI所支持的区域类型。
GDI+中的区域是一种显示表面的范围(an area of the display surface),可以是任意形状(的图形的组合),边界一般为路径。除了上面所讲的矩形、椭圆、多边形之外,其边界还可以含直线、折线、弧、贝塞尔曲线和样条曲线等开图形,其内容还可以包含饼、闭曲线等闭图形。
在GDI+中,区域所对应的类是Region,它是一个独立的类(没有基类,也没有派生类)。但是它又若干相关的类,如各种图形类和图形路径类等。Region类有6个构造函数:
Region(VOID);// 创建一个空区域
Region(const Rect &rect);// 创建一个整数型矩形区域 Region(const RectF &rect);// 创建一个浮点数型矩形区域 Region(const GraphicsPath *path);// 由图形路径来创建区域
Region(const BYTE *regionData, INT size);// 由(另一)区域的数据构造区域 Region(HRGN hRgn);// 由GDI的区域句柄构造区域
其中,创建矩形区域最简单,由路径创建区域最常用。
9、变换
变换(transform)是GDI+新增加的强大功能,包括图形对象的简单变换和基于矩阵的坐标变换、图形变换、图像变换、色彩变换、路径变换和区域变换等。
GDI+的核心——图形类Graphics,提供了3个成员函数,可以对其所绘制的图形进行平移(translate)、旋转(rotate)和伸缩(scale比例尺/缩放)等基本的图形变换:(与纹理刷类中的对应函数的原型是一样的)
Status TranslateTransform(REAL dx, REAL dy, MatrixOrder order = MatrixOrderPrepend);Status RotateTransform(REAL angle, MatrixOrder order = MatrixOrderPrepend);Status ScaleTransform(REAL sx, REAL sy, MatrixOrder order = MatrixOrderPrepend);其中的最后一个输入参数为矩阵相乘的顺序,取值为矩阵顺序枚举类型MatrixOrder中的符号常量,缺省值都为MatrixOrderAppend(左乘): typedef enum {
MatrixOrderPrepend = 0, // 矩阵左乘(预先序,前置)
MatrixOrderAppend = 1 // 矩阵右乘(追加序,后缀)} MatrixOrder;因为这些变换都可以用矩阵表示,而且与图形对象已经设置的现有变换矩阵要进行合成(相当于两个变换矩阵进行乘法运算)。在图形对象的这三种基本变换中,最常用的是第一种——平移变换。我们在前面曾多次使用,避免了重复定义(有坐标平移的)绘图区域的麻烦。
http://www.xiexiebang.com/
10、图像
GDI+支持如下9种用于Windows的常见图像格式:
——BitMaP(位图),扩展名为.BMP,由Microsoft与IBM于1980年代中期为Windows和PS/2制订的图像格式,一般不压缩。支持黑白、伪彩图、灰度图和真彩图,每像素位数可为1、4、8、16、24、32、64等,常用的是24位位图。
——Graphics Interchange Format(可交换图形格式),扩展名为.GIF,由CompuServe公司1987年制定,采用无损的变长LZW压缩算法。只支持伪彩图(最多256索引色),宽高用双字节无符号整数表示(最多64K*64K像素)。可存储多幅图片,常用于简单的网络动画。压缩比较高,使用广泛。
——Joint Photographic Experts Group(联合图象专家组),扩展名为.JPG,是国际标准化组织ISO和IEC于1991年联合制定的静态图像压缩标准,采用以DCT为主的有损压缩方法。支持灰度图和真彩图,但是不支持伪彩图。压缩比高,使用广泛。
——EXchangeable Image File Format(可交换图像文件格式),扩展名为.Exit?,由JEIDA(Japan Electronic Industry Development Association日本电子工业发展协会/日本电子情报技术产业协会)于1996年10月制定。用于数码相机,内含JPEG图像,另包含拍摄日期、快门速度、曝光时间、照相机制造厂商和型号等相关信息。
——Portable Network Graphic Format(可移植网络图形格式,读成“ping”),扩展名为.png,由W3C(World Wide Web Consortium万维网协会)于1996年10月推出的一种标准图像格式,2003年成为ISO国际标准。PNG采用与GIF一样的无损压缩方法,但是除了伪彩图外,PNG还支持多达16位深度的灰度图像和48位深度的彩色图像,并且还可支持多达16位的α通道数据。
——Tag Image File Format(标签图像文件格式),扩展名为.tif,由Aldus于1986年秋联合多家扫描仪制造商和软件公司共同开发,支持黑白、索引色、灰度、真彩图,可校正颜色和调色温,支持多种压缩编码(如Huffman、LZW、RLE),可存储多幅图片。常用于对质量要求高的专业图像的存储。
——icon(图标),扩展名为.ico,由Microsoft与IBM于1980年代中期为Windows和PS/2制订的图标图像格式。图像大小为16*
16、32*32或54*64。
——Windows MetaFile(视窗元文件),扩展名为.WMF,由Microsoft与IBM于1980年代中期为Windows和PS/2制订的图形文件格式,用于保存GDI的绘图指令记录。
——Enhanced Windows MetaFile(增强型视窗元文件),扩展名为.EMF,是微软公司于1993年随32位操作系统Windws NT推出的一种改进的WMF格式,用于Win32。GDI+使用的是扩展EMF格式——EMF+。
GDI+的图像及其处理的功能十分强大,可以用不同的格式加载、保存和操作图像。但由于篇幅所限,本小节只介绍最基本的内容。GDI+中有三个图像类,其中的Image(图像)为基类,其他两个为它的派生类——Bitmap(位图)和Metafile([图]元文件/矢量图形)。它们的类层次结构如下图所示:
图像类的层次结构
除此之外,还有大量与图像处理有关的GDI+类,如Effect类及其11个派生类以及与图像数据和信息有关的7个独立类。由于时间关系,我们只准备介绍上面这三个主要的图像类及其基本操作。
http://www.xiexiebang.com/
11、图元文件 从一开始GDI就支持(图)元文件(metafile),早期(1985年)的版本为WMF(Windows MetaFile视窗元文件),主要针对Win16(Win3.x),后来(1990年)也支持Win32(Win95/ 98/Me)。以后(1993年)随Windows NT推出了改进的元文件版本——EMF(Enhanced Windows MetaFile增强型视窗元文件),只支持Win32(Win95/98/Me/NT/2000/XP)。现在(2001年)又随GDI+推出了加强型EMF——EMF+,可以同时支持GDI和GDI+。元文件所支持的GDI类型
元文件类型 Win16 GDI Win32 GDI Win32/64 GDI+ WMF √ √ × EMF × √ × EMF+ × √ √
虽然在GDI+中,将图元文件所对应的类Metafile作为Image的派生类,但这只是为了图元文件可以同时处理图形和图像。其实图元文件中所包含的就是一系列绘图(包括绘制图像)指令及参数,属于矢量图形文件。它所占空间小、可以任意缩放(不会产生马赛克效应),但是绘制图形需要一定的时间。
在GDI+中,图元文件对应的类为Metafile,它是Image类的派生类。GDI+的Metafile类支持三种类型的图元文件:仅EMF类型、仅EMF+类型、EMF及EMF+双重类型(缺省值)。它们对应于枚举类型: typedef enum { EmfTypeEmfOnly = MetafileTypeEmf, // 仅EMF类型
EmfTypeEmfPlusOnly = MetafileTypeEmfPlusOnly, // 仅EMF+类型
EmfTypeEmfPlusDual = MetafileTypeEmfPlusDual // EMF及EMF+双重类型 } EmfType;// enhance meta file Metafile类有13个构造函数: // 文件型
Metafile(const WCHAR *filename);Metafile(const WCHAR *fileName, HDC referenceHdc, EmfType type = EmfTypeEmfPlusDual, const WCHAR *description = NULL);Metafile(const WCHAR *fileName, HDC referenceHdc, const Rect &frameRect, MetaFileFrameUnit frameUnit = MetafileFrameUnitGdi, EmfType type = EmfTypeEmfPlusDual, const WCHAR *description = NULL);Metafile(const WCHAR *fileName, HDC referenceHdc, const RectF &frameRect, MetafileFrameUnit frameUnit = MetafileFrameUnitGdi, EmfType type = EmfTypeEmfPlusDual, const WCHAR *description = NULL);// 流型
Metafile(IStream *stream);Metafile(IStream *stream, HDC referenceHdc, EmfType type = EmfTypeEmfPlusDual, const WCHAR *description = NULL);Metafile(IStream *stream, HDC referenceHdc, const Rect &frameRect, MetafileFrameUnit frameUnit = MetafileFrameUnitGdi, EmfType type = EmfTypeEmfPlusDual, const WCHAR *description = NULL);Metafile(IStream *stream, HDC referenceHdc, const RectF &frameRect, MetafileFrameUnit
http://www.xiexiebang.com/
frameUnit = MetafileFrameUnitGdi, EmfType type = EmfTypeEmfPlusDual, const WCHAR *description = NULL);// DC句柄型
Metafile(HDC referenceHdc, EmfType type = EmfTypeEmfPlusDual, const WCHAR *description = NULL);Metafile(HDC referenceHdc, const Rect &frameRect, MetafileFrameUnit frameUnit = MetafileFrameUnitGdi, EmfType type = EmfTypeEmfPlusDual, const WCHAR *description = NULL);Metafile(HDC referenceHdc, const RectF &frameRect, MetaFileFrameUnit frameUnit = MetafileFrameUnitGdi, EmfType type = EmfTypeEmfPlusDual, const WCHAR *description = NULL);// WMF/EMF句柄型
Metafile(HENHMETAFILE hEmf, BOOL deleteEmf = FALSE);Metafile(HMETAFILE hWmf, const WmfPlaceableFileHeader *wmfPlaceableFileHeader, BOOL deleteWmf = FALSE);其中用到的枚举类型有: typedef enum {
MetafileFrameUnitPixel = UnitPixel, // 象素
MetafileFrameUnitPoint = UnitPoint, // 点
MetafileFrameUnitInch = UnitInch, // 英寸
MetafileFrameUnitDocument = UnitDocument, // 文挡
MetafileFrameUnitMillimeter = UnitDocument + 1, // 毫米
MetafileFrameUnitGdi = UnitDocument + 2 // GDI+单位数目 } MetafileFrameUnit;typedef struct {
UINT32 Key;// 键
INT16 Hmf;//
PWMFRect16 BoundingBox;// 边界盒
INT16 Inch;// 英寸
UINT32 Reserved;// 保留
INT16 Checksum;// 检测和 } WmfPlaceableFileHeader;http://www.xiexiebang.com/
Metafile(HDC referenceHdc, EmfType type = EmfTypeEmfPlusDual, const WCHAR *description = NULL);它用于构造内存元文件。这些内存元文件构造函数还有对应的流构造函数版本。Metafile类的其他成员函数有:
// 显示元文件记录,需要与Graphics类的EnumerateMetafile Status PlayRecord(EmfPlusRecordType recordType, UINT flags, UINT dataSize, const BYTE *data);// 函数及用户自定义的回调函数配套使用(似GDI的)
static UINT EmfToWmfBits(HENHMETAFILE hemf, UINT cbData16, LPBYTE pData16, INT iMapMode, EmfToWmfBitsFlags eFlags);// 用于EMF到WMF的转换 HENHMETAFILEGetHENHMETAFILE(VOID);// 可用于EMF的SDK函数 // 获取和设置底层光栅限制,用于减少刷空间大小
// 陈宝楷??? UINT GetDownLevelRasterizationLimit(VOID);Status SetDownLevelRasterizationLimit(UINT metafileRasterizationLimitDpi);// 获取元文件头
Status GetMetafileHeader(MetafileHeader *header)const;static Status GetMetafileHeader(const WCHAR *filename, MetafileHeader *header);static Status GetMetafileHeader(IStream *stream, MetafileHeader *header);static Status GetMetafileHeader(HENHMETAFILE *hEmf, MetafileHeader *header);static Status GetMetafileHeader(HMETAFILE hWmf, const WmfPlaceableFileHeader *wmfPlaceableFileHeader, MetafileHeader *header);为了将绘图记录保存到图元文件中,需要先创建元文件对象,然后用该图元文件对象再来创建图形对象,最后调用图形类的各种绘图函数来向图元文件中添加绘图记录。具体方法如下:
可以先使用Metafile类的用于创建新图元文件的构造函数(带DC参数的),如 Metafile(const WCHAR *fileName, HDCreferenceHdc, EmfType type = EmfTypeEmfPlusDual, const WCHAR *description = NULL);来创建元文件对象。
然后使用Graphics类的构造函数(注意,Metafile是Image的派生类)Graphics(Image* image);来创建图形对象。
最后调用各种图形类的图形设置、操作和绘制函数成员函数来向图元文件添加绘图记录。例如:
Metafile *myMetafile = newMetafile(L“MyDiskFile.emf”, GetDC()->m_hDC);
Graphics *myGraphics = new Graphics(myMetafile);
// SmoothingMode::tiAlias不能在VC中使用,可在C#中使用。myGraphics->SetSmoothingMode(SmoothingModeAntiAlias);
myGraphics->RotateTransform(30);
// Create an elliptical clipping region.GraphicsPath myPath;
myPath.AddEllipse(0, 0, 200, 100);
Region myRegion(&myPath);
myGraphics->SetClip(&myRegion);
Pen myPen(Color(255, 0, 0, 255));
http://www.xiexiebang.com/
myGraphics->DrawPath(&myPen, &myPath);
for(int j=0;j<=300;j+=10)myGraphics->DrawLine(&myPen,0,0,300-j,j);
delete myGraphics;deletemyMetafile;可以先使用Metafile类的用于打开已有图元文件的构造函数(不带DC参数的),如 Metafile(const WCHAR *filename);来创建元文件对象。
然后再调用Graphics类的各种DrawImage成员函数,如: Status DrawImage(Image *image, INT x, INT y);来重画图元文件中的所有绘图记录。
另外,为了获取当前图元文件的边界矩形,可以先调用Metafile类的成员函数: Status GetMetafileHeader(MetafileHeader *header)const;来获取MetafileHeader对象,然后再用MetafileHeader类的成员函数: void GetBounds(Rect *rect);得到边界矩形。可用于Graphics类的DrawImage成员函数: DrawImage(Image *image, const Rect &rect);
注意,如果用带DC参数的构造函数来创建Metafile对象,则会清空原图元文件(以便重新开始添加记录),不能用于图元文件的播放。可以利用Metafile类的成员函数
Status PlayRecord(EmfPlusRecordType recordType, UINT flags, UINT dataSize, const BYTE *data);来重画图元文件中指定记录。与EMF中讨论的类似,该函数需要与Graphics类的枚举元文件成员函数(共有12个同名的重载函数),如: StatusEnumerateMetafile(const Metafile *metafile, const PointF &destPoint, EnumerateMetafileProccallback, VOID *callbackData = NULL, ImageAttributes *imageAttributes = NULL);配套使用,该函数遍历图元文件的每个记录,并调用用户自定义的回调函数(该函数可以自己命名)
BOOL CALLBACK metaCallback(EmfPlusRecordType recordType, unsigned int flags, unsigned int dataSize, const unsigned char* pStr, void* callbackData);对记录进行各种处理,包括使用元文件的成员函数PlayRecord来绘制(播放)记录。在GDI+中,想实现交互绘图时的窗口动态重画,非常困难。虽然Metafile类有一个成员函数
HENHMETAFILE GetHENHMETAFILE(VOID);可以用于获取图元文件的句柄,但经过我的实验发现,它只对使用不带DC输入参数的构造函数所创建的不能用于添加绘图记录的Metafile对象有效。
另外,虽说可以创建内存Metafile对象,但是GDI+却没有提供任何办法(没有复制、保存、克隆等函数,父类Image的对应函数对写入型Metafile对象都是无效的),可将其保存到图元文件中。因为无法获得用于添加记录的图元文件的句柄,所以各种SDK函数也派不上用场。
因为除了帮助文档,几乎无资料可看,唯一的途径就是编码做试验。下面是我经过很长时间,http://www.xiexiebang.com/
好不容易才摸索出来的,一种可行的解决办法(但是很臭。你们可以寻找其他办法,如果有了更好的方法,请与大家共享):
(说明:为了防止重画图元文件时,图形的位置有偏移或其大小发生变化,可以采用如下的构造函数:
Metafile(const WCHAR *fileName, HDC referenceHdc, const Rect &frameRect, MetaFileFrameUnit frameUnit = MetafileFrameUnitGdi, EmfType type = EmfTypeEmfPlusDual, const WCHAR *description = NULL);来创建Metafile对象。其中的边框矩形,可以设置为屏幕大小,并使用像素单位。该边框同时还用于进行图元文件重画的Graphics类的DrawImage函数。)
在视图类中定义如下几个类变量:Metafile对象及其对应的Graphics对象的指针、边框矩形、两个图元文件名的宽字符串数组(以便绕开GDI+的文件锁定功能)、以及在这两个文件名中切换的整数。如:
Metafile *mf;
Graphics *mfGraph;
Rect rect0;wchar_t *fns[2];
// wchar_t
int fni;
在视图类的构造函数中,初始化部分类变量:
mf = NULL;
mfGraph = NULL;
fns[0] = L“draw.emf”;
fns[1] = L“draw0.emf”;
fni = 0;
在视图类的初始化函数OnInitialUpdate中,计算边框矩形、创建Metafile对象:
HDC hdcRef = GetDC()->m_hDC;
rect0.X = 0;
rect0.Y = 0;
rect0.Width = GetDeviceCaps(hdcRef, HORZRES);
rect0.Height = GetDeviceCaps(hdcRef, VERTRES);
mf = new Metafile(fns[fni], hdcRef, rect0, MetafileFrameUnitPixel);
mfGraph = new Graphics(mf);
在视图类的OnLButtonUp等函数中,利用图元文件所对应的图形对象,向图元文件添加各种绘图记录。如:
mfGraph->DrawLine(&Pen(Color::Green), p0.x, p0.y, point.x , point.y);
……
在视图类的OnDraw函数中,删除当前元文件对象(系统才会将元文件的内容写入磁盘)和对应的图形对象,打开该磁盘元文件并播放。然后,切换文件名,创建新的元文件对象和对
http://www.xiexiebang.com/
应的图形对象,并将老元文件中现有的记录,通过新元文件所对应的图形对象的图像绘制,加入到新元文件中,最后删除老元文件的句柄。如:
delete mfGraph;
delete mf;
Metafile *mf0 = new Metafile(fns[fni]);
Graphics graph(pDC->m_hDC);
graph.DrawImage(mf0, rect0);fni =!fni;// 相当于if(fni)fni = 0;else fni = 1;
mf = new Metafile(fns[fni], pDC->m_hDC, rect0, MetafileFrameUnitPixel);
mfGraph = new Graphics(mf);
mfGraph->DrawImage(mf0, rect0);
delete mf0;
最后,在视图类的析构函数中,删除当前元文件对象(系统会将元文件的内容写入磁盘)和对应的图形对象。例如:
delete mfGraph;
delete mf;
第二篇:编程小结
编程小结
(一)一.累加:加数1+加数2+加数3+„„+加数n(n个加数相加)假设我们用i表示我们的加数数目,例如:当i=9时,就表示加数9 模版:int i,sum=0;(注意:如果是分数或者小数sum就是float类型)
for(i=1;i<=n;i++)(注意:循环变量的初值和递变规律,也有
可能是i--,或者i+=2等等){通项a;(通项:用一个通用的式子表示所有的加数)sum+=a;} printf(“%d”,sum);(注意:如果是float类型就是%f)
1、求1+2+3„„+100的和,则通项a就是i。
分析:因为a就是i的值,所以这里不需要通项这一行了,因此整个大括号中间就只有一句话,所以大括号可以省略。整理之后就是: int i,sum=0;for(i=1;i<=100;i++)sum+=i;printf(“%d”,sum);
2、求2+4+6„„+100的和。
分析:因为a就是i的值,所以这里不需要通项这一行了,因此整个大括号中间就只有一句话,所以大括号可以省略,再分析,再分析我们发现每个加数都是偶数,那么i的变化就是i+=2,并且i是从2开始变化,那么在赋值的时候就应该是i=2。整理之后就是: int i,sum=0;for(i=2;i<=100;i+=2)sum+=i;printf(“%d”,sum);
3、求1+3+5„„+99的和。
分析:因为a就是i的值,所以这里不需要通项这一行了,因此整个大括号中间就只有一句话,所以大括号可以省略,再分析,再分析我们发现每个加数都是奇数,那么i的变化就是i+=2。整理之后就是: int i,sum=0;for(i=1;i<=100;i+=2)sum+=i;printf(“%d”,sum);
4、求1+5+9+13+17+„„的前100项的和,则通项为j+4,则程序为: int i,sum=0,j=1;for(i=1;i<=100;i++){ sum+=j;j=j+4; } printf(“%d”,sum);因为加数的第一项是1,所以赋初值的时候j=1,然后加数进行变化,变成5加到sum里面,所以这里要将通项和求和这两句话互换位置。
5、求1+4+9+16+„„的前100项的和
分析可知:每个加数就是对应的加数数目的平方,则通项为i*i,则程序为: int i,sum=0;for(i=1;i<=100;i++)sum+= i*i;printf(“%d”,sum);
6、求1+(1+2)+(1+2+3)+(1+2+3+4)+„„的前100项的和。
分析可知每一个加数本身又是一个累加的式子,进一步观察可以发现,每个累加的式子都是加到这个加数所在的加数数目,即第35个加数就是1+2+3„„+35,并且是在前面一个加数的基础上加上这个加数所在的加数数目,也就是说第36个加数就是在前一个加数的基础上加上36,即:1+2+3„„+35+36。假设第k个加数是j,那么第k+1个加数就可以表示为j+(k+1),然后第k+2个加数就是j+(k+1)+(k+2)„„那么我们的通项就可以表示为a=a+i,则程序为: int i,sum=0, a=0;for(i=1;i<=100;i++){ a+=i;sum+=a;} printf(“%d”,sum);
7、求1+1+2+3+5+8+13+21+„„的前100项的和。
分析可知从第三个加数开始,每一个加数是其前两个加数之和,假设第k个加数是m,第k+1个加数是n,然后第k+2个加数就是m+n,那么我们的通项就可以表示为a=m+n,但是要注意每次加数所对应的m和n不一样,所以我们要在求出每个加数之后,找出其对应的m和n;再分析我们可以发现当前的n是下一次的m,当前的加数a是下一次的n,假设接着上面的推导,那么第k+3个加数就是n+(m+n),对应我们的通项a=m+n,理解前面一句话。则程序为: int i,sum=0, m=1,n=1,a;for(i=3;i<=100;i++){ a=m+n;sum+=a;m=n;n=a;} printf(“%d”,sum);
8、求1+1/2+1/3+„„+1/100 分析可知每一个加数就是我们的加数数目的倒数,则通项a就是1/i,我们说循环变量i一般定义为整型,那么1/i的结果就是整型,这样的话小数点后面的就会被省略,所以正确的应该写为a=1.0/i,则程序为:
int i;float sum=0;for(i=1;i<=100;i++){a=1.0/i;sum+=a;} printf(“%f”,sum);
9、求1+1/2+2/3+3/5+5/8+„„的前100项的和。
分析可从第三个加数开始观察,每一个加数的分母是其前一个加数的分子和分母之和,每一个加数的分子是其前一个加数的分母。可以将第一个加数看成1/1,那么第二个加数也符合我们的规律,只有第一个不符合,那么我们可以先将第一个加数加到sum,然后再变下一个加数,但是要注意每次加数所对应的分子和分母不一样,所以我们要在求出每个加数之后,找出下一个加数所对应的分子和分母。设通项表示为a=m/n, 那么下一个加数是n/(m+n),然后下下一个加数就是(m+n)/(m+n+n);再分析我们可以发现当前的分子和分母之和(m+n)是下一次的分母n,当前的分母n是下一次的分子m,注意这里在做数据交换的时候需要中间变量,对应我们的通项a=m/n,理解前面一句话。则程序为: int i;float sum=0, m=1,n=1,t;for(i=1;i<=100;i++){ sum+=m/n;t=m+n;m=n;n=t;} printf(“%f”,sum);
二.累乘:乘数1*乘数2*乘数3*„„*乘数n(n个乘数相乘)假设我们用i表示我们的乘数数目,例如:当i=9时,就表示乘数9 模版:int i,sum=1;(注意:如果是分数或者小数sum就是float类型)
for(i=1;i<=n;i++)(注意:循环变量的初值和递变规律,也有
可能是i--,或者i+=2等等){通项a;(通项:用一个通用的式子表示所有的乘数)sum*=a;} printf(“%d”,sum);(注意:如果是float类型就是%f)
1、求1*2*3„„*100的积,则通项a就是i。
分析:因为a就是i的值,所以这里不需要通项这一行了,因此整个大括号中间就只有一句话,所以大括号可以省略。整理之后就是: int i,sum=1;for(i=1;i<=100;i**)sum*=i;printf(“%d”,sum);
2、求2*4*6„„*100的和。分析:因为a就是i的值,所以这里不需要通项这一行了,因此整个大括号中间就只有一句话,所以大括号可以省略,再分析,再分析我们发现每个乘数都是偶数,那么i的变化就是i+=2,并且i是从2开始变化,那么在赋值的时候就应该是i=2。整理之后就是: int i,sum=1;for(i=2;i<=100;i+=2)sum*=i;printf(“%d”,sum);
3、求1*3*5„„*99的和。
分析:因为a就是i的值,所以这里不需要通项这一行了,因此整个大括号中间就只有一句话,所以大括号可以省略,再分析,再分析我们发现每个乘数都是奇数,那么i的变化就是i+=2。整理之后就是: int i,sum=1;for(i=1;i<=100;i+=2)sum*=i;printf(“%d”,sum);
4、求1*5*9*13*17*„„的前100项的积,则通项为j*4,则程序为: 分析:因为乘数的第一项是1,所以赋初值的时候j=1,然后乘数进行变化,变成5乘到sum里面,所以这里要将通项和求积这两句话互换位置。
int i,sum=1,j=1;for(i=1;i<=100;i**){ sum*=j;j=j*4; } printf(“%d”,sum);
5、求1*4*9*16*„„的前100项的积
分析可知:每个乘数就是对应的乘数数目的平方,则通项为i*i,则程序为: int i,sum=1;for(i=1;i<=100;i**)sum*= i*i;printf(“%d”,sum);
6、求1*(1*2)*(1*2*3)*(1*2*3*4)*„„的前100项的积。分析可知每一个乘数本身又是一个累乘的式子,进一步观察可以发现,每个累乘的式子都是乘到这个乘数所在的乘数数目,即第35个乘数就是1*2*3„„*35,并且是在前面一个乘数的基础上乘上这个乘数所在的乘数数目,也就是说第36个乘数就是在前一个乘数的基础上乘上36,即:1*2*3„„*35*36。假设第k个乘数是j,那么第k+1个乘数就可以表示为j*(k+1),然后第k+2个乘数就是j*(k+1)*(k+2)„„那么我们的通项就可以表示为a=a*i,则程序为: int i,sum=1, a=0;for(i=1;i<=100;i**){ a*=i;sum*=a;} printf(“%d”,sum);
7、求1*1*2*3*5*8*13*21*„„的前100项的积。
分析可知从第三个乘数开始,每一个乘数是其前两个乘数之和,假设第k个乘数是m,第k+1个乘数是n,然后第k+2个乘数就是m+n,那么我们的通项就可以表示为a=m+n,但是要注意每次乘数所对应的m和n不一样,所以我们要在求出每个乘数之后,找出其对应的m和n;再分析我们可以发现当前的n是下一次的m,当前的乘数a是下一次的n,假设接着上面的推导,那么第k+3个乘数就是n*(m+n),对应我们的通项a=m*n,理解前面一句话。则程序为: int i,sum=1, m=1,n=1,a;for(i=3;i<=100;i**){ a=m+n;sum*=a;m=n;n=a;} printf(“%d”,sum);
8、求1*1/2*1/3*„„*1/100 分析可知每一个乘数就是我们的乘数数目的倒数,则通项a就是1/i,我们说循环变量i一般定义为整型,那么1/i的结果就是整型,这样的话小数点后面的就会被省略,所以正确的应该写为a=1.0/i,则程序为:
int i;float sum=1;for(i=1;i<=100;i**){a=1.0/i;sum*=a;} printf(“%f”,sum);
9、求1*1/2*2/3*3/5*5/8*„„的前100项的积。
分析可从第三个乘数开始观察,每一个乘数的分母是其前一个乘数的分子和分母之和,每一个乘数的分子是其前一个乘数的分母。可以将第一个乘数看成1/1,那么第二个乘数也符合我们的规律,只有第一个不符合,那么我们可以先将第一个乘数乘到sum,然后再变下一个乘数,但是要注意每次乘数所对应的分子和分母不一样,所以我们要在求出每个乘数之后,找出下一个乘数所对应的分子和分母。设通项表示为a=m/n, 那么下一个乘数是n/(m+n),然后下下一个乘数就是(m+n)/(m+n+n);再分析我们可以发现当前的分子和分母之和(m+n)是下一次的分母n,当前的分母n是下一次的分子m,注意这里在做数据交换的时候需要中间变量,对应我们的通项a=m/n,理解前面一句话。则程序为: int i;float sum=1, m=1,n=1,t;for(i=1;i<=100;i**){ sum*=m/n;t=m+n;m=n;n=t;} printf(“%f”,sum);
10、求1+(1*2)+(1*2*3)+(1*2*3*4)+„„的前100项的和。
分析可知每一个加数本身是一个累乘的式子,进一步观察可以发现,每个累乘的式子都是乘到这个乘数所在的乘数数目,即第35个乘数就是1*2*3„„*35,并且是在前面一个乘数的基础上乘上这个乘数所在的乘数数目,也就是说第36个乘数就是在前一个乘数的基础上乘上36,即:1*2*3„„*35*36。假设第k个乘数是j,那么第k+1个乘数就可以表示为j*(k+1),然后第k+2个乘数就是j*(k+1)*(k+2)„„那么我们的通项就可以表示为a=a*i,再利用累加的模版,则程序为:
int i,sum=0, a=1;for(i=1;i<=100;i**){ a*=i;sum+=a;} printf(“%d”,sum);
11、求1*(1+2)*(1+2+3)*(1+2+3+4)*„„的前100项的积。
分析可知每一个乘数本身又是一个累加的式子,进一步观察可以发现,每个累加的式子都是加到这个乘数所在的乘数数目,即第35个乘数就是1+2+3„„+35,并且是在前面一个乘数的基础上加上这个乘数所在的乘数数目,也就是说第36个乘数就是在前一个乘数的基础上加上36,即:1+2+3„„+35+36。假设第k个乘数是j,那么第k+1个乘数就可以表示为j+(k+1),然后第k+2个乘数就是j+(k+1)+(k+2)„„那么我们的通项就可以表示为a=a+i, 再利用累乘的模版,则程序为:
int i,sum=1, a=0;for(i=1;i<=100;i**){ a+=i;sum*=a;} printf(“%d”,sum);
三.最大值和最小值:数字0,数字1,数字2,„„数字n-1(一共n个数字)假设我们用i表示我们的数字所在的位置,并且第一个位置是0,例如:当i=9时,就表示这个数字在第10个位子
模版: int i,max,a[n];(注意:如果是分数或者小数max和a[n]就是float
类型,注意这里定义的时候根据题目所给的具体数字把n换掉,千万不可以写a[n]o哦~~~~)
for(i=0;i 了数字,就在定义的时候直接赋值,这个循环就不需要了;如果要求产生给数组赋a到b之间的随机数,那么就用a[i]= a + rand()%(b-a);这句话代替这句。注意如果是float类型就是%f)max=a[0];for(i=0;i 1、求20个数字的最大值和最小值,要求赋1到100之间的随机数,并且输出它们及其下标。 分析:因为这里还要输出其下标,所以还有定义一个row来存放,并且要对其赋值为0,因为我们给max赋值为a[0],则程序为: int i,max,min,a[20],row1=0,row2=0;for(i=0;i<20;i++)a[i]= 1+rand()%99;max=a[0];min=a[0];for(i=0;i<20;i++){ if(maxa[i])(这里是找出最小值){ min=a[i];row2=i;} } printf(“max =%d, row=%dn min =%d, row=%dn”, max,row1,min,row2); 2、求4*5矩阵的最大值和最小值,要求赋值随机数,并且输出它们及其下标。分析:虽然这是一个二维的数组,但是其思路仍然和一维数组的一样,区别只是这里需要用嵌套循环。要求还要输出其下标,二维数组的下标是两个,所以还要定义一个row和一个col来存放,并且要对它们赋值为0,因为我们给max赋值为a[0] [0],则程序为: int i,j,max,min,a[4] [5],row1=0,row2=0,col1=0,col2=0;for(i=0;i<4;i++)for(j=0;j<5;j++)a[i] [j]=rand();max=a[0] [0];min=a[0] [0];for(i=0;i<4;i++)for(j=0;j<5;j++){ if(maxa[i] [j])(这里是找出最小值){ min=a[i] [j];row2=i;col2=j;} } printf(“max =%d, row=%d, col=%d n min =%d, row=%d, col=%d n”, max,row1, col1, min,row2, col2); 3、求4*5矩阵的每一行最大值和最小值,要求赋值随机数,并且输出它们及其下标。 分析:虽然这是一个二维的数组,但是要求的是每一行的最大最小值,我们知道二维数组的每一行本身就是一个数组,那么我们就还需要一个控制行数的循环。要求还要输出其下标,二维数组的下标是两个,每一行的最大最小值其行号不就是i,所以还要定义一个存放列号的col,并且要对它赋值为0,因为我们给max赋值为每一行的第一个元素,也就是a[i] [0],则程序为: int i,j,max,min,a[4] [5],col1=0,col2=0;for(i=0;i<4;i++)for(j=0;j<5;j++)a[i] [j]=rand();for(i=0;i<4;i++)(这个循环是控制行的,里面的循环体本身就是一个求 一维数组的最大最小值的程序) {max=a[i] [0];min=a[i] [0];for(j=0;j<5;j++){ if(maxa[i] [j])(这里是找出最小值){ min=a[i] [j];col2=j;} } printf(“max =%d, row=%d, col=%d n min =%d, row=%d, col=%d n”,max,i, col1, min,i, col2);} 4、求4*5矩阵的每一列最大值和最小值,要求赋值随机数,并且输出它们及其下标。 分析:虽然这是一个二维的数组,但是要求的是每一列的最大最小值,二维数组的每一列可以看成一个数组,那么我们就还需要一个控制列数的循环。要求还要输出其下标,二维数组的下标是两个,每一列的最大最小值其列号不就是j,所以还要定义一个存放行号的row,并且要对它赋值为0,因为我们给max赋值为每一列的第一个元素,也就是a[0] [j],则程序为: int i,j,max,min,a[4] [5],row1=0,row2=0;for(i=0;i<4;i++)for(j=0;j<5;j++)a[i] [j]=rand();for(j=0;j<5;j++)(这个循环是控制列的,里面的循环体本身就是一个求 一维数组的最大最小值的程序){max=a[0] [j];min=a[0] [j];for(i=0;i<4;i++){ if(maxa[i] [j])(这里是找出最小值){ min=a[i] [j];row2=i;} } printf(“max =%d, row=%d, col=%d n min =%d, row=%d, col=%d n”,max, row1,j, min, row2,j);} 5、排序(冒泡法)比如说 对于5个数字排序,首先要把5个数字放到一个一维的数组里面去 所以编程的前几句为:int a[5] for(i=0;i<5;i++)scanf(“%d”,&a*i+); 那接下来就是排序了,为了方便理解就将数组实际化:比如 a[5]里面放着{7,9,0,12,3}那画图出来就是 a[5] a[0] a[1] a[2] a[3] a[4] 那我们排序的方法是这样的采用这样几步: 1,用a[0]与后面的(a[1]~a[4]里面的每一个成员比较即是说:a[0]~a[1]比较 a[0]~a[2]比较 a[0]~a[3]比较 a[0]~a[4]比较)当后面的成员只要发现比a[0]小的就与他的位置交换 这部做完之后数组就应 该是这个样子: a[0] a[1] a[2] a[3] a[4] 2,用a[1]与后面的(a[2]~a[4]里面的每一个成员比较即是说: a[1]~a[2]比较 a[1]~a[3]比较 a[1]~a[4]比较)当后面的成员只要发现比a[1]小的就与他的位置交换 这部做完之后数 组该是这个样子:这个时候的a1不是我们赋初值时候的a1老就是我们改变后的数组所以这个时候的a1=9哦。 a[0] a[1] a[2] a[3] a[4] 3,用a[2]与后面的(a[3]~a[4]里面的每一个成员比较即是说: a[2]~a[3]比较 a[2]~a[4]比较)当后面的成员只要发现比a[2]小的就与他的位置交换 这部做完之后数组就应 该是这个样子: a[0] a[1] a[2] a[3] a[4] 4,用a[3]与后面的(a[4]~a[4]里面的每一个成员比较即是说: a[3]~a[4]比较)当后面的成员只要发现比a[2]小的就与他的位置交换 这部做完之后数组就应 该是这个样子: a[0] a[1] a[2] a[3] a[4] 循环就是 写成这个样子的哦: for(i=0;i<4;i++) for(j=i+1;j<5;j++)if(a[i] {c=a[i];a[i]=a[j];a[j]=c;}(这个复合语句表示交换a[i]与a[j]进行交换)你把这个 循环好好的分析一下,当i=0 j可以取(1 2 3 4)那if是不是就是a0跟a1—a4之间的所有进行比较并且交换。其他的以此类推。 最后是不是要对排好序的数组进行输出: for(i=0;i<5;i++)printf(“%d”,a*i+); 6、排序(选择法)比如说 对于5个数字排序,首先要把5个数字放到一个一维的数组里面去 所以编程的前几句为:int a[5] for(i=0;i<5;i++)scanf(“%d”,&a*i+); 那接下来就是排序了,为了方便理解就将数组实际化:比如 a[5]里面放着{7,9,0,12,3}那画图出来就是 a[5] a[0] a[1] a[2] a[3] a[4] 那我们排序的方法是这样的采用这样几步: 1,先把a[0]的下标储存起来,即赋值给k,然后用a[0]与后面的比较 (a[1]~a[4]里面的每一个成员比较即是说:a[0]~a[1]比较 a[0]~a[2]比较 a[0]~a[3]比较 a[0]~a[4]比较)当后面的成员只要发现比a[0]小的就把他的下标赋值给k,最后将a[0]和a[k]的位置交换,这步做完之后数组就应该是这个样子: a[0] a[1] a[2] a[3] a[4] 2,先把a[1]的下标储存起来,即赋值给k,然后用a[1]与后面的比较 (a[2]~a[4]里面的每一个成员比较即是说: a[1]~a[2]比较 a[1]~a[3]比较 a[1]~a[4]比较)当后面的成员只要发现比a[1]小的就把他的下标赋值给k,最后将a[1]和a[k]的位置交换 这步做完之后数组就应该是这个样子: a[0] a[1] a[2] a[3] a[4] 3,先把a[2]的下标储存起来,即赋值给k,然后用a[2]与后面的比较 (a[3]~a[4]里面的每一个成员比较即是说:a[2]~a[3]比较 a[2]~a[4]比较)当后面的成员只要发现比a[2]小的就把他的下标赋值给k,最后将a[2]和a[k]的位置交换 这步做完之后数组就应该是这个样子: a[0] a[1] a[2] a[3] a[4] 4,先把a[3]的下标储存起来,即赋值给k,然后用a[3]与后面的比较(a[4]里面的每一个成员比较即是说: a[3]~a[4]比较)当后面的成员只要发现比a[3]小的就把他的下标赋值给k,最后将a[3]和a[k]的位置交换 这步做完之后数组就应该是这个样子: a[0] a[1] a[2] a[3] a[4] 循环就是 写成这个样子的哦: for(i=0;i<4;i++) {k=i;for(j=i+1;j<5;j++) if(a[i] k=j;if(k!=i) {c=a[i];a[i]=a[j];a[j]=c;} }(这个复合语句表示交换a[i]与a[j]进行交换)把这个循环好好的分析一下,当i=0, j可以取(1 2 3 4)那if是不是就是a0跟a1—a4之间的所有进行比较并且交换。其他的以此类推。 最后是不是要对排好序的数组进行输出: for(i=0;i<5;i++)printf(“%d”,a*i+); 四.寻找特殊的数字或解应用题:输出a到b之间的所有的具有某个特点的数字 模版: int n,a,b;(注意:如果是分数或者小数a和b就是float类型) scanf(“%d,%d”,&a,&b);(从键盘输入查找的范围;如果题目已经给 了范围,就在循环的时候直接带值,这句话就不需要了。注意如果是float类型就是%f。注意如果运行程序,在输入数据验证的时候注意格式要匹配)for(n=a;n<=b;n++)(如果题目已经给了具体的范围,那么这里就根 据题目把a和b换掉){if(条件)(注意:这句话是这类题目的核心,有时候也许不是一 句话,这句话放在这的意思是判定是否是特殊数字)printf(“%d”, n);(注意:如果是float类型就是%f)} 1、输出3到1000之间的所有素数 分析:在做本题之前,先要搞明白什么是素数,它又是如何判定的。补充: 素数 又叫质数,如果一个数只能被1和它本身整除,那么我们就说它是素数。分析:既然一个素数只可以被1和它本身整除,那么当我们判断一个数n是不是素数的时候,就用这个数去除2到(n-1),一旦我们发现可以整除这个区间的某一个数,那么我们就不再去除别的数了,因为在2到(n-1)这个范围内,n可以整除其中的某一个数,那么就肯定不是素数。这个过程需要一个循环和停止循环的break来实现。继续分析,当我们在2到(n-1)这个范围内找不到n可以整除的数,那么就说明这个数是素数,那么我们就判断上面的循环时候做完了,如果中间就跳出循环,则说明不是素数,反之,如果做完了,那么就是素数。P判断能否整除,就是求余看是否为0,则程序如下: int n;(n是要判断的数,具体根据题意赋值或从键盘输入)for(i=2;i 上面的循环有没有做完)本题分析:只要用上面的程序替换掉模版的那个if就可以了,注意这里不再需要else了,因为题目只要求输出素数,输出语句也只需要一句,则程序如下: int n,i;for(n=3;n<=1000;n++){ for(i=2;i 2、输出1到100之间的所有同构数 分析:在做本题之前,先要搞明白什么是同构数,它又是如何判定的。补充: 同构数 如果一个数出现在自己的平方数的右边,那么我们就说它是同构数。分析:既然一个同构数会出现在它自己的平方数的右边,那么当我们判断一个数n是不是同构数的时候,先要做的就是求出这个数的平方,然后该怎么判断是不是出现在右边呢?我们人有眼睛,可以直接看,但是电脑不长眼睛的,它看不到,它只能分析,那么它怎么分析呢?1到100之间的所有数只有一位或者两位,那么我们在取平方数右边的时候,只要取这个平方数的最右边的一位或者两位,与我们的数进行比较,看是否一样,如果一样就是同构数,反之就不是。怎么取一个数的最右边一位或者两位呢?求余!!一个数对10求余就是取它的最右边一位,也就是个位;如果对100求余就是取它的最右边两位,也就是十位和个位。则程序如下: int n;(n是要判断的数,具体根据题意赋值或从键盘输入)if(n*n%10==n|| n*n %100==n)printf(“%d is a isomorphic number!n”,n);本题分析:直接带模版,则程序如下: int n;for(n=1;n<=100;n++){ if(n*n%10==n|| n*n %100==n)printf(“%d is a isomorphic number!n”,n);}(这里的大括号实际是可以去掉的,不去掉也没有关系) 3、输出1到1000之间的所有回文数 分析:在做本题之前,先要搞明白什么是回文数,它又是如何判定的。补充: 回文数 如果一个数字正读和倒读一样,那么这个数字就是回文数。例如:98789, 这个数字正读是98789,倒读也是98789,所以这个数字就是回文数。 分析:既然一个回文数正读和倒读一样,也就是它的最高位和最低位一样,它的次高位和次低位一样,那么当我们判断一个数n是不是回文数的时候,先要确定这个数有几位,才可以确定谁与谁进行比较,然后确定这个数每一位都是谁。1到1000之间的数,除了1000其余最多三位数,显然1000不是回文数,先不考虑,怎么确定这个数是几位呢?如果它的百位是0,那么肯定不是三位数,如果百位和十位都是0,那么肯定是一位数,我们知道一位数肯定都是回文数;对于一个两位数,只要判断它的个位和十位是不是一样就可以了,如果一样,那么肯定是回文数;对于一个三位数只要判断他的个位和百位就可以了,如果一样就是回文数。求一个最多是三位数的每一位,就是将这个数对10求余得到个位;然后这个数除以10,再对10求余得到十位;最后除以100得到百位。则程序如下: int n;(n是要判断的数,具体根据题意赋值或从键盘输入)if(n>0&&n<10)printf(“%d is a huiwen number!n”,n);else if(n/100==0){if(n/10==n%10)printf(“%d is a huiwen number!n”,n);} else if(n/100==n%10)printf(“%d is a huiwen number!n”,n);本题分析:只要用上面的程序替换掉模版的那个if就可以了,则程序如下: int n;for(n=1;n<=1000;n++){ if(n>0&&n<10)printf(“%d is a huiwen number!n”,n);else if(n/100==0){if(n/10==n%10)printf(“%d is a huiwen number!n”,n);} else if(n/100==n%10)printf(“%d is a huiwen number!n”,n);} 4、输出1到1000之间的所有完数 分析:在做本题之前,先要搞明白什么是完数,它又是如何判定的。补充: 再做完数之前先讲怎么求两个数的最大公约数和最小公倍数。 分析:假设求a和b两个数的最大公约数和最小公倍数,并且a>b,如果a0&&n<10)printf(“%d is a wanshu!n”,n);else if(n/100==0){if(n/10==n%10)printf(“%d is a wanshu!n”,n);} else if(n/100==n%10)printf(“%d is a wanshu!n”,n);本题分析:只要用上面的程序替换掉模版的那个if就可以了,则程序如下: int n;for(n=1;n<=1000;n++){ if(n>0&&n<10)printf(“%d is a wanshu!n”,n);else if(n/100==0){if(n/10==n%10)printf(“%d is a wanshu!n”,n);} else if(n/100==n%10)printf(“%d is a wanshu!n”,n);} 5、输出1到999之间的所有水仙花数 分析:在做本题之前,先要搞明白什么是水仙花数,它又是如何判定的。补充: 水仙花数 如果一个三位数的各个位数字的立方和等于该数字本身,那么这个数就是水仙花数。例如:153,1*1*1+5*5*5+3*3*3=153,所以这个数字就是回文数。分析:既然一个水仙花数的各个位数字的立方和等于该数字本身,那么当我们判断一个数n是不是水仙花数的时候,先要求出各个位数字,然后求其立方和,判断是不是和该数本身一样,如果一样就是水仙花数,否则就不是。求一个三位数的每一位,就是将这个数对10求余得到个位;然后这个数除以10,再对10求余得到十位;最后除以100得到百位。则程序如下: int n,a,b,c;(n是要判断的数,具体根据题意赋值或从键盘输入)a=n/100;b=n/10%10;c=n%10;if(a*a*a+b*b*b+c*c*c==n)printf(“%d is the shuixianhua number!n”,n);本题分析:只要用上面的程序替换掉模版的那个if就可以了,则程序如下: int n;for(n=1;n<=1000;n++){ a=n/100;b=n/10%10;c=n%10;if(a*a*a+b*b*b+c*c*c==n)printf(“%d is the shuixianhua number!n”,n);} 6、用一张100的钱换100张零钞,假设面额有5元,3元,1/2元三种,问有多少种方法? 分析:这是一道解方程组的题,根据我们的小学知识可以列出方程组,其中有三个未知数,所以应该是三层嵌套循环,再分析题目我们知道1/2的张数只能是偶数张,则程序为: int i,j,k,n;for(i=0;i<=20;i++)for(j=0;j<=33;j++)for(k=0;k<=100;k++)if(5*i+3*j+k/2==100&&i+j+k==100&&k%2==0){ printf(“%d,%d,%dn”,i,j,k);n++;} printf(“There are %d changes!n”,n); 7、爱因斯坦阶梯问题。设有一阶梯,每步跨2阶,最后剩1阶;每步跨3阶,最后剩2阶;每步跨5阶,最后剩4阶;每步跨6阶,最后剩5阶;每步跨7阶,正好到阶梯顶。问满足条件的最少阶梯数是多少? 分析:这道题的实质是找满足上述条件的数,而且要最小的,那么我们就写一个循环,循环变量从最小的数开始递增,分析题目我们可知从7开始递增即可(如果不从7,从1开始也是可以的),一旦满足上述条件,循环变量就不需要增加了,输出循环变量即可,所以我们选择while循环结构,当不满足上述条件我们就做循环变量的递增,如果满足就输出,则程序为: int n=7;while(!(n%2==1&&n%3==2&&n%5==4&&n%6==5&&n%7==0)){ n++;} printf(“%dn”,n); 8、求一句英文所含有的单词数。 分析:一句英文里面每个单词之间都用空格隔开,所以我们只要数空格的个数即可,但是注意最后一个单词后面是没有空格的。一句英文肯定要存放在数组中,我们选择简单的一维数组。从字符数组中的第一个元素开始查看,先查看第一个元素,如果不是空格,那就证明是第一个单词,单词个数加一,然后一直做循环,直到遇到空格,就说明这个单词结束了,然后再判断是不是到数组的结尾,如果没有就继续查找,直到数组结束为止,则程序如下: #include } 五.图案:输出n行的具有规律的字符,组成我们所想要的图案。模版: int i,j,k;for(i=0;i 具体对待)for(k;;)printf(“%d”,);(注意:如果是char类型就是%c)} 1、输出下列图案 * *** ***** printf(“ There are %d words.n”,num);******* ********* ******* ***** *** * 分析:这种图案一般我们会将其分为两部分,从最多一行隔开,分为上下两个部分,先输出上面的图案,再输出下面的。通过分析我们可以发现每行既要输出空格,又要输出*,所以循环体里面需要两个循环,循环体里面的循环变量的控制最好和外层的控制行数的循环变量相关联。我们用i控制行数,用j控制每行的空格数,用k控制每行的*数,通过观察我们发现如下规律: i j k 0 4 1 1 3 3 2 2 5 3 1 7 4 0 9 那么,i+j=4,k均为奇数,再分析发现k=2i+1,每行输完还要输出换行,则程序如下: int i,j,k;for(i=0;i<5;i++){ for(j=0;j<4-i;j++)printf(“ ”);for(k=0;k<2*i+1;k++)printf(“*”);printf(“n”);} for(i=0;i<4;i++){ for(j=0;j 2、输出下列图案 A BBB CCCCC DDDDDDD EEEEEEEEE FFFFFFF GGGGG HHH I 分析:这种图案一般我们会将其分为两部分,从最多一行隔开,分为上下两个部分,先输出上面的图案,再输出下面的。通过分析我们可以发现每行既要输出空格,又要输出字母,所以循环体里面需要两个循环,循环体里面的循环变量的控制最好和外层的控制行数的循环变量相关联。我们用i控制行数,用j控制每行的空格数,用k控制每行的字母数,通过观察我们发现如下规律: i j k 0 4 1 1 3 3 2 2 5 3 1 7 4 0 9 那么,i+j=4,k均为奇数,再分析发现k=2i+1。每行的字母相同但是和上下行的不相同,观察发现字母是按照顺序递增的,那么我们就先把字母存放在一个变量里面,然后在输出每行所需的字符之后,改变字母。每行输完还要输出换行,则程序如下: int i,j,k;char c=’A’;for(i=0;i<5;i++){ for(j=0;j<4-i;j++)printf(“ ”);for(k=0;k<2*i+1;k++)printf(“%c”,c);c++;printf(“n”);} for(i=0;i<4;i++){ for(j=0;j 3、输出下列图案 121 12321 1234321 123454321 1234321 12321 121 1 分析:这种图案一般我们会将其分为两部分,从最多一行隔开,分为上下两个部分,先输出上面的图案,再输出下面的。通过分析我们可以发现每行既要输出空格,又要输出数字,所以循环体里面需要两个循环,循环体里面的循环变量的控制最好和外层的控制行数的循环变量相关联。我们用i控制行数,用j控制每行的空格数,用k控制每行的数字数,每行的数字还不相同,观察发现数字是按照顺序递增递减的,那么我们输出数字的循环又要分为两个循环,继续观察我们发现每次输出的数字和循环变量k有关,通过观察我们发现如下规律: i j k 0 4 1 1 3 2 2 2 3 3 1 4 4 0 5 那么,i+j=4,k均为奇数,再分析发现k的递增从1开始到i+1为止,递减是从i开始到1为止。每行输完还要输出换行,则程序如下: int i,j,k;for(i=0;i<5;i++){ for(j=0;j<4-i;j++)printf(“ ”);for(k=1;k<=i+1;k++)printf(“%d”,k);for(k=i;k>0;k--)printf(“%d”,k);printf(“n”);} for(i=0;i<4;i++){ for(j=0;j0;k--)printf(“%d”,k);printf(“n”);} 4、输出九九乘法表 1*1=1 1*2=2 2*2=4 1*3=3 2*3=6 3*3=9 1*4=4 2*4=8 3*4=12 4*4=16 „„ „„ 分析:如果用i表示行,j表示列,那么每行输出i个式子,分析发现每个式子可以用j*i表示。每行输完还要输出换行,则程序如下: int i,j;for(i=1;i<10;i++){ for(j=1;j<=i;j++)printf(“%d*%d=%dt”,j,i,j*i);printf(“n”);} 5、输出杨辉三角的前10行 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 1 6 15 20 15 6 1 7 21 35 35 21 7 1 8 28 56 70 56 28 8 1 9 36 84 126 126 84 36 9 1 分析:如果用i表示行,j表示列,那么每行输出i个数字,分析发现除了两头的数字为1以外,其余的每个数字每个数字等于上一行的左右两个数字之和,所以用二维数组比较简单。每行输完还要输出换行,则程序如下: int a[10][10],i,j;for(i=0;i<10;i++){ for(j=0;j<=i;j++){ if(i==j||j==0)a[i][j]=1;else a[i][j]=a[i-1][j]+a[i-1][j-1];printf(“%dt”,a[i][j]);} printf(“n”);} 五.字符串操作: 1.函数的原型说明为int chrn(char *s,char c);,其功能是测试c在s中出现的次数,编制该函数并用相应的主调函数对其进行测试。#include 电脑编程 从例1-1中可以看出C语言的一些书写格式和编程风格,下面将做具体解释。 1.文件包含命令 2.主函数 3.变量的定义 4.格式输入函数 5.格式输出函数 6.注释 C语言程序编写规则 从例1-1中可以看出C语言的一些书写格式和编程风格,下面将做具体解释。 1.文件包含命令 2.主函数 3.变量的定义 4.格式输入函数 5.格式输出函数 6.注释 开发C语言程序 我们前面了解到,高级语言远离计算机的硬件,它是使用易懂的类似于英文的语言编写的,不同于机器语言,因此,计算机是无法识别的。高级语言编写的程序指令在计算机运行时需要对其进行翻译,也就是转换成计算机能够读懂的二进制语言。 C语言程序的开发原理 使用高级语言编写出来的程序称为源程序,高级语言翻译成计算机能够读懂的二进制形式后的程序称为目标程序,这个翻译过程称为编译。完成这个翻译任务的系统称为编译系统。C语言的编译过程如图1-1所示。 C语言程序的开发过程 通过C语言的编译过程可以知道,用C语言编写的程序到计算机可以执行的操作是一个复杂的过程,但这些是用C语言编译器完成的,不需要用户的直接参与。C语言开发过程也是一个复杂的过程,是从建立源程序文件直到执行该程序并输出正确结果的全过程。在不同的操作系统和编译环境下运行一个C语言程序,其具体操作和命令形式可能有所不同,但基本过程是相同的。一般来说,这个过程要经历创建源程序、编译源程序、连接目标代码、运行可执行文件等过程。具体的开发过程如图1-2所示。 上机操作C语言程序 C语言的开发需要在一定的集成环境中进行,本书使用Visual C++ 6.0的集成开发环境。Visual C++ 6.0是一个基于Windows操作系统的可视化集成开发环境(Integrated Development Environment,IDE),是目前非常盛行的一种C编译系统,功能强大、操作方便、界面友好,已成为专业程序员进行软件开发的首选工具。 编程 人与人交流使用人类语言,人与计算机交流使用计算机语言。随着计算机技术的发展,计算机语言也逐步得到完善。C语言是当今世界应用最为广泛的程序设计语言。认识C语言有助于更好地学习、掌握和运用C语言。 计算机语言随着计算机技术的发展而不断地更新完善,人们最初使用的计算机语言是二进制代码也就是机器语言,后来使用助记符语言即汇编语言,现在使用最广泛的计算机语言是高级语言。 机器语言是计算机最早使用的语言。机器语言是直接用代码指令表达的,由0和1组成的一串二进制代码,这些二进制代码是面向CPU指令系统的,可以由计算机直接识别,不需要任何解释,执行速率很高。由于机器语言是面向硬件的,计算机使用的CPU类型不同,所以每一种类型的CPU都有一种对应的机器语言,因此,一台计算机上面的指令换到另一台机器上后就无法使用,由此可见,机器语言的移植性和通用性很差。机器语言是由二进制代码编写的,数据位数比较难记忆,在进行编写和输入时难度较大,并且是纯数据,可读性差,不便于程序员之间进行交流与合作,所以使机器语言无法获得迅速推广。 计算机执行用机器语言编写的程序的速度很快,但是难于记忆、辨认,编出的程序效率低、质量差,所以人们对机器语言作了一种改进:用一些简洁的英文字母、符号来代替特定的二进制指令串。例如,将十进制数1000送寄存器AX写成: MOV AX,1000 对于8088微处理器来说,机器语言编写的代码为: ***000000011 高级语言是目前绝大多数编程者的首选,它将许多相关的机器指令合成为一条指令,并且去掉了与具体操作有关但与完成工作无关的细节,大大简化了程序中的指令。高级语言是相对于低级语言而言的,它不是特指某一种具体的语言,而是包括很多编程语言,如Fortran、Pascal、Cobol、C、C++、Basic、Ada、Java、C# 等。 用高级语言编写的程序称为源程序。高级语言不是面向硬件的,计算机无法读懂,与汇编语言程序类似,需要进行转换。将高级语言程序转换成机器语言程序的过程称为编译,完成这个转换任务的系统称为编译系统。根据编译的时间不同,可将编译系统分为解释和编译两类。 面向对象的语言是在面向过程的计算机语言的基础上发展而来的。概括地讲,面向对象系统包含对象、类和继承三个要素,能支持这三个方面的语言被称为面向对象语言。面向对象语言的发展有两个方向:一种是纯面向对象语言,如Smalltalk等;另一种是混合型面向对象语言,即在过程式语言及其他语言中加入类、继承等成分,如C++等。 面向对象语言刻画客观系统较为自然,便于软件扩充与复用。面向对象语言系统中的基本构件可以认为是一组可识别的离散对象,具有相同数据结构与行为的所有对象可组成一类,具有唯一的静态类型和多个可能的动态类型,在基本层次关系的不同类中共享数据和操作。基于类的面向对象语言是面向对象世界的主流。面向对象的程序设计语言有C++、Java、C#、VB.NET。 1011 字符逆序 Description:将一个字符串str的内容颠倒过来,并输出。Str的长度不超过100个字符。 Input:输入包括一行。第一行输入的字符串。Output:输出转换好的逆序字符串。Sample input:I am a student Sample output:tneduts a ma I 解答: #include int main(){ int i = 0;char str[100];gets(str);int len=strlen(str)-1;for(i=len;i>=0;i--)printf(“%c”,str[i]);return 0;} 1541 课后习题9.1 Description:输入一行电报文字,将字母变成其下一字母(如a变成b,z变成a等)Input:一行字符 Output:加密处理后的字符 Sample Input:a b Sample Output:b c #include printf(“%sn”,str);return 0;} 1888 #include Input 输入只有三个正整数a、b、c。 Output 输出一行,包括三个的和、乘积、平均数。数据之间用一个空格隔开,其中平均数保留小数后面两位。 Sample Input 1 2 3 Sample Output 6 6 2.00 #include第三篇:编程小结3
第四篇:编程小结1
第五篇:编程题小结