??xml version="1.0" encoding="utf-8" standalone="yes"?>
函数原型 COLORREF SetPixel( int x, int y, COLORREF crColor );
COLORREF SetPixel( POINT point, COLORREF crColor );
MoveTo()Q移动当前位|到指定的坐标,q回gؓ(f)以前位置的坐标;
函数原型 CPoint MoveTo( int x, int y );
CPoint MoveTo( POINT point );
LineTo()Q从当前位置到指定位|画一条直U,成功q回?Q?br> 函数原型 BOOL LineTo( int x, int y );
BOOL LineTo( POINT point );
Polyline()Q从当前位置Q绘d条曲U,成功q回?Q?br> 函数原型 BOOL Polyline( LPPOINT lpPoints, int nCount/*数目*/ );
Rectangle()Q根据指定参数绘制一个矩形,成功q回?Q?br> 函数原型 BOOL Rectangle( int x1, int y1, int x2, int y2 );
BOOL Rectangle( LPCRECT lpRect );
Ellipse()Q?Ҏ(gu)指定的矩形绘制一个内切椭圆,成功q回?Q?br> 函数原型 BOOL Ellipse( int x1, int y1, int x2, int y2 );
BOOL Ellipse( LPCRECT lpRect );
DrawIcon()Q在指定位置M个图标,成功q回?Q?br> 函数原型 BOOL DrawIcon( int x, int y, HICON hIcon );
BOOL DrawIcon( POINT point, HICON hIcon );
(2)、有x(chng)本处理的常用函数Q?br> TextOut()Q在函数参数指定的位|显C文本串?br> 函数原型 virtual BOOL TextOut( int x, int y, LPCTSTR lpszString, int nCount );
BOOL TextOut( int x, int y, const CString& str );
DrawText()Q在函数参数指定的矩形区域内昄文本丌Ӏ?br> 函数原型 virtual int DrawText( LPCTSTR lpszString, int nCount, LPRECT lpRect, UINT nFormat /*cd*/);
int DrawText( const CString& str, LPRECT lpRect, UINT nFormat );
SetTextColor()Q设|显C文本的颜色Q返回当前文本RGB颜色|
函数原型 virtual COLORREF SetTextColor( COLORREF crColor );
GetTextColor()Q获得当前文本颜Ԍ 函数原型 COLORREF GetTextColor( ) const;
SetBkColor()Q设|显C文本的背景颜色Q返回当前文本背景RGB颜色|
函数原型 virtual COLORREF SetBkColor( COLORREF crColor );
GetBkColor()Q获得当前文本背景颜Ԍ 函数原型 COLORREF GetBkColor( ) const;
SetBkMode()Q设|文本的背景模式Q返回当前背景模式|
函数原型 int SetBkMode( int nBkMode /*模式*/); TRANSPARENT透明Q?strong>OPAQUE 不透明
GetBkMode()Q获得当前文本背景模式; 函数原型 int GetBkMode( ) const;
SetTextAlign()Q设|显C文本的寚w方式Q成功返回非0Q?br> 函数原型 UINT SetTextAlign( UINT nFlags );
GetTextAlign()Q获得文本的寚w方式Q函数原?UINT GetTextAlign( ) const;
]]>
指针Q但要经q类型{?br>步骤Q?br>1、创Z个或多个属性页Q基cMؓ(f)CPropertyPage?br>class CPropSet1 : public CPropertyPage
{
// Dialog Data
//{{AFX_DATA(CPropSet1)
enum { IDD = IDD_PROP_SET1 };
int m_MAXVALUEX2;
int m_MINVALUEX2;
//}}AFX_DATA
}
2、徏立CProp表单Q基cMؓ(f)CPropertySheet?br>CPropSheet::CPropSheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage)
:CPropertySheet(nIDCaption, pParentWnd, iSelectPage)
{
AddPage(&m_propSet1); //军_page序
AddPage(&m_propSet2);
}
3、菜单函敎ͼ(x)
void CDataView::OnPropsheet()
{
// TODO: Add your command handler code here
CPropSheet propSheet("参数讄"); //表单名称Q其他ؓ(f)~省变量
propSheet.m_propSet1.m_MAXVALUEX2=m_XValueMax;
propSheet.m_propSet1.m_MINVALUEX2=m_XValueMin;
if( IDOK==propSheet.DoModal())
{
m_ChartCtrl1.EnableRefresh(false);
m_XValueMax=propSheet.m_propSet1.m_MAXVALUEX2;
m_XValueMin=propSheet.m_propSet1.m_MINVALUEX2;
m_ChartCtrl1.GetBottomAxis()->SetMinMax(m_XValueMin,m_XValueMax);
m_ChartCtrl1.EnableRefresh(true);
}
}
4、徏立向|(x)
首先在调用属性表单对象的DoModal函数之前Q调用SetWizardMode函数?br> propSheet.SetWizardMode();
然后通过SetWizardButtons函数讄向导对话框上的按钮?br> ((CPropSheet*)GetParent())->SetWizardButtons(PSWIZB_NEXT);
((CPropSheet*)GetParent())->SetWizardButtons(PSWIZB_NEXT | PSWIZB_BACK);
((CPropSheet*)GetParent())->SetWizardButtons(PSWIZB_BACK | PSWIZB_FINISH);
注意点:(x)需Ҏ(gu)字种cdcd?
]]>
BOOL CElectronValveView::OnPreparePrinting(CPrintInfo* pInfo)
{
// default preparation
pInfo->SetMinPage(1); //讄打印文g起始?nbsp;
pInfo->SetMaxPage(1); //讄打印文gl止?br> return DoPreparePrinting(pInfo);
}
void CElectronValveView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add extra initialization before printing
m_ChartCtrl.GetBottomAxis()->GetGrid()->SetColor(BlackColor);//讄栅格颜色为黑Ԍ不然打印的时候太?br> m_ChartCtrl.GetLeftAxis()->GetGrid()->SetColor(BlackColor);
}
void CElectronValveView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add cleanup after printing
m_ChartCtrl.GetBottomAxis()->GetGrid()->SetColor(BlueColor);//恢复颜色Q不然控件中也是q个颜色?jin)?br> m_ChartCtrl.GetLeftAxis()->GetGrid()->SetColor(BlueColor);
}
void CElectronValveView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
{
// TODO: add customized printing code here
CMainFrame* pMain=(CMainFrame *)AfxGetApp()->m_pMainWnd
CDC *pCurrentDC = GetDC(); // will have dimensions of the client area
CSize PaperPixelsPerInch(pDC->GetDeviceCaps(LOGPIXELSX), pDC->GetDeviceCaps(LOGPIXELSY));
//获得打印U设备每英寸的像素数Q应该是一L(fng)?br> CSize ScreenPixelsPerInch(pCurrentDC->GetDeviceCaps(LOGPIXELSX), pCurrentDC->GetDeviceCaps(LOGPIXELSY));
//应该是获得屏q的每英寸的像素敎ͼ应该是一L(fng)
CSize m_PaperSize,m_LogicalPageSize;
m_PaperSize = CSize(pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES));
//把纸张所得的像素对应的屏q大得到?br> m_LogicalPageSize.cx = ScreenPixelsPerInch.cx * m_PaperSize.cx / PaperPixelsPerInch.cx * 3 / 4;
m_LogicalPageSize.cy = ScreenPixelsPerInch.cy * m_PaperSize.cy / PaperPixelsPerInch.cy * 3 / 4;
//q里必须q样设,是ؓ(f)?jin)和ChartCtrl中的打印对应h?br> pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(m_LogicalPageSize);
pDC->SetViewportExt(m_PaperSize);
pDC->SetWindowOrg(0, 0);
CRect rcClient,rcClient1;
GetClientRect(&rcClient1); //得到的仍然是打印预览昄客户区的大小
rcClient=pInfo->m_rectDraw;//打印U的客户?br> double ratioX,ratioY;
ratioX=(double)rcClient.right/(double)rcClient1.Width();
ratioY=(double)rcClient.bottom/(double)rcClient1.Height();
int nWid,left,right;
CFont *pOldFont;
CFont fnBig,fnBig1;
CPen Pen,*OldPen;
//M?br> Pen.CreatePen(PS_SOLID,2,RGB(0,0,0));
OldPen=pDC->SelectObject(&Pen);
pDC->Rectangle(20,20,m_LogicalPageSize.cx-20,m_LogicalPageSize.cy-20);
pDC->SelectObject(OldPen);
//L题栏
pDC->MoveTo(20,60);
pDC->LineTo(m_LogicalPageSize.cx-20,60);
pDC->MoveTo(20,85);
pDC->LineTo(m_LogicalPageSize.cx-20,85);
pDC->SelectObject(&Pen);
pDC->MoveTo(20,110);
pDC->LineTo(m_LogicalPageSize.cx-20,110);
pDC->SelectObject(OldPen);
pDC->MoveTo(196,60);
pDC->LineTo(196,110);
pDC->MoveTo(390,60);
pDC->LineTo(390,110);
//ȝ果栏
pDC->MoveTo(20,430);
pDC->LineTo(m_LogicalPageSize.cx-20,430);
pDC->MoveTo(85,430);
pDC->LineTo(85,470);//量l果1分界U竖U?br> pDC->MoveTo((m_LogicalPageSize.cx-85-100)/4+85,430);//开启响应时间分界线
pDC->LineTo((m_LogicalPageSize.cx-85-100)/4+85,470);
pDC->MoveTo((m_LogicalPageSize.cx-85-100)/4*2+85,430);
pDC->LineTo((m_LogicalPageSize.cx-85-100)/4*2+85,470);
pDC->MoveTo((m_LogicalPageSize.cx-85-100)/4*3+85,430);
pDC->LineTo((m_LogicalPageSize.cx-85-100)/4*3+85,470);
pDC->MoveTo((m_LogicalPageSize.cx-85-100)/4*4+85,430);
pDC->LineTo((m_LogicalPageSize.cx-85-100)/4*4+85,470);
pDC->MoveTo(20,450);
pDC->LineTo(m_LogicalPageSize.cx-20,450);
pDC->SelectObject(&Pen);
pDC->MoveTo(20,470);
pDC->LineTo(m_LogicalPageSize.cx-20,470);
pDC->SelectObject(OldPen);
//写标?br> fnBig.CreatePointFont(200,"黑体",pDC);
pOldFont=pDC->SelectObject(&fnBig);
nWid=rcClient1.Width();
left=rcClient1.left;
right=rcClient1.right;
pDC->SetTextAlign(TA_CENTER);
pDC->TextOut(m_LogicalPageSize.cx/2,30,"XXX性能试报告");
fnBig.DeleteObject();
fnBig.CreatePointFont(110,"?hu)?,pDC);
pOldFont=pDC->SelectObject(pOldFont);
pOldFont=pDC->SelectObject(&fnBig);
pDC->SetTextAlign(TA_LEFT);
pDC->TextOut(25,67,"产品名称Q?+pMain->m_strProductName);
pDC->TextOut(25,92,"产品囑֏Q?+pMain->m_strProductPictureNo);
pDC->TextOut(201,67,"(g)时_(d)(x)"+pMain->m_strMeasureTime0);
pDC->TextOut(201,92,"生厂家Q?+pMain->m_strProductFactory);
pDC->TextOut(395,67,"产品~号Q?+pMain->m_strProductBianHao);
pDC->TextOut(395,92,"(g) ?员:(x)"+pMain->m_strMeasurerName);
CString aa;
aa.Format("%d(ms)",m_iPreviousTime1);
fnBig.DeleteObject();
fnBig.CreatePointFont(85,"?hu)?,pDC);
pDC->SelectObject(&fnBig);
pDC->TextOut(25,420,"预置?sh)信h_(d)(x)"+aa);
aa.Format("%d",m_iCurveNumber1);
pDC->TextOut(150,420,"曲线数量Q?+aa);
fnBig1.CreatePointFont(100,"?hu)?,pDC);
pOldFont=pDC->SelectObject(&fnBig1);
pDC->TextOut(25,455,"试l果");
pDC->TextOut(90,435,"开启响应时?ms)");
pDC->TextOut(120,455,m_strOpenResponseTime);
pDC->TextOut((m_LogicalPageSize.cx-85-100)/4+85+5,435,"开启换向时?ms)");
pDC->TextOut((m_LogicalPageSize.cx-85-100)/4+85+5+30,455,m_strOpenInvertTime);
pDC->TextOut((m_LogicalPageSize.cx-85-100)/4*2+85+5,435,"关闭响应旉(ms)");
pDC->TextOut((m_LogicalPageSize.cx-85-100)/4*2+85+5+30,455,m_strCloseResponseTime);
pDC->TextOut((m_LogicalPageSize.cx-85-100)/4*3+85+5,435,"关闭换向旉(ms)");
pDC->TextOut((m_LogicalPageSize.cx-85-100)/4*3+85+5+30,455,m_strCloseInvertTime);
pDC->TextOut((m_LogicalPageSize.cx-85-100)/4*4+85+10,435,"(g)结?);
//最后一?br> fnBig.DeleteObject();
fnBig.CreatePointFont(130,"?hu)?,pDC);
pDC->SelectObject(&fnBig);
pDC->TextOut(m_LogicalPageSize.cx-180,m_LogicalPageSize.cy-20-20,"审核Q?);
pDC->SetTextAlign(TA_LEFT);
CPoint offset(16,110);
m_ChartCtrl.Print1(offset,pDC,pInfo,0);//调用chartcL画表格和曲线
fnBig.DeleteObject();
CFormView::OnPrint(pDC, pInfo);
}
本程序利用ChartCtrl来实现绘制表格和曲线?/p>
// 创徏囑փ昄的对象ƈd囑փ文g
m_pPicObj = new CPictureObj;
if(!m_pPicObj->Load(lpszFileName))
{
// d文gp|Q清除对?br> m_pPicObj = NULL;
delete m_pPicObj;
// 清除昄的图像ƈ昄错误提示
PaintDib(IsValidDib());
return FALSE;
}
PaintDib(IsValidDib());
return TRUE;
}
catch (CFileException* e)
{
m_lpszFileName = NULL;
PaintDib(IsValidDib());
e->Delete();
return FALSE;
}
}
void CDIBStatic::PaintDib(BOOL bDibValid)//昄
{
ASSERT_VALID(this);
ClearDib(); // 清除以前的图?br>
CRect PaintRect;
// 获得昄区域
GetClientRect(&PaintRect);
PaintRect.InflateRect(-1, -1);
CClientDC dc(this);
if (bDibValid && m_bPreview)
{
CSize size = m_pPicObj->GetSize(&dc);
int nDestX, nDestY, nDestWidth, nDestHeight;
if ((DWORD)size.cx < (DWORD)PaintRect.Width() && (DWORD)size.cy < (DWORD)PaintRect.Height())
{ // 囑փ寸于昄区域图像显C在中间
nDestX = PaintRect.left + (PaintRect.Width() - size.cx)/2;
nDestY = PaintRect.top + (PaintRect.Height() - size.cy)/2;
nDestWidth = size.cx;
nDestHeight = size.cy;
}
else
{ // 囑փ寸大于昄区域Q进行比例羃?
if ((PaintRect.Width()/(float)size.cx) <= (PaintRect.Height()/(float)size.cy))
{ // 宽度限制
nDestWidth = PaintRect.Width();
nDestHeight = (nDestWidth*size.cy) / size.cx;
nDestX = PaintRect.left;
nDestY = PaintRect.top + (PaintRect.Height() - nDestHeight) /2;
}
else
{ // 高度限制
nDestHeight = PaintRect.Height();
nDestWidth = (nDestHeight*size.cx) / size.cy;
nDestX = PaintRect.left + (PaintRect.Width() - nDestWidth) /2;
nDestY = PaintRect.top;
}
}
// 获得囑փ的显CZ|和大小
CRect RectDest(nDestX, nDestY, nDestX+nDestWidth, nDestY+nDestHeight);
// 昄囑փ
m_pPicObj->Draw(&dc,&RectDest,&RectDest);
// l图像加一外框
CBrush* pOldBrush = (CBrush*)dc.SelectStockObject(NULL_BRUSH);
dc.Rectangle(RectDest);
if(NULL != pOldBrush) { dc.SelectObject(pOldBrush); }
}
else
{
// 昄错误提示信息
CString strText = "不能识别的文件格?";
if( m_lpszFileName == NULL || strlen(m_lpszFileName) <= 0 )
{
strText = "没有选择文g!";
}
if( !m_bPreview )
{
strText = "";
}
dc.DrawText(strText, strText.GetLength(), &PaintRect, DT_SINGLELINE|DT_CENTER|DT_VCENTER|DT_END_ELLIPSIS);
}
return;
}
HBRUSH CDIBSatic::CtlColor(CDC* pDC, UINT nCtlColor)//用于重绘
{
// TODO: Change any attributes of the DC here
PaintDib(IsValidDib());
return (HBRUSH)GetStockObject(NULL_BRUSH);
}
BOOL IsValidDib() const { return (m_pPicObj && m_pPicObj->m_pPict); }
void CDIBSatic::ClearDib()//清除囄
{
ASSERT_VALID(this);
CClientDC dc(this);
CRect rectPaint;
GetClientRect(&rectPaint);
rectPaint.InflateRect(-1,-1);
CBrush* pBrushWhite; //白画?br> pBrushWhite = CBrush::FromHandle((HBRUSH)::GetStockObject(WHITE_BRUSH));
dc.FillRect(&rectPaint, pBrushWhite);
}
void RemoveDib() { m_lpszFileName = NULL; delete m_pPicObj; m_pPicObj = NULL; PaintDib(IsValidDib()); }
void SetPreview(BOOL bPreview) { m_bPreview = bPreview; PaintDib(IsValidDib()); }
CPreviewFileDlg源代码:(x)
BOOL CPreviewFileDlg::OnInitDialog()
{
CFileDialog::OnInitDialog();
m_DIBStaticCtrl.SubclassDlgItem(IDC_IMAGE, this);
CWnd* pParent = GetParent();
CRect rcParent;
pParent->GetClientRect(&rcParent);
CRect rcPrev;
GetDlgItem(IDC_PREVIEW)->GetClientRect(&rcPrev); //复选框
CRect rc;
m_DIBStaticCtrl.GetClientRect(&rc);
int height = rc.Height();
rc.top = rcPrev.bottom - 10;//囑փ框设|?br> rc.bottom = rc.top + height ;
rc.left = 50;
rc.right = rcParent.Width() - rc.left;
m_DIBStaticCtrl.MoveWindow(&rc, true);
GetDlgItem(IDC_PREVIEW)->SendMessage(BM_SETCHECK, (m_bPreview) ? 1 : 0);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void CPreviewFileDlg::OnFileNameChange()
{
CFileDialog::OnFileNameChange();
if (m_bPreview)
{
m_DIBStaticCtrl.SetPreview(m_bPreview);//昄囄
m_DIBStaticCtrl.LoadDib(GetPathName()); //加蝲
}
}//当点?yn)L件时调用
void CPreviewFileDlg::OnFolderChange()
{
CFileDialog::OnFolderChange();
m_DIBStaticCtrl.RemoveDib();//清除
}
菜单栏源代码Q?br>void CPreviewDlg::OnPreview()
{
// TODO: Add extra validation here
static char BASED_CODE szFilter[] = "Bitmap(*.bmp)|*.bmp|JPEG(*.jpg)|*.jpg|GIF(*.gif)|*.gif|WMF(*.wmf)|*.wmf|ICON(*.ico)|*.ico||";
CString strDefName;
char szPath[MAX_PATH];//最大目录大?br>
CPreviewFileDlg FileDlg(TRUE,"*.*",NULL,
OFN_FILEMUSTEXIST|OFN_NONETWORKBUTTON|
OFN_PATHMUSTEXIST,szFilter);
FileDlg.m_ofn.lpstrInitialDir = szPath;
if( FileDlg.DoModal() != IDOK )
return;
// To get the selected file's path and name
CString strFileName;
strFileName = FileDlg.GetPathName();
if(strFileName.IsEmpty())
{
return;
}
}
1、函数原型及(qing)说明Q?/span>
void *malloc(long NumBytes)Q?/span>
该函数分配了(jin)NumBytes个字节,q返回了(jin)指向q块内存的指针。如果分配失败,则返回一个空指针Q?/span>NULLQ?/span>
关于分配p|的原因,应该有多U,比如说空间不_是一U?/span>
void free(void *FirstByte)Q?/span>
该函数是之前用malloc分配的空间还l程序或者是操作pȝQ也是释放?jin)这块内存,让它重新得到自由?/span>
2、函数的用法Q?/span>
其实q两个函数用h倒不是很难,也就?/span>malloc()之后觉得用够?jin)就甩?jin)它把它给free()?jin),举个单例子:(x)
E序代码Q?/span>
// Code...
float *YValue;
YValue=(float *)malloc(DataNumberMax*sizeof(float)); //动态分配内?/strong>
if (NULL == YValue) exit (1);
gets(YValue);
// code...
free(YValue);
YValue= NULL;
// code...
是q样Q当?dng)具体情况要具体分析以及(qing)具体解冟뀂比如说Q你定义?jin)一个指针,在一个函数里甌?jin)一块内存然后通过函数q回传递给q个指针Q那么也?dng)R放这块内存这工作就应该留给其他函数?jin)?/span>
3、关于函C用需?strong>注意的一些地方:(x)
A、申请了(jin)内存I间后,必须(g)?/strong>是否分配成功?/span>
B、当不需要再使用甌的内存时Q记?strong>释放Q释攑应该把指向这块内存的指针指向NULLQ防止程序后面不心(j)使用?jin)它?/span>
C、这两个函数应该?strong>配对。如果申请后不释攑ְ是内存泄Ԍ如果无故释放那就是什么也没有做。释攑֏能一ơ,如果释放两次?qing)两ơ以上?x)出现错误Q释攄指针例外Q释攄指针其实也等于啥也没做,所以释攄指针释放多少ơ都没有问题Q?/span>
D、虽?/span>malloc()函数的类型是(void *),Mcd的指针都可以转换?/span>(void *),但是最好还是在前面q行强制cd转换Q因样可以躲q一些编译器的检查?br>
二?/span>malloc()到底从哪里得来了(jin)内存I间Q?/span>
1?/span> malloc()到底从哪里得C(jin)内存I间Q?/span> {案是从堆里面获得空间?/span>也就是说函数q回的指针是指向堆里面的一块内?/strong>。操作系l中有一个记录空闲内存地址的链表。当操作pȝ收到E序的申hQ就?x)遍历该链表Q然后就LW一个空间大于所甌I间的堆l点Q然后就该l点从空闲结炚w表中删除Qƈ该l点的空间分配给E序。就是这P
2?strong>什么是堆:(x)堆是大家共有的空_(d)分全局堆和局部堆?/strong>全局堆就是所有没有分配的I间Q局部堆是用户分配的空间。堆在操作系l对q程 初始化的时候分配,q行q程中也可以向系l要额外的堆Q但是记得用完了(jin)要还l操作系l,要不然就是内存泄漏?/span>
什么是栈:(x)栈是U程独有的,保存其运行状态和局部自动变量的?/span>栈在U程开始的时候初始化Q每个线E的栈互相独立。每个函数都有自q栈,栈被用来在函C间传递参数?/strong>操作pȝ在切换线E的时候会(x)自动的切换栈Q就是切?/span>SS/ESP寄存器。栈I间不需要在高语言里面昑ּ的分配和释放?/span>
通过上面Ҏ(gu)늚描述Q可以知道:(x)
栈是q译器自动分配释放Q存攑և数的参数倹{局部变量的值等?/span>操作方式cM于数据结构中的栈?/span>
堆一般由E序员分配释放,若不释放Q程序结束时可能?/span>OS回收。注意这里说是可能,q一定。所以我惛_一ơ,记得要释放!
所以,举个例子Q如果你在函C面定义了(jin)一个指针变量,然后在这个函数里甌?jin)一块内存让指针指向它。实际上Q这个指针的地址是在栈上Q但是它所指向的内容却是在堆上面的Q这一点要注意Q所以,再想惻I在一个函数里甌?jin)空间后Q比如说下面q个函数Q?/span>
E序代码Q?/span>
// code...
void Function(void)
{
char *p = (char *)malloc(100 * sizeof(char));
}
p个例子,千万不要认ؓ(f)函数q回Q函数所在的栈被销毁指针也跟着销毁,甌的内存(sh)׃栯着销毁了(jin)Q这l对是错误的Q因?strong>甌的内存在堆上Q而函数所在的栈被销毁跟堆完全没有啥关系。所以,q是那句话:(x)记得释放Q?/span>
3?/span>free()到底释放?jin)什?/span>
free()释放的是指针指向的内?/span>Q注意!释放的是内存Q不是指针!q点非常非常重要Q?strong>指针是一个变量,只有E序l束时才被销毁。释放了(jin)内存I间后,原来指向q块I间的指针还是存在!只不q现在指针指向的内容的垃圾,是未定义的,所以说是垃圾。因此,前面我已l说q了(jin)Q释攑ֆ存后把指针指?/span>NULLQ防止指针在后面不小?j)又被解引用了(jin)。非帔R要啊q一点!
三?/span>malloc()以及(qing)free()的机Ӟ(x)
事实上,仔细看一?/span>free()的函数原型,也许也会(x)发现g很神奇,free()函数非常单,只有一个参敎ͼ只要把指向申L(fng)间的指针传?/span>
l?/span>free()中的参数可以完成释攑ַ作!q里要追t到malloc()的申请问题(sh)(jin)?strong>甌的时候实际上占用的内存要比申L(fng)大。因出的I间是用来记录对q块内存的管理信息?/strong>
malloc()甌的空间实际我觉得是分了(jin)两个不同性质的空间?strong>一个就是用来记录管理信息的I间Q另外一个就是可用空间了(jin)?/strong>而用来记录管理信息的实际上是一个结构体。在C语言中,用结构体来记录同一个对象的不同信息?/span>
下面看看q个l构体的原型Q?/span>
E序代码Q?/span>
struct mem_control_block {
int is_available; //q是一个标讎ͼ
int size; //q是实际I间的大?/span>
};
对于size,q个是实际空间大。这里其实我有个疑问Q?/span>is_available是否是一个标讎ͼ因ؓ(f)我看?/span>free()的源代码之后对这个变量感觉有点纳P源代码在下面分析Q。这里还请大家指出!
所以,free()是Ҏ(gu)q个l构体的信息来释?/span>malloc()甌的空_(d)而结构体的两个成员的大小我想应该是操作系l的事了(jin)。但是这里有一个问题,malloc()甌I间后返回一个指针应该是指向W二U空_(d)也就是可用空_(d)不然Q如果指向管理信息空间的话,写入的内容和l构体的cd有可能不一_(d)或者会(x)把管理信息屏蔽掉Q那没法释攑ֆ存空间了(jin)Q所以会(x)发生错误Q(感觉自己q里说的是废话)(j)
好了(jin)Q下面看?/span>free()的源代码Q我自己分析?jin)一下,觉得比vmalloc()的源代码倒是Ҏ(gu)单很多。只是有个疑问,下面指出Q?/span>
E序代码Q?/span>
// code...
void free(void *ptr)
{
struct mem_control_block *free;
free = ptr - sizeof(struct mem_control_block);
free->is_available = 1;
return;
}
看一下函数第二句Q这句非帔R要和关键。其实这句就是把指向可用I间的指针倒回去,让它指向理信息的那块空_(d)因ؓ(f)q里是在g减去?jin)一个结构体的大!后面那一?/span>free->is_available = 1;我有点纳P我的x(chng)是:(x)q里is_available应该只是一个标记而已Q因Zq个变量的名UC来看Q?/span>is_available 译q来是“是可以用”。不要说我土Q我觉得变量名字可以反映一个变量的作用Q特别是严}的代码。这是源代码Q所以我觉得l对是严谨的Q!q个变量的值是1Q表明是可以用的I间Q只是这里我想了(jin)惻I如果把它改ؓ(f)0或者是其他g知道?x)发生什么事Q!但是有一Ҏ(gu)可以肯定Q就是释攄对不?x)那么顺利进行!因?f)q是一个标讎ͼ
当然Q这里可能还是有Z(x)有疑问,Z么这样就可以释放呢?Q我刚才也有q个疑问。后来我惛_Q释放是操作pȝ的事Q那么就free()q个源代码来看,什么也没有释放Q对吧?但是它确实是定?jin)管理信息的那块内存的内宏V所以,free()只是记录?jin)一些信息,然后告诉操作pȝ那块内存可以去释放,具体怎么告诉操作pȝ的我不清楚,但我觉得q个已经出?jin)我q篇文章的讨围了(jin)?/span>
那么Q我之前有个错误的认识,是认ؓ(f)指向那块内存的指针不移到那块内存(sh)的哪个位|都可以释放那块内存Q但是,q是大错牚wQ释放是不可以释放一部分的!首先q点应该要明白。而且Q从 free()的源代码看,ptr只能指向可用I间的首地址Q不?dng)减去l构体大之后一定不是指向管理信息空间的首地址。所以,要确保指针指向可用空间的首地址Q?br>E序代码Q?br>float *YValuePoint;
while ( !feof(file) && i<DataNumberMax) //L
{
fscanf(file,"%f ",&data);
YValue[i]=data;
sum+=YValue[i];
pLineSerie->AddPoint(XValue++,YValue[i]);
i++;
}
average=sum/DataNumberMax;
max=*YValue;
min=*(YValue+2);
YValuePoint=YValue; //保存首地址
for(int j=0;j<DataNumberMax;j++)
{
if(max <* YValue)
{
max =* YValue;
}
else
{
if(min > *YValue) min = *YValue;
}
YValue++; //YValue地址?1
}
free(YValuePoint); //释放内存Q释放从该内存空间的首地址开?/strong>
一Q?回顾指针概念Q?/strong> #include<stdio.h> printf("误入一l数l的?\n"); printf("误入二l数l的?\n"); printf("用指针输Zl数l?\n"); printf("用指向指针的指针变量输出一l数l?1):\n"); printf("用指针输Zl数l?\n"); printf("用指向指针的指针变量输出二维数组(1):\n"); 利用指向指针的指针变量对二维字符数组的访问?/p>
#include<stdio.h> for(i=0;i<4;i++)/*按行输出字符?/ } } printf("用指向指针的指针变量输出二维数组(2):\n"); }
早在本系列第二篇中我对指针的实质进行了(jin)阐述。今天我们又?a onclick="javascript:tagshow(event, '%D1%A7%CF%B0');" href="javascript:;" target=_self>学习(fn)一个叫做指向另一指针地址的指针。让我们先回一下指针的概念吧!
当我们程序如下申明变量:(x)
short int i;
char a;
short int * pi;
E序?x)在内存某地址I间上ؓ(f)各变量开辟空_(d)如下图所C?br>内存地址→6 7 8 9 10 11 12 13 14 15
-------------------------------------------------------------------------------------
… | | | | | | | | | |
-------------------------------------------------------------------------------------
|short int i |char a| |short int * pi|
图中所CZ可看出:(x)
i 变量在内存地址5的位|,占两个字节?br>a变量在内存地址7的位|,占一个字节?br>pi变量在内存地址9的位|,占两个字节?注:(x)pi 是指针,我这里指针的宽度只有两个字节Q?2位系l是四个字节)
接下来如下赋?
i=50;
pi=&i;
l过上在两句的赋|变量的内存映象如?
内存地址→6 7 8 9 10 11 12 13 14 15
--------------------------------------------------------------------------------------
… | 50 | | | 6 | | | |
--------------------------------------------------------------------------------------
|short int i |char a| |short int * pi|
看到没有Q短整型指针变量pi的gؓ(f)6Q它?yu)是I变量的内存v始地址。所以,q时当我们对*piq行d操作Ӟ其实是对i变量的读写操作。如Q?br>*pi=5; //是{h(hun)于I=5;
二. 指针的地址与指向另一指针地址的指?/strong>
在上一节中Q我们看刎ͼ指针变量本n?a onclick="javascript:tagshow(event, '%C6%E4%CB%FC');" href="javascript:;" target=_self>其它变量一样也是在某个内存地址中的Q如pi的内存v始地址?0。同L(fng)Q我们也可能让某个指针指向这个地址?br>看下面代码:(x)
short int * * ppi; //q是一个指向指针的指针Q注意有两个*?br>ppi=pi
W一句:(x)short int * * ppi;——申明了(jin)一个指针变量ppiQ这个ppi是用来存储(或称指向Q一个short int * cd指针变量的地址?br>W二句:(x)&pi那就是取pi的地址Qppi=pi是把pi的地址赋给?jin)ppi。即地址?0赋值给ppi。如下图Q?br>内存地址→6 7 8 9 10 11 12 13 14 15
------------------------------------------------------------------------------------
… | 50 | | | 6 | 10 | |
------------------------------------------------------------------------------------
|short int i|char a| |short int * pi|short int ** ppi|
从图中看出,指针变量ppi的内容就是指针变量pi的v始地址。于?#8230;…
ppi的值是多少呢?—?0?br>*ppi的值是多少呢?—?,即pi的倹{?br>**ppi的值是多少呢?—?0,即I的|也是*pi的倹{?br>呵呵Q不用我说太多了(jin)Q我怿你应明白q种指针?jin)吧Q?br>
三. 一个应用实?/strong>
1Q?设计一个函敎ͼ(x)void find1(char array[], char search, char * pi)
要求Q?/strong>q个函数参数中的数组array是以0gؓ(f)l束的字W串Q要求在字符串array中查扑֭W是参数search里的字符。如果找刎ͼ函数通过W三个参敎ͼpaQ返回gؓ(f)array字符串中W一个找到的字符的地址。如果没扑ֈQ则为pa??br>设计Q?/strong>依题意,实现代码如下?br>void find1(char array[] , char search, char * pa)
{
int i;
for (i=0;*(array+i)!=0;i++)
{
if (*(array+i)==search)
{
pa=array+i
break;
}
else if (*(array+i)==0)
{
pa=0;
break;
}
}
}
你觉得这个函数能实现所要求的功能吗Q?br>调试Q?/strong>
我下面调用这个函数试试?br>void main()
{
char str[]={“afsdfsdfdf\0”}; //待查扄字符?br> char a=’d’; //讄要查扄字符
char * p=0; //如果查找到后指针p指向字W串中查扑ֈ的第一个字W的地址?br> find1(str,a,p); //调用函数以实现所要操作?br> if (0==p )
{
printf (“没找刎ͼ\n”);//1.如果没找到则输出此句
}
else
{
printf(“扑ֈ?jin),p=%d”,p); //如果扑ֈ则输出此?br> }
}
分析Q?/strong>
上面代码Q你认ؓ(f)?x)是输出什么呢Q?br>q行试试?br>唉!怎么输出的是Q没有找刎ͼ
而不是:(x)扑ֈ?jin)?#8230;…?br>明明agؓ(f)’d’Q而str字符串的W四个字W是’d’Q应该找得到呀Q?br>再看函数定义处:(x)void find1(char array[] , char search, char * pa)
看调用处Qfind1(str,a,p);
依我在第五篇的分析方法,函数调用时会(x)Ҏ(gu)一个参数进行一个隐含的赋值操作?br>整个调用如下Q?br> array=str;
search=a;
pa=p; //h意:(x)以上三句是调用时隐含的动作?br> int i;
for (i=0;*(array+i)!=0;i++)
{
if (*(array+i)==search)
{
pa=array+i
break;
}
else if (*(array+i)==0)
{
pa=0;
break;
}
}
哦!参数pa与参数search的传递ƈ没有什么不同,都是g递嘛Q小语:(x)地址传递其实就是地址g递嘛Q!所以对形参变量pa|当然值是一个地址|(j)的修改ƈ不会(x)改变实参变量p|因此p的值ƈ没有改变(即p的指向ƈ没有被改??br>Q如果还有疑问,再看一看《函数参数的传递》了(jin)。)(j)
修正Q?/strong>
void find2(char [] array, char search, char ** ppa)
{
int i;
for (i=0;*(array+i)!=0;i++)
{
if (*(array+i)==search)
{
*ppa=array+i
break;
}
else if (*(array+i)==0)
{
*ppa=0;
break;
}
}
}
d数的调用处改如下Q?br> find2(str,a,&p); //调用函数以实现所要操作?br>再分析:(x)
q样调用函数时的整个操作变成如下Q?br> array=str;
search=a;
ppa=&p; //h意:(x)以上三句是调用时隐含的动作?br> int i;
for (i=0;*(array+i)!=0;i++)
{
if (*(array+i)==search)
{
*ppa=array+i
break;
}
else if (*(array+i)==0)
{
*ppa=0;
break;
}
}
看明白了(jin)吗?
ppa指向指针p的地址?br>?ppa的修改就是对p值的修改?br>下面看一下指向指针变量的指针变量怎样正确引用?br>用指向指针的指针变量讉K一l和二维数组?/p>
#include<stdlib.h>
main()
{
int a[3],b[2][2],*p1,*p2,**p3,i,j;
for(i=0;i<3;i++)
scanf("%d",&a[i]);/*一l数l的输入*/
for(i=0;i<2;i++)
for(j=0;j<2;j++)
scanf("%d",&b[i][j]);/*二维数组输入*/
for(p1=a,i=0;i<3;i++) /* 用指针输Zl数l?/
{
printf("%4d",*(p1+i));
}
printf("\n");
for(p1=a,p3=&p1,i=0;i<3;i++)
printf("%4d",*(*p3+i));/*用指向指针的指针变量输出一l数l?/
printf("\n");
printf("用指向指针的指针变量输出一l数l?2):\n");
for(p1=a;p1-a<3;p1++)/*用指向指针的指针变量输出一l数l?/
{
p3=&p1;
printf("%4d",**p3);
}
printf("\n");
for(i=0;i<2;i++) /*用指针输Zl数l?/
{
p2=b[i] ;
for(int j=0;j<2;j++)
{
printf("%4d",*(p2+j)) ;
}
}
printf("\n");
for(i=0;i<2;i++)/*用指向指针的指针变量输出二维数组*/
{
p2=b[i];
p3=&p2;
for(j=0;j<2;j++)
printf("%4d",*(*p3+j));
#include<stdlib.h>
main()
{
int i;
char * ptr;
static char c[][16]={"clanguage","fox","computer","homepage"};
/*二维字符数组*/
static char *cp[]={c[0],c[1],c[2],c[3]};/*指针数组*/
static char **cpp;/*指向字符指针的指针变?/
cpp=cp;/*指针数l的首地址传递给指向字符指针的指针变?/
for(i=0;i<4;i++)/*按行输出字符?/
printf("%s\n",*cpp++);
printf("-----------\n");
{
cpp=&cp[i];
printf("%s\n",*cpp);
}
printf("-----------\n");
for(i=0;i<4;i++)
{
ptr=c[i];
printf("%s",ptr);
printf("\n");
}
printf("\n");
for(i=0;i<2;i++)/*用指向指针的指针变量输出二维数组*/
{
p2=b[i];
for(p2=b[i];p2-b[i]<2;p2++)
{
p3=&p2;
printf("%4d",**p3);
}
printf("\n");
}
#include <iostream.h>
class Metal
{
public:
unsigned atomicNumber;
float atomicWeight;
float pricePerounce;
public:
Metal( unsigned Number=0,
float Weight=0.000000,
float Perounce=0.000000)
{
atomicNumber=Number;
atomicWeight=Weight;
pricePerounce=Perounce;
}
~Metal() {}
unsigned GetNumber(void) {return atomicNumber;} //内联函数
float GetWeight(void) {return atomicWeight;}
float Getprice(void) {return pricePerounce;}
virtual void output()
{
cout << "The atomic weight =" << atomicWeight << endl;
cout << "The atomic number =" << atomicNumber << endl;
cout << "Price per ounce =" << pricePerounce << endl;
}
};
class Pb : public Metal //公有l承Q单l承
{
public:
Pb (unsigned Number=82,float Weight=207,float Perounce=0.01):Metal(Number,Weight,Perounce) {}
//子类构造首先调用基cL造函?br>};
class Au : public Metal
{
public:
Au (unsigned Number=79,float Weight=196.9665,float Perounce=450.75):Metal(Number,Weight,Perounce) {}
Au (Pb& lemp) //拯函数
{
atomicNumber=lemp.GetNumber()-3;
atomicWeight=lemp.GetWeight()-10.2335;
pricePerounce=lemp.Getprice()+450.74;
}
};
void main ()
{
Pb m;
Au n=m; //拯
n.output();
}
zcȝ三种l承方式Q公有?public)、私有?private)、保护?protected)是常用的三种l承方式Q?br> 公有l承Ӟ水^讉K和垂直访问对基类中的公有成员?sh)受限制Q?br> U有l承Ӟ水^讉K和垂直访问对基类中的公有成员?sh)不能访问?br> 保护l承Ӟ对于垂直讉K同于公有l承Q对于水q问同于私有ѝ?br>
M一个类都可以派生出一个新c,zcM可以再派生出新类?/span>
// Destroy any previous menu
if (m_hMenu)
{
::DestroyMenu(m_hMenu);
m_hMenu = NULL;
m_hParentWndMenu = NULL;
m_bMenuDisplayed = FALSE;
} // if
// Load menu
if (nMenu)
{
// Find correct resource handle
hInstResource = AfxFindResourceHandle(MAKEINTRESOURCE(nMenu), RT_MENU);
// Load menu resource
m_hMenu = ::LoadMenu(hInstResource, MAKEINTRESOURCE(nMenu));
m_hParentWndMenu = hParentWnd;
// If something wrong
if (m_hMenu == NULL) return BTNST_INVALIDRESOURCE;
} // if
// Repaint the button
if (bRepaint) Invalidate();
return BTNST_OK;
} // End of SetMenu
DWORD CButtonST::SetMenu(UINT nMenu, HWND hParentWnd, BOOL bWinXPStyle, UINT nToolbarID, CSize sizeToolbarIcon, COLORREF crToolbarBk, BOOL bRepaint) //除前两个参数Q其他参数都有初始?br>{
BOOL bRetValue = FALSE;
// Destroy any previous menu
if (m_menuPopup.m_hMenu)
{
m_menuPopup.DestroyMenu();
m_hParentWndMenu = NULL;
m_bMenuDisplayed = FALSE;
} // if
// Load menu
if (nMenu)
{
m_menuPopup.SetMenuDrawMode(bWinXPStyle);
// Load menu
bRetValue = m_menuPopup.LoadMenu(nMenu);
// If something wrong
if (bRetValue == FALSE) return BTNST_INVALIDRESOURCE;
// Load toolbar
if (nToolbarID)
{
m_menuPopup.SetBitmapBackground(crToolbarBk);
m_menuPopup.SetIconSize(sizeToolbarIcon.cx, sizeToolbarIcon.cy);
bRetValue = m_menuPopup.LoadToolbar(nToolbarID);
// If something wrong
if (bRetValue == FALSE)
{
m_menuPopup.DestroyMenu();
return BTNST_INVALIDRESOURCE;
} // if
} // if
m_hParentWndMenu = hParentWnd;
} // if
// Repaint the button
if (bRepaint) Invalidate();
return BTNST_OK;
} // End of SetMenu