0
点赞
收藏
分享

微信扫一扫

7月22 -- 调试

查看临时变量的值

在调试开始之后,用于观察变量的值。

查看内存信息

在调试开始之后,用于观察内存信息。

查看调用堆栈

通过调用堆栈,可以清晰的反应函数的调用关系以及当前调用所处的位置

查看汇编信息

在调试开始之后,有两种方式转到汇编:

(1)第一种方式:右击鼠标,选择【转到反汇编】:

(2)第二种方式:可以切换到汇编代码。

查看寄存器信息

可以查看当前运行环境的寄存器的使用信息。

多多动手,尝试调试,才能有进步。

一定要熟练掌握调试技巧。 初学者可能80%的时间在写代码,20%的时间在调试。但是一个程序员可能20%的时间在写 程序,但是80%的时间在调试。 我们所讲的都是一些简单的调试。 以后可能会出现很复杂调试场景:多线程程序的调试等。 多多使用快捷键,提升效率。

实现代码:求 1!+2!+3! ...+ n! ;不考虑溢出。

int main()
{
	int i = 0;
	int sum = 0;//保存最终结果
	int n = 0;
	int ret = 1;//保存n的阶乘
	scanf("%d", &n);
	for (i = 1; i <= n; i++)
	{
		int j = 0;
		for (j = 1; j <= i; j++)
		{
			ret *= j;
		}
		sum += ret;
	}
	printf("%d\n", sum);
	return 0;
}

这时候我们如果3,期待输出9,但实际输出的是15。

why? 这里我们就得找我们问题。

  1. 首先推测问题出现的原因。初步确定问题可能的原因最好。
  2. 实际上手调试很有必要。
  3. 调试的时候我们心里有数


#include <stdio.h>
int main()
{
    int i = 0;
    int arr[10] = { 0 };
    for (i = 0; i <= 12; i++)
    {
        arr[i] = 0;
        printf("hehe\n");
    }
    return 0;
}

研究程序死循环的原因。


优秀的代码:

  1. 代码运行正常
  2. bug很少
  3. 效率高
  4. 可读性高
  5. 可维护性高
  6. 注释清晰
  7. 文档齐全 常见的coding技巧:
  8. 使用assert
  9. 尽量使用const
  10. 养成良好的编码风格
  11. 添加必要的注释
  12. 避免编码的陷阱。



模拟实现库函数:strcpy

/***
*char *strcpy(dst, src) - copy one string over another
*
*Purpose:
*       Copies the string src into the spot specified by
*       dest; assumes enough room.
*
*Entry:
*       char * dst - string over which "src" is to be copied
*       const char * src - string to be copied over "dst"
*
*Exit:
*       The address of "dst"
*
*Exceptions:
*******************************************************************************/
char* strcpy(char* dst, const char* src)
{
    char* cp = dst;
    assert(dst && src);

    while (*cp++ = *src++)
        ;     /* Copy src over dst */
    return(dst);
}

注意:

  1. 分析参数的设计(命名,类型),返回值类型的设计
  2. 这里讲解野指针,空指针的危害。
  3. assert的使用,这里介绍assert的作用
  4. 参数部分 const 的使用,这里讲解const修饰指针的作用


const的作用

#include <stdio.h>
//代码1
void test1()
{
    int n = 10;
    int m = 20;
    int *p = &n;
    *p = 20;//ok?
    p = &m; //ok?
}
void test2()
{
     //代码2
    int n = 10;
    int m = 20;
    const int* p = &n;
    *p = 20;//ok?
    p = &m; //ok?
}
void test3()
{
    int n = 10;
    int m = 20;
    int *const p = &n;
    *p = 20; //ok?
    p = &m;  //ok?
}
int main()
{
    //测试无cosnt的
   test1();
    //测试const放在*的左边
    test2();
    //测试const放在*的右边
    test3();
    return 0;
}


结论:

const修饰指针变量的时候:

1. const如果放在的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改 变。但是指针变量本身的内容可变。 2. const如果放在的右边,修饰的是指针变量本身,保证了指针变量的内容不能修改,但是指

针指向的内容,可以通过指针改变。

模拟实现一个strlen函数

#include <stdio.h>
int my_strlen(const char *str)
{
    int count = 0;
    assert(str != NULL);
    while(*str)//判断字符串是否结束
   {
        count++;
        str++;
   }
    return count;
}
int main()
{
    const char* p = "abcdef";
    //测试
    int len = my_strlen(p);
    printf("len = %d\n", len);
    return 0;
}

编程常见的错误

1 编译型错误 直接看错误提示信息(双击),解决问题。或者凭借经验就可以搞定。相对来说简单。

2 链接型错误 看错误提示信息,主要在代码中找到错误信息中的标识符,然后定位问题所在。一般是标识符名不 存在或者拼写错误。

3 运行时错误 借助调试,逐步定位问题。最难搞。 温馨提示: 做一个有心人,积累排错经验。


举报

相关推荐

0 条评论