程序调试的问题!!!!

boyzhxj 2002-04-15 08:02:58
我在调试一个程序时,本来变量N(作为形参传给函数)的值为8,执行玩一个FOR循环后,结束时弹出对话框,说一个叫_CTYPE.C.的文件找不到,然后下面的N就变成了一个随机数,导致后面的程序无法执行。请高手指点呀!!!!!!
...全文
224 7 打赏 收藏 举报
写回复
7 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
mldnking 2002-04-16
给你这个也许对你有用

电脑报Visual C++网络教程


附录1 Visual C++程序的调试

 

由于各种原因,在程序开发过程中难免会出现这样那样的错误。错误主要有三种:编译错误,运行错误和逻辑错误。编译错误可以通过检查C++语法、拼写以及函数参数形式等来排除。如果要排除运行过程中的错误和逻辑上的错误,则需要通过调试程序来完成。另外,调试本身也是一种很好的学习方法,通过调试跟踪,我们可以了解MFC的内部运行机制。因此,我们有必要了解调试技术,本附录就简要的介绍Visual C++程序调试技术。

 

1.启动调试器

Visual C++提供一个功能强大的内置集成调试器。要启动调试器,可以在Build菜单下选择Start Debug菜单。这个菜单有四个子菜单:Go,Step Into,Run to cursor,Attach to process。

Go命令从当前语句开始执行程序,直到遇到一个断点或程序结束。用Go命令启动调试器时,从头开始执行程序。Step Into单步执行每一程序行,遇到函数时进入函数体内单步执行。Run to cursor运行程序至当前光标位置。Attach to process将调试器与当前运行的其中某个进程联系起来,这样就可以跟踪进入进程内部,就象调试项目工作区中当前打开的应用程序一样调试运行中的进程。

2.调试菜单

启动调试器后,Build菜单消失,取而代之的是Debug菜单。Debug菜单提供如下菜单项用于调试程序,见表13.1。

 

表13.1 用于调试的菜单命令

菜单项 快捷键 作用
Go
F5
运行程序至断点或程序结束

Restart
Ctrl+Shift+F5
重新载入程序,并启动执行

Stop Debugging
Shift+F5
关闭调试会话

Break
  在当前位置出终止程序执行

Step Into
F11
单步执行,并进入所调用的函数体内

Step Over
F10
单步执行,但不进入函数

Step Out
Shift+F11
运行程序到当前函数调用结束后的第一条语句,即跳出当前调用的函数

Run to Cursor
Ctrl+F10
运行至当前光标(可插入字符)处

Exceptions
  用于设置异常,程序可以选择在遇到异常处停止或遇到未处理的异常处停止这两种异常处理方式。

Threads
  用于线程调试,可以挂起、恢复执行或切换活动线程

Step Into Specific Function
  直接进入某个函数内部执行,这对于多层嵌套的函数非常有用


 

 

注:按F7快捷键重建程序或关闭Developer Studio窗口等操作都会终止调试会话。

 

另外,在View菜单下还提供一个Debug Windows菜单,Debug Windows菜单有几个子菜单,用于隐藏或显示与调试工作相关的一些窗口。这些菜单有:

 

Watch
Alt+3
显示Watch窗口,用于观察和设置一些变量值

Call Stack
Alt+7
显示调用栈(call stack),可以让用户观察调用的全局函数和类成员函数情况。

Memory
Alt+6
观察未使用的内存块

Variables
Alt+4
观察与当前函数相关的全局变量和局部变量

Registers
Alt+5
观察微处理器的寄存器值

Disassembly
Alt+8
打开窗口显示汇编程序源代码


 

 

缺省情况下,启动调试器时,Developer Studio自动打开Varialbles和Watch、Debug三个窗口,如图13.1所示。



图13.1 调试窗口

 

在左边的Variables和右边的Watch窗口中,可以观察和修改变量的数值。在Variables窗口中,有三个标签:Auto,Local和This,分别用于观察和设置与当前函数相关的局部和全局变量、当前函数内的局部变量以及当前成员函数所对应的对象的相关数值。

要改变一个变量的数值,只需要选择变量在Values列的数值,然后输入一个新值,并按Enter键。

在窗口底部是Debug输出窗口,输出程序运行时的调试信息。

Visual C++调试器有一个非常有用的特性:当用户让鼠标器在某个变量上停留片刻后,就会出现一个小小的黄色Tip窗口,显示该变量当前数值。如果是指针,则显示指针数值;如果是字符串,就显示字符串内容。

3.设置断点

断点是指程序调试过程中暂时停止执行的地方。在断点处,可以观察、设置变量的数值,检查程序是否按所期望的逻辑执行,以排除程序中的错误。

 

插入断点

在源程序窗口内任一程序行上按鼠标右键,从右键快捷菜单中选择Insert/Remove Breakpoint菜单项,就可以在当前语句行处加入一个断点。此时,在语句行右边,会出现一个红色实心圆,指示当前行加了一个断点。

 

删除断点

在有断点的行上按右键弹出快捷菜单,选择Remove Breakpoint命令,就可以删除该断点。此时,程序行边上的红色实心圆消失。

 

禁止断点

有时候并不想删除断点,而只是希望暂时禁止断点,以后该断点可能还会用到。这是,可以从语句行的右键快捷菜单上选择Disable Breakpoint,禁止当前行的断点。此时,标志断点的红色实心圆变成空心圆,表示断点被禁止。

 

恢复断点

要恢复被禁止的断点,可以从含有被禁止断点的语句行的右键菜单中选择Enable Breakpoint命令。

4.用于调试的宏和函数

Visual C++提供了一些宏和成员函数用于调试程序。最常用的宏有:TRACE,ASSERT,ASSERT_VALID和CObject::Dump。

 

 

4.1 TRACE宏

TRACE宏在调试窗口输出变量数值,它采用类似于printf和CString::Format()成员函数的字符串格式化语法,在TRACE宏中,可以使用各种MFC类。举例如下:

int nSize=3;

CString sName(“why”);

TRACE(“Name=%s,Size=%d\n”,sName,nSize);

调试窗口输出

Name=why,Size=3

并换行。

 

4.2 ASSERT宏

ASSERT语法如下:

ASSERT(表达式);

如果表达式返回结果为真,则程序继续运行;如果返回结果为假,则在该语句行处终止程序运行,并弹出一个对话框,显示程序终止的行及所在文件信息。

如:

CMyFrame *pFrame=(CMyFrame*)AfxGetMainWnd();

ASSERT(pFrame->IsKindOf(RUN_TIMECLASS(CMyFrame)));

pFrame->DoSomeOperation();

又如:

CAge a(21);

ASSERT( a.IsKindOf( RUNTIME_CLASS( CAge ) ) );

ASSERT( a.IsKindOf( RUNTIME_CLASS( CObject ) ) );

 

4.3 ASSERT_VALID宏

ASSERT_VALID用于检查指针和对象的有效性。对于一般指针,只检查指针是否为空(NULL),如果为空,则终止程序执行。对于MFC对象指针,不但检查对象指针是否为空,还调用对象的AssertValid成员函数,判断对象合法性。这对于许多对象来说是非常有用的,比如,我们可以把人的年龄限制在1到150之间,如果超出这一范围,就可以认为是非法的数值。

ASSERT_VALID语法如下:

ASSERT_VALID(指针)

举例如清单13.1:

 

清单13.1 ASSERT_VALID宏的使用

class CPerson : public CObject

{

protected:

CString m_strName;

int m_nAge;

public:

CPerson(CString aName,int aAge);

//...

#ifdef _DEBUG

virtual void AssertValid() const; // Override

#endif

// ...

};

#ifdef _DEBUG

void CPerson::AssertValid() const

{

//首先调用父类的AssertValid方法

CObject::AssertValid();

//检查CPerson对象的数据成员

ASSERT( !m_strName.IsEmpty()); //姓名不能为空

ASSERT( (m_nAge > 0)&&(m_nAge<150) ); //年龄必需大于0且小于150

}

#endif

......

void CMainFrame::OnAddPerson()

{

CPerson* pPerson= new CPerson(“why”,25);

ASSERT_VALID(pPerson);

}

 

 

4.4 Dump

CObject::Dump用于输出对象内部数据成员的数值。当程序调试过程中希望检查对象内部状态时,Dump是非常有用的。Dump使用<<插入操作符输出数据成员数值。Dump的使用如清单13.2所示。

 

清单13.2使用Dump

void CAge::Dump( CDumpContext &dc ) const

{

CObject::Dump( dc );

dc << "Age = " << m_years;

}

其中,dc是一个CDumpContext类型的变量,有关CDumpContext参见Visual C++帮助文档。

 


--------------------------------------------------------------------------------

本教程由Visual C++王朝(Where programmers come together)协助制作
未经许可,请勿以任何形式复制


 

 

 

 
  • 打赏
  • 举报
回复
boyzhxj 2002-04-15
我试图在函数调用前把N付给一个变量,调用完了再付回给N,可是那个变量也变了!!!
  • 打赏
  • 举报
回复
lsqid 2002-04-15
宏定义就可以
  • 打赏
  • 举报
回复
flounder 2002-04-15
你将你的n定义为成员变量吧
  • 打赏
  • 举报
回复
boyzhxj 2002-04-15
void four1(float data[],unsigned long nn,int isign)
{
unsigned long n,mmax,m,j,istep,i;
float wtemp,wr,wpr,wpi,wi,theta; //??????????
float tempr,tempi;
n=nn<<1;
j=1;
for(i=1;i<n;i+=2){ //???????
if(j>i){
SWAP(data[j],data[i]); //??????
SWAP(data[j+1],data[i+1]);
}
m=nn>>1;
while((m>=2) && (j>m)){
j-=m;
m>>=1;
}
j+=m;
}
//
mmax=2;
while(n>mmax)
{ //??log2NN????
istep=mmax<<1;
theta=isign*(6.28318530717959/mmax); //????????
wtemp=sin(0.5*theta);
wpr=-2.0*wtemp*wtemp;
wpi=sin(theta);
wr=1.0+wpr;
wi=0.0;
for(m=1;m<mmax;m+=2)
{
for(i=m;i<=n;i+=istep)
{
j=i+mmax; //????棗?????
tempr=wr*data[j]-wi*data[j+1];
tempi=wr*data[j+1]+wi*data[j];
data[j]=data[i]-tempr;
data[j+1]=data[i+1]-tempi;
data[i]+=tempr;
data[i+1]+=tempi;
}
wr=(wtemp=wr)*wpr-wi*wpi+wr; //????
wi=wi*wpr+wtemp*wpi+wi;
}
mmax=istep;
}
}

/////////////////////////////////////////////////////////////////////
//??twofft
//??four1???????????? fft1?fft2,???n

void twofft(float data1[],float data2[],float fft1[],float fft2[],unsigned long ln)
{
//void four1(float data[],unsigned long nn,int isign);
unsigned long nn3,nn2,jj,j;
float rep,rem,aip,aim;

nn3=1+(nn2=2+ln+ln); //???????????????
for(j=1,jj=2;j<=ln;j++,jj+=2)
{
fft1[jj-1]=data1[j];
fft1[jj]=data2[j];
}
four1(fft1,ln,1); //???????
fft2[1]=fft1[2];
fft1[2]=fft2[2]=0.0;
for(j=3;j<ln+1;j+=2)
{
rep=0.5*(fft1[j]+fft1[nn2-j]); //??????????
rem=0.5*(fft1[j]-fft1[nn2-j]);
aip=0.5*(fft1[j+1]+fft1[nn3-j]);
aim=0.5*(fft1[j+1]-fft1[nn3-j]);
fft1[j]=rep; //?????????????
fft1[j+1]=aim;
fft1[nn2-j]=rep;
fft1[nn3-j]=-aim;
fft2[j]=aip;
fft2[j+1]=-rem;
fft2[nn2-j]=aip;
fft2[nn3-j]=rem;
}
;
}

void realft(float data[],unsigned long n,int isign)
{

unsigned long i,i1,i2,i3,i4,np3;
float c1=0.5,c2,h1r,h1i,h2i,h2r;
float wr,wi,wpr,wpi,wtemp,theta;

theta=3.141592653589793/(double)(n>>1);
if(isign==1)
{
c2=-0.5;
four1(data,n>>1,1);
}else
{
c2=0.5;
theta=-theta;
}
wtemp=sin(0.5*theta);
wpr=-2.0*wtemp*wtemp;
wpi=sin(theta);
wr=1.0+wpr;
wi=wpi;
np3=n+3;
for(i=2;i<=(n>>2);i++)
{
i4=1+(i3=np3-(i2=1+(i1=i+i-1)));
h1r=c1*(data[i1]+data[i3]);
h1i=c1*(data[i2]-data[i4]);
h2r=-c2*(data[i2]+data[i4]);
h2i=c2*(data[i1]-data[i3]);
data[i1]=h1r+wr*h2r-wi*h2i;
data[i2]=h1i+wr*h2i+wi*h2r;
data[i3]=h1r-wr*h2r+wi*h2i;
data[i4]=-h1i+wr*h2i+wi*h2r;
wr=(wtemp=wr)*wpr-wi*wpi+wr;
wi=wi*wpr+wtemp*wpi+wi;
}
if(isign==1)
{
data[1]=(h1r=data[1])+data[2];
data[2]=h1r-data[2];
}else
{
data[1]=c1*((h1r=data[1])+data[2]);
data[2]=c1*(h1r-data[2]);
four1(data,n>>1,-1);
}
}

////////////////////////////////
void comvlv(float data[],unsigned long n,float respns[],unsigned long m,int isign,float ans[])
{

unsigned long no2,tt,i;
//tt=n<<1;
float dum,mag2;
float fft[8];
// tt=n;
//fft=vector(1,n<<1);
for(i=1;i<=(m-1)/2;i++)
respns[n+1-i]=respns[m+1-i];
for(i=(m+3)/2;i<=n-(m-1)/2;i++)
respns[i]=0.0;
twofft(data,respns,fft,ans,n);//这个函数执行完,N 就变了!!
// n=tt;
no2=n/2;
for(i=2;i<=n+2;i+=2)
{
if(isign==1)
{
ans[i-1]=(fft[i-1]*(dum=ans[i-1])-fft[i]*ans[i])/no2;
ans[i]=(fft[i]*dum+fft[i-1]*ans[i])/no2;
}else if(isign==-1)
{
if((mag2=sqrt(ans[i-1])+sqrt(ans[i]))==0.0)
//nrerror("Deconvolving at response zero in convlv");
ans[i-1]=(fft[i-1]*(dum=ans[i-1])+fft[i]*ans[i])/mag2/no2;
ans[i]=(fft[i]*dum-fft[i-1]*ans[i])/mag2/no2;
}//else
//nrerror("No meaning for isign in convlv");
}
ans[2]=ans[n+1];
realft(ans,n-1,1);
// free_vector(fft,1,n<<1);
}
////////////////////////
void main()
{
float ire1[8]={1,2,3,4,5,6,7,8};
float ire2[8]={4,4,3,3,2,2,6,7};
float answer1[8];
float answer2[8];
unsigned long hh=8;
//twofft(ire1,ire2,answer1,answer2,hh);

comvlv(ire1,hh,ire2,hh,1,answer1);

int i;

cout << "answer1:"
<< '/n';
for(i=1;i<8;i++)
{
cout << answer1[i];
cout << '/n';
char aa;
cin >> aa;
}
// return 0;
}
  • 打赏
  • 举报
回复
Koshima 2002-04-15
说明白点!最好贴上代码!
  • 打赏
  • 举报
回复
killer_2001 2002-04-15
把代码贴出来看看呀!!
  • 打赏
  • 举报
回复
相关推荐
发帖
VC/MFC

1.6w+

社区成员

VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
帖子事件
创建了帖子
2002-04-15 08:02
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……