使用VC++6.0调试程序
调试程序 调试运行 单步跟踪 单步跳进跟踪 观察自动变量 观察其他变量 停止调试
1:打开jiecheng项目(双击jiecheng.dsw文件) 2:build该项目,确定程序可以运行 3:调试运行阶乘程序 4:设置断点 5:再次调试运行程序 6:使用单步执行程序到结束
1:打开jiecheng项目
2:Build该项目,确定程序可以运行
3:调试运行阶乘程序 Go
4:设置断点 将鼠标停留在程序的第8行,在第8行的任意地方单击鼠标左键(第8行即“i = i*4;”) 在工具栏上选择 按钮,为第8行设置断点,以便让程序在此处暂停运行
5:再次调试运行阶乘程序 Go 注意观察,现在调试运行程序会如何?
5:再次调试运行阶乘程序(续) 程序暂停之处 调试(Debug)工具: 控制程序前进步伐 查看程序当前状态
6:使用单步执行到程序结束 设置断点以后,调试运行程序时,程序开始执行,并且运行到断点处暂停下来,此时我们有机会观察程序的运行情况,并且诊断程序目前的状态是否如我们所预期的那样。 不过我们先不着急观察程序的状态,而是来看看如何控制程序的运行,以便在我们需要的时候让程序暂停下来,并且以我们需要的方式走走停停!
6:使用单步执行到程序结束 程序停下来了,如何让程序从暂停的地方继续向前执行? 方法是使用单步执行手段(Step Over)让程序向前走一步 停止调试 停止调试并重新启动调试 单步执行 当前位置
熟悉调试工具栏和菜单(只在调试运行时出现) 对比调试运行时出现的 调试菜单“Debug”和调试 工具栏,根据图标查找 对应项
观察自动变量 自动变量
观察变量的值及其随程序运行时的变化情况 设置断点,调试运行程序,此时程序暂停在断点处等待 选择Debug菜单,找到 最后一项“Quick Watch” 并点击
点击Add Watch 输入想要观察的变量 变量名 变量的值
点击Add watch,看到如下画面
调试观察每一步骤变量i的值 点击单步执行按钮或者菜单,程序则向前单独运行一个步骤 每向前执行一步,就会暂停下来,这样我们就有充足的时间观察所关心的变量名称 观察变量i的值的情况
注意在调试过程中 断点不能设置在空白行上面 添加断点和删除断点的方法一样 一个程序中可以设置多个断点 按下F5键可以让程序从当前位置向前执行,直到遇见下一个断点或者程序结束
相关C语言基础知识 指针: 结构体:
指针
新建Visual C++程序 四、利用已有的程序编写新程序 无论是控制台程序,或者是Windows窗口程序,Visual C++都会要求有对应的项目文件。而且在大多数情况下,C程序的基本框架都是一致的,例如:都有主函数等等。所以在编写一个新的程序时,可以利用以前编写过的程序,其操作方法有两种。 (1)程序复用操作 将已有的程序复用到新程序上的方法很简单,就是将程序内容通过“复制―粘贴”实现。 (2)项目复用操作 打开已有的项目文件,将原来的文件删除,利用项目管理增加新程序文件或资源元素等。
新建Visual C++程序 五、项目管理 无论项目是否建立,只要开始程序的编译、链接、运行或调试过程,Visual C++就会按项目管理方式进行控制。 例如:当使用文件新建方式建立一个源程序文件后,只要开始编译则Visual C++会自动提示创建项目。
新建Visual C++程序
地址和指针的概念 一、指针概述: 1、“&” :地址运算符 2. “*” :指针运算符,取其指向的内容: exp: &a: 变量a的地址: *p: 变量p的内容; 注: “&” 不能施加在常数,常量和表达式上;
二、指针变量: 存放某种变量地址的变量称为指针变量。 二、指针变量: 存放某种变量地址的变量称为指针变量。 10 35 …. 2010 a b 2012 因此,在C语言中,将地址形象化地称为指针 p 2010 q 2012
定义一个指针变量 指针变量的定义一般形式为: 基类型 *指针变量名; 例如: int i, j, *pi, *pj; 定义一个指针变量 指针变量的定义一般形式为: 基类型 *指针变量名; 例如: int i, j, *pi, *pj; float x, y, *p1, *p2; 指针变量的赋值:使得指针变量指向变量 指针变量名=&变量名; 如: pi=&i; pj=&j; p1=&y; p2=&x; 注意:指针变量只能存放指针(地址),且只能是相同类型变量的地址。 例如,指针变量pi、pj,只能接收int型、p1, p2只能接收float型的地址,否则出错。
结构体
指针变量的引用 在程序中,可以用:*指针变量名 代替其所指变量。 如若: int i, *p; p=&i; 在程序中,可以用:*指针变量名 代替其所指变量。 如若: int i, *p; p=&i; 则 i=5; 与*p=5; 的作用相同,即可用*p代替i,这里*号称为指针运算符(或称为间接访问运算符)
指针变量作为函数参数 例10.3 通过函数调用实现例10.2的功能。 swap(int *p1, int *p2) {int temp; 实参:变量地址或已赋值的指针变量,形参:指针变量 功能:地址传送方式,会将改变后的值带回。 例10.3 通过函数调用实现例10.2的功能。 swap(int *p1, int *p2) {int temp; temp=*p1; *p1=*p2; *p2=temp; } main() {int a, b, *pointer1,*pointer2; scanf("%d%d",&a,&b); pointer1=&a; pointer2=&b; if(a<b) swap(&a,&b); printf("\n%d,%d",a,b);
数组与指针 1.概念 数组的指针──数组在内存中的起始地址,用数组名表示 2.指向数组的指针变量---赋于数组名的指针变量 数组与指针 1.概念 数组的指针──数组在内存中的起始地址,用数组名表示 2.指向数组的指针变量---赋于数组名的指针变量 例如,int a [10], *p=a (或*p=&a[0]); 或者: int a [10], *p; p=a;
3.通过指针引用数组元素 如果有“int a [10],*p=a;” ,则: (1)p+i==a+i==&a[i]。 (2)*(p+i)==*(a+i)==a[i]。 (3)p[i]==*(p+i)==a[i]。 注意:p+1指向数组的下一个元素,而不是简单地使指针变量p的值+1。其实际变化为p+1*size(size为一个元素占用的字节数)。 例如,假设指针变量p的当前值为3000,则p+1为3000+1*2=3002,而不是3001
用数组名作为函数参数 形参:数组或指针变量 实参:数组名或指向数组的指针变量 传递方式:地址传送方式 作用:若函数中对数组作了修改,则调用函数中的数组也会作同样的修改
指向函数的指针 1.函数指针的概念 一个函数在编译时,被分配了一个入口地址,这个地址就称为该函数的指针。 1.函数指针的概念 一个函数在编译时,被分配了一个入口地址,这个地址就称为该函数的指针。 可以用一个指针变量指向一个函数,然后通过该指针变量调用此函数。
2.指向函数的指针变量 (1)定义格式 函数类型 (*指针变量)( ); 注意:“*指针变量”外的括号不能缺,否则成了返回指针值的函数。 例如,int (*fp)(); /* fp为指向int函数的指针变量*/
(2)赋值 函数名代表该函数的入口地址。因此,可用函数名给指向函数的指针变量赋值。 指向函数的指针变量=[&]函数名; (2)赋值 函数名代表该函数的入口地址。因此,可用函数名给指向函数的指针变量赋值。 指向函数的指针变量=[&]函数名; 注意:函数名后不能带括号和参数;函数名前的“&”符号是可选的。
(3)调用格式 (*函数指针变量)([实参表]) 3.指向函数的指针变量作函数参数 指向函数的指针变量的常用用途之一,就是将函数指针作参数,传递到其它函数。 注意:对指向函数的指针变量,诸如p+i、p++/p--等运算是没有意义的。 例10.24 设有一个函数process,在调用它时,每次实现不同的功能。输入a和b两个数,第一次调用时找出a与b中的大者,第 二次找出小者,第三次求和。
#include<stdio.h> void main() {int max(int,int); int min(int,int); int add(int,int); int process(int, int, int (*fun)()); int a,b; printf("enter a and b:"); scanf("%d%d",&a,&b); printf("\nmax="); process(a,b,max); printf("\nmin="); process(a,b,min); printf("\nsum="); process(a,b,add); }
max(int x, int y) {return x>y?x:y;} min(int x, int y) {return x>y?y:x;} add(int x, int y) {return x+y;} process(int x, int y, int (*fun)(int,int)) /*fun是一个指向函数的指针,该函数是一个有两个整型参数的返回整型值的函数*/ {int result; result=(*fun)(x,y); printf("%d\n",result); }
返回指针值的函数 函数类型 *函数名(形参表列) 例如: int *a(int x,int y); 一个函数可以返回一个int型、float型、char型的数据,也可以返回一个指针类型的数据。 返回指针值的函数(简称指针函数)的定义格式如下: 函数类型 *函数名(形参表列) 例如: int *a(int x,int y); 该函数的函数名为a,返回的是一个整型的指针。
指针数组 指针数组的概念 数组的每个元素都是一个指针数据。指针数组比较适合用于指向多个字符串,使字符串处理更加方便、灵活。 指针数组的概念 数组的每个元素都是一个指针数据。指针数组比较适合用于指向多个字符串,使字符串处理更加方便、灵活。 数据类型 *数组名[元素个数] 例如: int *p[4]; char *string[10];
p指向数组a易混淆的问题 *p++,*p(++),*(++p),(*p) 设P指向a数组中的第i个元素: *(p--)==a[i--];
结 构 体
一、结构体类型的定义 结构体概念的引入 例: 描述一个学生的姓名、学号、性别、年龄。 数据的描述: 基本类型:整型、实型、字符型。 数组:属于同一种类型的元素的集合。 有时,需要用不同的数据类型来描述一个事物的各方面属性,故此,C语言引入了结构体的概念。 例: 描述一个学生的姓名、学号、性别、年龄。 每个学生都有这样的属性,它们构成一个描述学生具体情况的一个整体。而每个属性又是一个基本的类型,本例中可分别用字符数组、长整型、字符型、和整型来描述。
结构体类型的定义 struct 结构体类型名 { 类型标识符 成员名1; 类型标识符 成员名2; …… 类型标识符 成员名n; }; 如: { 类型标识符 成员名1; 类型标识符 成员名2; …… 类型标识符 成员名n; }; 如: struct student { char name[10]; long id; char gender; int age; } 注意: struct student 应作为一个类型整体, name[10]、id、gender、age都是其成员。 struct及花括号后的“;”不能省。
(1) 学生情况: 包含学生的学号、 姓名、 性别、 年龄、10门课程成绩: 结构体类型的举例 定义结构体类型, 描述下列数据 (1) 学生情况: 包含学生的学号、 姓名、 性别、 年龄、10门课程成绩: struct student { int no; /*学号*/ char name[10]; /*姓名*/ char sex; /*性别*/ int age; /*年龄*/ float score[10]; /*成绩*/ }; 注意 结构体类型可以嵌套定义 即一个结构体类型中的某些成员又是其他结构体类型
格式: struct 结构体名 结构体变量名表; 二、结构体变量 结构体变量的定义 三种方法: 1.先定义结构体类型, 再定义结构体变量 格式: struct 结构体名 结构体变量名表; 例如,对已定义的结构体类型struct student ,可以定义结构体 变量: struct student zhang ,stu1;
2.在定义结构体类型的同时定义变量 格式: struct 结构体类型名 { 类型标识符 成员名1; 类型标识符 成员名2; …… 类型标识符 成员名n; } 变量名表; 例如:struct student { char name[10]; char sex; int age; float score; } stu1,stu2;
结构体的说明 3. 用匿名形式直接定义结构体类型变量(不出现结构体名) 格式: struct { 类型标示符 成员名1; { 类型标示符 成员名1; 类型标示符 成员名2; …… 类型标示符 成员名n; } 变量名表; 例如:struct { char name[10]; char sex; int age; float score; } stu1,stu2; 结构体的说明 (1)类型与变量是不同的概念,不要混同。对结构体变量来说,在定义时一般先定义一个结构体类型,然后定义变量为该类型。只能对变量赋值、存取或运算,而不能对一个类型赋值、存取或运算。在编译时,对类型是不分配存储空间的,只对变量分配存储空间。 (2)对结构体中的成员,可以单独使用,它的作用相当于普通变量。 (3)成员也可以是一个结构体变量。 (4)成员名可与程序中的变量同名,两者不代表同一对象。
其中的圆点运算符称为成员运算符,它的运算级别是最高的。 结构体变量的使用 结构体变量一般不整体引用,而是引用其成员变量。 成员变量引用格式 结构体变量名.成员名 其中的圆点运算符称为成员运算符,它的运算级别是最高的。 例。定义结构体变量stu1: struct student stu1; stu1.age=20; scanf("%f",&stu1.score); stu1.age 表示引用结构体变量stu1中的age成员,因该成员的类型为int型,所以可以对它执行任何int型变量可以执行的运算。
说明 (1) 结构体类型变量的各成员(分量)必须单独引用,成员运算符“•”具有最高优先级。 (2) 不允许对结构体变量进行整体的输入输出 如:scanf(“%s%c%d%f”,&stu1); (3) 如果结构体变量类型相同,可以互相赋值。 stu1=stu2; (4) 严格区分类型与变量的概念。 (5) 如果结构体成员本身又是结构体类型的,则可继续使用成员运算符取结构体成员的结构体成员,逐级向下,引用最低一级的成员。程序只能对最低一级的成员进行运算。例如,对stu1某些成员的访问: stu1.birthday.day=23; stu1.birthday.month=8; stu1.birthday.year=1985;
结构体变量的初始化 格式 结构体变量可以在定义时初始化。 struct 结构体名 { 成员表; } 结构体变量={初始化数据表}; 例 struct student { char name[10]; char sex; int age; float score; }stu1,stu2={“Wangwu”,’m’,20,88.5};
四、结构体类型指针 一个结构体变量的指针就是该变量所占据的内存段的起始地址。可以定义一个指针变量,用来指向一个结构体变量,此时该指针变量的值是结构体变量的起始地址 。
指向结构体变量的指针 定义格式 struct 类型名 *指针变量名; 例如: struct student *pstu, stu; *pstu 表示指针pstu所指示的结构体变量(对象)stu,因而,其成员表示为(*pstu).name ,(*pstu).age。 为方便起见,C语言定义了结构体的指针变量引用结构体成员的特殊形式: 指针变量名->成员名 “->”为指向运算符 上面示例(*pstu).name,(*pstu).age。可以等价表示为: pstu->name, pstu->age
总结:结构体成员变量引用方式 ①结构体变量.成员名 ②(*p).成员名 ③p->成员名 其中,->称为指向运算符 可转换为: ①p->n ②(p->n)++ ③++(p->n) 请分析下列几种运算: ①p->n ②p->n++ ③++p->n