20201231-成信大-C语言程序设计-20201学期《C语言程序设计B》平时自主学习-跟踪调试题参考_请单击此处下载文件d13456.c,然后对程序进行跟踪调试,调试过程中不得对程序进行任-程序员宅基地

技术标签: c  c语言  成信大  

20201学期《C语言程序设计B》平时自主学习

D13428.C

题干:

请单击此处下载文件D13428.C,然后对程序进行跟踪调试,要求不增加或删除行,测试时输入的数据为6 1 3 2 9 -222。
程序的功能是:从键盘上读入一组整数(最多100个,但若读入的数为-222时,则表示输入结束且-222不算在该组数内),然后对这一组数按从小到大的顺序进行排序,最后将排序后的这一组数输出到屏幕上。

下载的文件内容是:

#include <stdio.h>

#define maxNums 100
#define endFlag -222

int input(int arr[]);
void px(int data[], int n);
void output(int sz[], int n);

int main(void)
{
    
	int num[maxNums], Count;
	
	Count = input(num);		//M1
	px(num, Count);			//M2
	output(num, Count);		//M3

	return 0;				//M4
}

//读入数据到arr中,以endFlag表示输入结束且不计endFlag,返回读到数据的个数
int input(int arr[])
{
    
	int i;

	printf("Please input numbers:");	//I1
	for (i=0; i<maxNums; i++)			//I2
	{
    
		scanf("%d", &arr[i]);			//I3
		if (arr[i] = endFlag)			//I4
		{
    
			break;						//I5
		}
	}

	return i;							//I6
}

//对data中的n个数按由小到大进行排序
void px(int data[], int n)
{
    
	int i, j, mini, tmp;

	for (i=0; i<n-1; i++)				//P1
	{
    
		mini = i;						//P2
		for (j=i+1; j<n; j++)			//P3
		{
    
			if (data[j] < data[mini])	//P4
			{
    
				mini = j;				//P5
			}
		}

		if (mini != i)					//P6
		{
    
			tmp = data[mini];			//P7
			data[mini] = data[i];		//P8
			data[i] = tmp;				//P9
		}
	}
}

//输出sz中的n个数
void output(int sz[], int n)
{
    
	int i;

	for (i=0; i<n; i++)					//O1
	{
    
		if (i % 13  == 0)				//O2
		{
    
			printf("\n");				//O3
		}
		printf("%-6d", sz[i]);			//O4
	}
	printf("\n");						//O5
}

调试注意事项

  1. 在VC60中,可以打断点调试,也可以直接使用debug工具调试
  2. 调试时,尽可能一 步步调试,查看内存中变量或是数组中的元素的值的变化
  3. 尽量把程序读懂了再调试
  4. 跟踪过程,要细心,点击时,手不能抖,一下子跑好几步,一定是单步跟踪
  5. 碰到程序自定义函数时,一定要跟踪进入
  6. 有进入,就有返回跳出
  7. 有不需要的循环,如不需要关注的循环体,或是空循环等,可以运行到光标处,提高调试效率
  8. 每一行一条语句,可以分为
    1. 执行前
    2. 执行
    3. 执行后
    4. 一定要注意自己的光标所在的位置
  9. 如果出错,或是弹出窗口,要注意光标所在的当前位置
  10. 跟踪过程中,随时注意内存数据的变化,要知道变化的原因【因为赋值语句的执行,或是赋值表达式动作的执行】
  11. 自定义函数进入和跳出,要特别注意作用域发生的变化

对于跳转后的数组可见性的分析

主函数main的作用域

int main(void)
{
    
	int num[maxNums], Count;
	
	Count = input(num);		//M1
	px(num, Count);			//M2
	output(num, Count);		//M3

	return 0;				//M4
}

显然,在主函数的作用域里,只能见到num数组和Count变量

当进入到input函数中时

功能函数input的作用域

//读入数据到arr中,以endFlag表示输入结束且不计endFlag,返回读到数据的个数
int input(int arr[])
{
    
	int i;

	printf("Please input numbers:");	//I1
	for (i=0; i<maxNums; i++)			//I2
	{
    
		scanf("%d", &arr[i]);			//I3
		if (arr[i] = endFlag)			//I4
		{
    
			break;						//I5
		}
	}

	return i;							//I6
}

进入到这个作用域之后,可以见到的变量有:

  • 循环变量i
  • 形参数组arr
    • 主函数中的调用语句是:Count = input(num); //M1
    • 进入之后,num是实参,实参的大小是确定的
    • 发生调用跳转后,可以在watch窗口添加对arr[0],arr[1],arr[2],arr[3],arr[4],arr[5]元素的监视,因为这时,已经看不到num[0],num[1],num[2],num[3],num[4],num[5]了一定要小心这一点,但本质上,这两个数组名指针,指向的是同一块内存空间。因为数组名作用函数的参数,是传的地址,即首地址,数组的首地址
    • 还可以看到两个全局变量,即:maxNums和endFlag

程序的出错点

if (arr[i] = endFlag)			//I4

分析:

  • 这一步,看似在进行比较判断,实质在做一个赋值动作,即endFlag的值,会写入到arr[i]中,第一次时,i的值就是0,也就是数组的首元素被赋值为0,见最后的图,在执行I4之后,num[0]的值变为-222
  • 平时写程序,要特别注意这样的低级错误,C的语法,要求相等判断要用==,而不是=

再进入到px函数作用域

//对data中的n个数按由小到大进行排序
void px(int data[], int n)
{
    
	int i, j, mini, tmp;

	for (i=0; i<n-1; i++)				//P1
	{
    
		mini = i;						//P2
		for (j=i+1; j<n; j++)			//P3
		{
    
			if (data[j] < data[mini])	//P4
			{
    
				mini = j;				//P5
			}
		}

		if (mini != i)					//P6
		{
    
			tmp = data[mini];			//P7
			data[mini] = data[i];		//P8
			data[i] = tmp;				//P9
		}
	}
}

在这个作用域里,内存上可见:

  • i,j,mini,tmp,这些,就是本地变量,也叫局部变量,即这个函数的局部可见可用

  • 两个形参变量:data数组 和 n

  • 而这里,由于data在获取实参数,本质上就是data指针也指向了主函数的num数组,所以,对data的操作,即为对num的操作

  • 这里程序的算法是实现了选择排序

  • 显然,对于测试数据

测试时输入的数据为6 1 3 2 9 -222

第一轮,会选出1和6交换

第二轮,会选出2和6交换

最终,有序的结果是:

1 2 3 6 9

这个即为M2执行后的num数组的状态

如果一步步跟踪程序的执行细节,可以看到选择排序的过程

  • 第1次p9执行后,1和6交换
  • 第2次p9执行后,2和6交换
  • 而回到M2时,数组num已经变得有序了

小题答题情况

在这里插入图片描述

D13454.C

程序内容

#include <stdio.h>

int main(void)
{
    
	int iA, iB;

	printf("please input x y: ");	//M1
	scanf("%d%d", &iA, &iB);		//M2

	if (iA = iB)					//M3
	{
    
		printf("\nyes\n");			//M4
	}
	else
	{
    
		printf("\nno\n");			//M5
	}

	return 0;
}


逻辑出错位置:

if (iA = iB)					//M3

分析:

  • 误将判断搞成了赋值
  • 低级编程引发的血案
  • 再次强调:等于是用双等号,等于是关系运算,等号是赋值运算

题目参考解答

在这里插入图片描述

D13455.C

程序内容

#include <stdio.h>
#include <string.h>

#define N 128

void conj(char *s1, char *s2, char *s3);

int main(void)
{
    
	char s1[N * 2] = "99999", s2[N]="8888888", s3[N * 2]="777777777";

	printf("Please input string1: ");	//M1
	gets(s1);							//M2
	printf("Please input string2: ");
	gets(s2);							//M3

	conj(s1, s2, s3);
	printf("\ns3 = %s\n", s3);

	return 0;
}

void conj(char *s1, char *s2, char *s3)
{
    
	int i1, i2, j;

	for (i1=0, i2=0; s1[i1]!='\0' || s2[i2]!='\0'; )
	{
    
		for (j=0; j<1000; j++)
		{
    
			;  //本步骤实际没有意义,别管它!
		}

		if (s1[i1] != '\0')
		{
    
			s3[i1 + i2] = s1[i1];
			i1++;					//C1
		}

		if (s2[i2] != '\0')
		{
    
			s3[i1 + i2] = s2[i2];
			i2++;					//C2
		}
	}
	s3[i1 + i2] = '\0';				//C3
}

跟踪过程要点

  • 字符串和字符数组的内涵关系
    • 数组用于装字符串
    • 字符串有结束符\0
    • 字符串可以申请很大内存空间,但只使用一部分
    • 完成输入后,之后的内存空间里的数据是不用管的,到\0就结束了字符串
  • 跟踪技巧
    • 碰到循环,先找到光标位置
    • 再要运行到光标处,提高效率

题目参考解答

在这里插入图片描述

D13456.C

程序内容

#include <stdio.h>
#include <string.h>

#define N 128

void rev(char *str);
void conj(char *s1, char *s2, char *s3);
char *up(char *str);


int main(void)
{
    
	char s3[N*2], s1[N*2], s2[N];

	printf("Please input string1: ");
	gets(s1);
	printf("Please input string2: ");
	gets(s2);

	conj(s1, s2, s3);
	printf("\ns3 = %s\n", s3);

	return 0;
}

void conj(char *s1, char *s2, char *s3)
{
    
	int i1, i2, j;

	for (i1=0, i2=0; s1[i1]!='\0' || s2[i2]!='\0'; )
	{
    
		for (j=0; j<1000; j++)
		{
    
			printf("H\n%s\n", up(s2));
		}

		if (s1[i1] != '\0')
		{
    
			s3[i1 + i2] = s1[i1];
			i1++;
		}

		if (s2[i2] != '\0')
		{
    
			s3[i1 + i2] = s2[i2];     //C1
			i2++;
		}
	}

	s3[i1 + i2] = '\0';
	rev(s3);
	up(s3);
}

void rev(char *str)
{
    
	int i, len, mid;
	FILE * fp;

	len = strlen(str);
	mid = len / 2 + 10;

	for (i=0; i<mid; i++)
	{
    
		char tmp;
	
		tmp = str[i];
		str[i] = str[len - i -1];
		str[len - i -1] = tmp;
	}
	
	fp = fopen("temp.txt", "w");
	if (fp == NULL)
	{
    
		printf("file open error");
	}
	else
	{
    
		fprintf(fp, "%s", str);
		printf("%f", len);
		fclose(fp);
	}
}

char *up(char *str)
{
    
	static int m=1;
	char *old = str;

	while (*str)
	{
    
		if (*str >= 'a' && *str <= 'z')
		{
    
			*str -= 'a' - 'A' - 1;
			*str = (*str - 'A' + m) % 26 + 'A';
		}
		else if (*str >= 'A' && *str <= 'Z')
		{
    
			*str += 'a' - 'A' + 1;
			*str = (*str - 'a' + m) % 26 + 'a';
		}
		str++;
	}
	m++;
	m  %= 10;

	return old;
}

本题特点

程序无编译连接错误,其功能和意义不需要了解,也不需要读懂!!!

跟踪过程要点

  • 自定义的函数,一定要step into
  • 系统的库函数,一定要step over

题目参考解答

在这里插入图片描述

最后的建议

  • 因为是学习,所以还是把每一行代码读懂啊
  • 要学会调试本身,而不是做题
  • 要学会使用断点
  • 要学会高效调试,特别是程序的运行结果与程序员的预期不一致时
  • 把内存里的数据看清楚,想清楚,就是开始进阶到高级编程阶段的时候
  • 理解:图灵机和冯诺依曼的工作原理
    • 存储程序【写内存】
    • 执行程序【读内存】
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/matrixbbs/article/details/112041401

智能推荐

qt移植到OK6410开发板linux系统过程_qt lunix 通过网线复制到开发板-程序员宅基地

文章浏览阅读1.7k次。操作系统:ubuntu 11.04交叉编译工具链:arm-linux-gcc 4.3.2 源码:qt-everywhere-opensource-src-4.7.3.tar.gz移植过程:1 下载源码,解压,进入解压后文件夹:#tar zxvf qt-everywhere-opensource-src-4.7.3.tar.gz#cd qt-everywhere-o_qt lunix 通过网线复制到开发板

集体通宵发版怎么破?阿里敏捷教练开出四道“药方”-程序员宅基地

文章浏览阅读762次。阿里妹导读:忙不完的事情,解不完的bug,每次发版都得集体熬个大通宵。干得多,结果还不好。相信绝大部分技术工作者都有过这样的困扰。今天,阿里云效敏捷教练蔡春华以团队敏捷实..._干移动外包熬夜发版

SSM框架搭建使用json遇到406错误_som.406-程序员宅基地

文章浏览阅读897次。1. 后台返回JSON格式的数据,会报406错误。(fastjson)原因:Springframework框架版本过旧,最新的版本可以。2.请求报错:No converter found for return value of type: class com.alibaba.fastjson.JSONObject原因:报这种错误表示fastjson 或 jackson 转换SpringMVC错误,需_som.406

csdn-工具 资源 大全_csdn工具站-程序员宅基地

文章浏览阅读353次。1 .Android系统在超级终端下必会的命令大全(adb shell命令大全) 2 . 顶级外语学习资源[转] 近600个教学学习资料链接 3 .电脑故障维修判断指导大全(联想内部文件)[网络转载] 4 .11月热门下载资源TOP100强力推荐! 5 .电子书下载网址大全 6 .电脑知识大全 7 .电脑DOS命令大全 8 .Windows 2003安全设置大全 9 .电脑快捷键大_csdn工具站

“做好大数据测试,我是认真的!”-程序员宅基地

文章浏览阅读1w次,点赞20次,收藏102次。阿里妹导读:大数据已然是当下的重要课题,大大小小的企业在重视大数据的同时,也渐渐重视大数据质量的问题。阿里巴巴测试开发专家小郅,今天会分享他对数据测试的系统性思考。文章内..._大数据测试工作规划

lvs+keepalived+nginx高性能负载均衡集群-程序员宅基地

文章浏览阅读4.6k次,点赞14次,收藏60次。lvs+keepalived+nginx高性能负载均衡集群项目发布时候,别人还能访问呢?双机主从热备LVS作用LVS是一个开源的软件,可以实现传输层四层负载均衡。LVS是Linux Virtual Server的缩写,意思是Linux虚拟服务器。目前有三种IP负载均衡技术(VS/NAT、VS/TUN和VS/DR);八种调度算法(rr,wrr,lc,wlc,lblc,lblcr,dh..._lvs+keeplived、nginx工作原理

随便推点

Android开发笔记(三十)SQLite数据库基础操作_"string create_sql = \"create table if not exists -程序员宅基地

文章浏览阅读3.2k次。SQLite语法SQLite是一个小巧的嵌入式数据库,使用方便、开发简单,手机上最早由ios运用,后来android兴起同样也采用了sqlite。sqlite的多数sql语法与oracle是一样的,下面只列出不同的地方:1、建表时为避免重复操作,应加上“IF NOT EXISTS”关键词,例如:CREATE TABLE IF NOT EXISTS table_name2、同样的,删表时_"string create_sql = \"create table if not exists \" + table_name + \" (\" + \"_id"

linux指定网卡走流量,Linux实时输出指定网卡流量-程序员宅基地

文章浏览阅读706次。理论上能正常运行ifconfig的Linux操作系统都可适用这个脚本(当然一般默认会安装perl),打印实时网卡流量和丢包数,好久前当时为了验证输出流量随手写的,多次想改得漂亮点,一直没动手,就这样吧,以免用的时候找不到其实我还想评论自己一句:把Perl写得跟C语言新手一样,真是Perl的悲哀!!!#!/usr/bin/perl -w################################..._linux 所有流量使用指定网卡

OpenCV4萌新之路——详解图像显示三兄弟 “imshow”、“namedWindow” 和“waitKey”_opencv imshow-程序员宅基地

文章浏览阅读2.2k次。OpenCV4萌新之路——详解图像显示三兄弟 “imshow”、“namedWindow” 和“waitKey”一、函数简析二、参数详解1.1 const String & winname1.2 InputArray mat2.1 int delay = 03.1 const String & winname3.2 int flags = WINDOW_AUTOSIZE三、测试代码四. 其他测试1.无限制缩放?2.支持OpenGL四、参考文献上一篇"OpenCV4萌新之路——详解图像读取函_opencv imshow

lightoj 1283 - Shelving Books DP_pipioj1283-程序员宅基地

文章浏览阅读570次。给定n个书本的厚度,然后依次放到书架上,要么放在最左边要么放在最右边,或者不放,要求书的厚度是非递减的序列。然后问最多放置多少本书。数字范围10^5,但是只有100个数字,我们先离散化一下。然后对于放置一本书来言,就是要么增大下界,要么减小上界,或者上下界都不变。那么我们可以采用dp[i][j]代表当前下界为i上界为j最多放置多少本书。对于一个新的书,就是产生dp[a[i]][j]_pipioj1283

我们一起来学习redis吧【redis的启动和关闭,配置文件详解】【redis.windows.conf和redis.windows-service.conf文件的区别】_redis.windows-service.conf和redis.windows.conf-程序员宅基地

文章浏览阅读1.1w次,点赞18次,收藏48次。1:redis的安装1.1:redis在window系统的安装省略,可以自行百度我这里安装的压缩版1.2:redis在linux系统的安装现在还没有用到,用到了再补上TODO2:redis的服务启动2.1:在windows系统中启动redis服务端使用cmd进入到redis的安装目录redis-server.exe redis.windows.conf可以在windows系统中编写一个启动文件,可以把该指令写入到startup.cmd文件中启动redis客户端重新启用一个cmd会_redis.windows-service.conf和redis.windows.conf

Sql注入waf过滤机制及绕过姿势-程序员宅基地

文章浏览阅读375次。在进行sql注入测试中总会遇到各种厂商的waf,本篇文章将对waf的过滤机制,以及常见的绕过方法进行介绍,希望在以后的测试中会对大家有所帮助。0x01 WAF的过滤机制 WAF全称网站应用级***防御系统是Web Application Firewall的简称,主要有以下四个功能:1. 审计设备--用来截获所有HTTP数据或者仅仅满足某些规则的会话 ;2. 访问控制设..._%d6%5c

推荐文章

热门文章

相关标签