wujr5 / c-and-cpp-language-learning

C和C++编程语言学习 - 2015级
67 stars 34 forks source link

软件:week7 实验:c程序测试与断点调试 #17

Open ghostbody opened 8 years ago

ghostbody commented 8 years ago

实验3:c程序断点调试

C程序完成一般思路

  1. 对于复杂的逻辑需求,先写伪代码或者画程序流程图得到清晰的逻辑结构。
  2. 自顶向下逐步求精解决问题(大问题分解为可解决的小问题),写出C程序。
  3. 修改C程序的编译错误。
  4. 通过测试,修改C程序的逻辑错误。

    高效c语言编程方法

    1、命令行编译与高效文本编辑器

为什么使用命令行编译?

  1. 可以获得比集成编译系统(IDE)更高的自由度。
  2. 为之后的linux编程工具链打下基础。
  3. 更好的理解c程序编译执行过程。

配置方法: 1、打开Dev Cpp,并且找到对应的安装路径。 dev 2、找到定义的MinGW目录下的bin目录这个是dev cpp的核心编译器。

3、配置系统环境变量,在系统的高级选项中找到path(可见第一周python配置方法) path

4、打开cmd窗口,输入gcc --version输出编译器版本信息,配置完成。 image

编译方法: 1、找到一个c源代码所在的文件夹,在文件夹中按住shift+鼠标右键,选择在此处打开命令行。 2、输入gcc + 空格 + 你要编译的文件 -o 编译出来之后的可执行程序的名字, 如:gcc main.c -o main.exe(如果省略-o后面的命令,则会生成a.exe) gcc 3、在命令行中输入 main.exe 即可运行程序。

高效文本编辑器: 高效文本编辑器是一些专门为编程者设计的编辑器,他们具有自动缩进、自动补全代码、自由配置的特点,深受程序员喜爱。这些编辑器不仅仅c语言使用,c++、pyhton、html、markdown和许多其他语言都适用。他们有,vim、emacs、sublime等。

现在我们介绍sublime-text 3,这是一款收费软件,可是有无限试用期。 image

下载和使用请自行百度。

2、测试数据的文件输入输出代替键盘输入输出(重点)

现在大家做题一般的输入方法就是,按照西西里的测试例子,键盘输入,当程序错误的时候需要一次次输入非常繁琐,现在给大家提供一种高效而且重要的方法,文件流输入代替键盘流输入。

其实,在抽象的层面上,键盘输入、文件输入和网络输入等都是IO,是等价的。我们可以利用这个进行文件代替键盘输入。

1、在刚才我们编译的程序之中,我们生成了main.exe的程序。建设现在我们的程序是做a-b的简单运算。我们现在在源代码的同一个目录下新建一个文件"input.txt"。我们打开文件输入两个数100和99。 image input

2、接着我们在命令行输入命令main.exe < input.txt。我们很惊喜地发现,程序自动输出了1,我们不需要手动去使用键盘输出。 fileinput

对于长而复杂的输入,这无疑是一个简化的过程。

对于文件输出,同样是可以的 'main.exe < input.txt >output.txt' output

3、断点调试法(课题讲解)

错误示例代码(来源于同学)

#include<stdio.h>

struct employee {
    long id, salary, height, boss, subordinate;
};
int main() {
    struct employee a[10000], temp, current_deal, potential_boss, search;
    int total_test, current_test, current_e, e_num, id_search;
    int i, k, j, m, n, t, u;
    for (u = 1;u <= 10000;u++) {
        a[u].subordinate = 0;
        a[u].boss = 0;
        a[u].height = 0;
        a[u].id = 0;
        a[u].salary = 0;
    }
    printf("How many test do you want to have?\n");
    scanf("%d", &total_test);
    current_test = 1;
    while (current_test <= total_test) {
        printf("please input the number of employees\n");
        scanf("%d", &e_num);
        current_e = 1;
        for (i = 1;current_e <= e_num;i++) {
            printf("please input No.%d empolyees' id, salary, height(seperated by space)\n", i);
            scanf("%d %d %d", &a[i].id, &a[i].salary, &a[i].height);
            current_e ++;
        }  for (k = 1;k <= (e_num - 1);k++) {
            for(j = 1;j <= (e_num - 1);j++) {
                if(a[j].salary > a[j+1].salary) {
                    temp = a[j];
                    a[j] = a[j+1];
                    a[j+1] = temp; 
                }
            }
        }   

             for (m = 1;m <= e_num;m++) {
                     current_deal = a[m];
                for(n = e_num;n <= (m + 1);n--) {
                            potential_boss = a[n];
                    if(current_deal.height <= potential_boss.height) {
                        a[m].boss = potential_boss.id;
                        a[n+1].subordinate += 1;
                     }
                 }  
             }
             printf("please input the id you want to search for its boss and subordinates\n");
             scanf("%d", &id_search);
             for (t = 1;t <= e_num;t++) {
                if (id_search == a[t].id) {
                    search = a[t];
                 }
             }
             printf("(%d,%d)\n", search.boss, search.subordinate);
             current_test ++;

    }    
        return 0;
}

1、设置断点 2、运行程序 3、添加监控变量 4、执行程序、单步运行

ghostbody commented 8 years ago

Lab 3 : Breakpoint Debug

Pre Assignment:

  1. Learn about breakpoint debug method.
  2. Learn about file stream input for a C executable program.
  3. Learn about how to compile a program using command line interface.
  4. Learn about how to use sublime text efficiently to help you develop your c program.

Notice that: These knowledge is very important for you and it's a good preparation for the course project as well as some other following courses. You can ignore this assignment, but you are responsible for the yourself.

Assignment 0(10pts)

Learn about command line compile and file input. And then use the method on one of the questions in week 7 in sicily (write this part in your report and snap shoots are recommended).

Assignment 1(80pts):

Learn about breakpoint debug method yourself and using it to debug the following three C programs.

Target: A solution with three correct C source programs.

Questions:

  1. What is the bugs of the program and how can you find the bug? (8 pts)
  2. What test data you use in the debug process? (8 pts)
  3. Tell the problems about coding styling in the following program.(8 pts)
  4. Understand three sorting algorithm(Bubble sort, selection sort and insertion sort), and then write Pseudo code or Flowchart for them respectively.(16 pts)
  5. Correct the three programs' error include its style problems respectively and note that you should submit your source code. (45pts )

Notice that:

  1. Style is very important while coding, so if your new program is still ugly in style, 50% score will be deducted.
  2. We will use black box test this time with auto running scripts. So if your file structure is wrong or your program result in errors will cause 0pts. And the grade depends on how many test cases passed like that in YOJ.
  3. You should not add prompt statement this time like "please input an integer". The testing program will consider it to be wrong answer if you do it.
  4. Sample input and output for all the three correct programs. Input: The first line contain an integer n which indicates the number of test cases. There will be n line in the flowing. For each line, there will be an integer m at the first of the line which means the size of the array. And there will be m integers. Note that, 1<n<20, 1<m<10000. Output: For each input output the sorted array(from small to big) with spaces between elements.
input:
3
3 1 3 2
5 1 2 3 4 5
4 99 100 22 33

output:
1 2 3
1 2 3 4 5
22 33 99 100

Also Notice that the output of the flowing program is not correct at all, please correct it

link: bubble sort insertion sort selection sort

Program 1 Bubble sort

#include <stdio.h>

int main() {
int num[10000];
int n;
int i, j, temp;
int m, k, p, q, o;
int result[2000];

scanf("%d", &n);

for(i = 0; i < n; i++) {
scanf("%d", &num[i]);
}

for(i = 0; i <= n; i++) {
for(j = 0; i + j < n; j++) {
  if(num[j] > num[j + 1]) {
temp = num[j];
num[j + 1] = num[j];
num[j] = temp;
  }
}
}

for(i = 0; i < n - 1; i++) {
printf("%d ", num[i]);
}
printf("%d\n", num[i]);

return 0;
}

Program 2 Insertion sort

#include <stdio.h>

int main() {
  int num[10000];
  int n;
  int i, j, temp;
  scanf("%d", &n);
  for(i = 0; i < n; i++) {
  scanf("%d", &num[i]);}
  for(i=1; i<n; i++){
  temp = num[i];
  for(j=i-1; j>-1&&num[j]>temp;j--) {
  num[i]=num[j]; num[j]=temp;}}
  for(i = 0; i < n - 1; i++) {
  printf("%d ", num[i]);}
  printf("%d\n", num[i]);
  return 0;
}

Program 3 Selection sort

#include <stdio.h>

int main() {
  int num[10000];
  int n;
  int i, j, temp;
  scanf("%d", &n);
  for(i = 0; i < n; i++)
    scanf("%d", &num[i]);
  for(i=0; i < n; i++){
    min = num[i];
    for(j = i; j < n; j++) {
      if(min>num[j]) {
    temp = num[j];
    num[j] = min;
    min = temp;
    } for(i = 0; i < n - 1; i++) {
    printf("%d ", num[i]);}
  printf("%d\n", num[i]);
  return 0;
}

Discussion,Cooperation and Summary (15pts)

In this part, you will have some options, if you do more options, you will learn more and get more marks. You should note this part in your report

option 1: Github Discussion

Comment at the issue which is opened for dicuss for week7 and decribe a problem that you meet and how you solve detailedly.

Notice that

  1. you should not copy and paste your personal report simply.
  2. you should not write a very simple one and your comment will be deleted if you do that.
  3. you should not post meaningless questions.

option 2: Simple Presentation

Have a simple presentation in the lab class on Monday (4 persons limited). And after the presentation, everyone is encouraged to ask questions and you can get bonus by asking good questions.

Notice that

  1. The presentation is no more than 5 minutes and there will be 5 extra minutes for discussion.
  2. You should prepare much for it.
  3. First come, first get the opportunity.

option 3: Helping others

You can help others to slove any problems the will meet. Detailedly decribe the quesion, the solution and your personal experience as well.

Notice that

  1. it's no need to consult with others that I help you, you help you to get marks. You can simply send email to me and I will give you the marks.

option 4: Personal Summary

Write personal summary for yourself. List the problems that you have met in your learning in c language this week and decribe the solution as well.

Notice that

  1. you should not have very simple problems, you must let me know your learning method and also the method to solve problems.

Report:

Contents: 1、Assignment‘s Questions exclude the source code for the three programs. 2、Discussion, Cooperation and Summary Part.

Submit

screenshot

作业发给学委,不要发压缩包,注意文件命名必须完全一致,否则机器测试无法进行,0分处理。

Deadline:

18:00 Nov 19th

Note that homework after deadline will not be accepted this time whatever your reasons. 本次作业不接受缓交。

ghostbody commented 8 years ago

Extra作业:

1、 期中考试没有全部Accepted的同学,请将没有ac的题目重新做完,自行测试好。 2、没有全部ac的同学,每位同学,请自行到github这个地址进行comment,总结自己问题: link

Submit:

1、没做完的题目的源代码,以pid.c命名,即1000.c等放在自己学好的文件夹。 image

2、发给学习委员,统一整理后发给我

Deadline:

2015年11月22日晚9点

不接受缓交

langzi989 commented 8 years ago

程序员必学调试技巧

在写程序开发的过程中,不可避免的会出现很多bug,bug的类型也多种多样,可能是逻辑错误,也可能是内存泄露,这个时候我们就需要通过调试跟踪变量的值或者其他信息,来找出错误的位置,再进行修改,现在介绍两种常用的调试方法,断点调试以及输出调试,后面有一个内存泄露的检测小工具,有兴趣的同学可以自学一下。

一、断点调试及单步调试(推荐)

以devC++为例,其他编译器用法类似 事例程序:

#include <iostream>
#include <algorithm>
#include <string>
using namespace std;

int getRanking(string s1, string s2) {
    int rank = 0;
    for (int i = 0; i < s1.length(); i++) {
       for (int j = 0; j < s2.find(s1[i]); j++) {
           if (s1.find(s2[j]) > i) {
               rank++;
           }
       } 
    }
    return rank;
}

int getMedianRanking(string s1, string* s, int n) {
    int total = 0;
    for (int i = 0; i < n; i++) {
        total += getRanking(s1, s[i]);
        //cout << s1 << endl << s[i] << endl;
        //cout << getRanking(s1, s[i]) << endl;
    }
    return total;
}
int main() {
    int n;
    string s[100];
    string result = "ABCDE", target;
    while (cin >> n && n != 0) {
        for (int i = 0; i < n; i++)
            cin >> s[i];
        int min = 10000000;
        target = result;
        int temp = getMedianRanking(result, s, n);
        min = temp < min ? temp : min;
        while (next_permutation(result.begin(), result.end())) {
             temp = getMedianRanking(result, s, n);
             if (temp < min) {
                 min = temp;
                 target = result;
             }
        }
        cout << target << " is the median ranking with value " << min << '.' << endl;
    }
} 
/*样例输入
4
ABDCE
BACDE
ABCED
ACBDE
*/                                                          

第一 设置断点,进行调试

在你想要程序停止的位置所在的行,在行的前面设置一个断点,此时调试程序执行到这一步直接停止,此步不执行,在 1 开始调试 2

第二 学会使用工具栏,进入下一个断点或者单步调试

3 监视变量值以及当前状态 4 点击后出现下列对话框,输入要监视变量的名字 5 然后进行单步调试,观察左上角变量值的变化 开始查找错误

二、输出调试

狂printf("blablablablablablablablablablablablabla");

三、C程序内存监视工具MemLeak(有兴趣的同学自学)

下载得到的 memleak 压缩包大小不到 15 kB,解压后只有两个文件:memleak.c 和 memleak.h。在使用过程中只需要包含头文件 memleak.h 就可以使用 memleak 提供的几个易用而有效的内存检测函数了。

memleak 的原理是利用 C 语言的宏调用来替代原有的函数调用,比如我们在代码中调用 malloc(s),实际是调用了:dbg_malloc(s),这个宏定义在 memleak.h 中给出:

#define malloc(s) (FILE_LINE, dbg_malloc(s))

memleak 维护了一个链表,在这个链表中保存着程序中对内存函数调用的记录,这些函数包括:malloc、calloc、realloc、free。每次调用这些函数时,就会更新这个链表。 有了这个表,我们就可以在适当的位置调用 memleak 提供的函数,显示一些重要的信息,包括 malloc、calloc、realloc、free调用的次数,申请及分配的内存数,调用的文件和位置等等,信息非常详细。有了这些功能,我们就很容易定位内存使用的错误源。

由于 memleak 在某些交叉编译器下不能正常编译通过,这里我将 memleak.c 中的结构体 struct head 修改如下:

struct head
{
struct head *addr;
size_t size;
char *file;
unsigned line;
/* two addresses took the same space as an address and an integer on many archs => usable */
union lf {
struct { struct head*prev, *next; } list;
struct { char *file; unsigned line; } free;
} u;
};

memleak.c 文件中其它调用到 head 中共用体 u 的地方也要做相应的修改。 修改后的文件可以点击这里下载。

memleak 提供了以下几个函数接口:

extern void dbg_init(int history_length);
extern int dbg_check_addr(char *msg, void *ptr, int opt);
extern void dbg_mem_stat(void);
extern void dbg_zero_stat(void);
extern void dbg_abort(char *msg);
extern void dbg_heap_dump(char *keyword);
extern void dbg_history_dump(char *keyword);
extern void dbg_catch_sigsegv(void);

详细的介绍请查看 memleak.c 头部的注释或查看源代码理解。

下面举个简单的例子:

#include 
#include 
#include "memleak.h"
int main(void)
{
char * s, * t;
dbg_init(10);
s = (char *)malloc(100);    // 申请 100 bytes
t = (char *)malloc(11);     // 再申请 11 bytes
free(s);                    // 释放 100 bytes
s = (char *)malloc(80);     // 重新申请 80 bytes
dbg_heap_dump("");          // 显示调用栈
dbg_mem_stat();             // 显示调用统计
free(t);                    // 释放 11 bytes
free(s);                    // 释放 80 bytes
dbg_mem_stat();             // 再次显示调用统计
return 0;
}

编辑后保存为 test.c,与 memleak.c 和 memleak.h 放于同一目录下。 然后编写一 Makefile:

CC = gcc
EXEC = test
CSRC = test.c memleak.c
OBJS = $(patsubst %.c,%.o, $(CSRC))
all: $(EXEC)
$(EXEC): $(OBJS)
$(CC) $(OBJS) $(LDFLAGS) $(LDLIBS) -o $@
$(OBJS): %.o : %.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
-rm -f $(EXEC) *.elf *.gdb *.o
也保存于同一目录,在该目录下 make 编译,执行 ./test 后输出如下:
***** test.c:14: heap dump start
(alloc: test.c:11 size: 11)
(alloc: test.c:13 size: 80)
***** test.c:14: heap dump end
test.c:15: m: 3, c: 0, r: 0, f: 1, mem: 91
test.c:18: m: 3, c: 0, r: 0, f: 3, mem: 0

怎么样,很简单吧?

memleak 中还有一个函数 dbg_catch_sigsegv(void),可以绑定系统出现 SIGSEGV 信号时的处理函数,我们可以通过修改 memleak.c 中的 sigsegv_handler,自定义这个 SIGSEGV 信号处理函数。不知道 uClinux 下的 SIGSEGV 信号是否也存在,有的话调试一些内存问题就更容易了。