首页 > 其他分享 >【C语言有这个就够了】七.实用调试技巧

【C语言有这个就够了】七.实用调试技巧

时间:2022-10-16 17:31:47浏览次数:53  
标签:return int 就够 C语言 char dest arr1 my 调试

(一)什么是BUG

历史上第一个bug

【C语言有这个就够了】七.实用调试技巧_调试

导致程序运行错误的对象

(二)调试是什么

调试就是破案的过程,因为有人写代码是这样的:

【C语言有这个就够了】七.实用调试技巧_调试_02

1.调试

又称除错,是发现和减少计算机程序或电子仪器设备中程序错误的一个过程。


2.调试的基本步骤

  • 发现错误的存在
  • 以隔离,消除等方式对错误进行定位
  • 确定错误的产生原因
  • 提出纠正错误的解决办法
  • 对程序错误予以改正,重新测试

3.debug和release的介绍

debug称为调试版本,它包含调试信息,且不做任何优化,便于存程序员调试程序

【C语言有这个就够了】七.实用调试技巧_优秀代码_03

release称为发布版本,它往往是进行了各种优化,使程序在代码大小和运行速度上都是最优的,以便用户使用

【C语言有这个就够了】七.实用调试技巧_解决bug_04

我们可以看到,同一个代码,在不同版本下,内存大小不同。

同样对于这个代码:

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

【C语言有这个就够了】七.实用调试技巧_调试_05

【C语言有这个就够了】七.实用调试技巧_解决bug_06

如果是 debug 模式去编译,程序的结果是死循环;

如果是 release 模式去编译,程序没有死循环;

这样看来,release的确会优化。

(三) Windows环境调试介绍

1.准备

选择debug模式

2.快捷键

2.1 F5

启动调试,经常用来直接跳到下一个断点处。

注:F5通常与F9配合使用(在代码错误处用F9设置断点,用F5直接跳到断点处)

2.2 F9

创建断点和取消断点(代码执行到断点处停下来)

断点的重要作用,可以在程序的任意位置设置断点。

这样就可以使得程序在想要的位置随意停止执行,继而一步步执行下去。


2.3 F10

逐过程,通常用来处理一个过程,一个过程可以是一次函数调用,或者是一条语句。


2.4 F11

逐语句,就是每次都执行一条语句,但是这个快捷键可以使我们的执行逻辑进入函数内部(这是最常用的)

3.调试的时候查看程序当前信息

【C语言有这个就够了】七.实用调试技巧_解决bug_07

合理运用,可以更快找出bug。

(四) 一些调试的实例

1.实现代码:求 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;
}

【C语言有这个就够了】七.实用调试技巧_优秀代码_08

我们发现i=3时,ret为12,结果错误;

仔细分析,发现ret未初始化;

在​​ int j=0;​​​前增加​​ret=1;​

2.研究程序死循环的原因

#include <stdio.h>
int main()
{
int i = 0;
int arr[10]={1,2,3,4,5,6,7,8,9,10};
for (i = 0; i <= 12; i++)
{
arr[i] = 0;
printf("gaga\n");
}
return 0;
}

1.栈区的默认使用规则:

先使用高地址处的空间

再使用低地址处的空间

2.数组随着下标的增长,地址由低到高变化

【C语言有这个就够了】七.实用调试技巧_优秀代码_09

3.过程中数组越界可能可能遇到i,在越界改变时可能把i变为0,导致程序死循环

【C语言有这个就够了】七.实用调试技巧_优秀代码_10

(五)如何写出好代码

1.优秀的代码

代码运行正常

 bug很少

 效率高

 可读性高

 可维护性高

 注释清晰

 文档齐全

2.技巧

使用assert

尽量使用const

养成良好的编码风格

添加必要的注释

避免编码的陷阱

3.案例模拟实现strcpy

#include<stdio.h>
int main()
{
char arr1[] = "#########";
char arr2[] = "ajfhk";
strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}

【C语言有这个就够了】七.实用调试技巧_调试_11

那为什么没有打印后面的#######?

通过调试发现:

【C语言有这个就够了】七.实用调试技巧_优秀代码_12

拷贝了一个\0过去,打印时遇到\0停止

自己的strcpy

5分

#include<stdio.h>
void my_strcpy(char* dest, char* src)
{
while (*src != '\0')
{
*dest = *src;
src++;
dest++;
}
*dest = *src;//'0'
}
int main()
{
char arr1[] = "#########";
char arr2[] = "ajfhk";
my_strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}


6分

#include<stdio.h>
void my_strcpy(char* dest, char* src)
{
while (*dest++ = *src++)
{
;
}
}

int main()
{
char arr1[] = "#########";
char arr2[] = "ajfhk";
my_strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}


7分

#include<stdio.h>

void my_strcpy(char* dest, char* src)
{
if (dest != NULL && src != NULL)
{
while (*dest++ = *src++)
{
;
}
}
}

int main()
{
char arr1[] = "#########";
char arr2[] = "ajfhk";
my_strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}

防止输入为NULL的时候,整个程序崩盘;但这种更改方式也没有进行拷贝,而且没提示;


8分

#include<stdio.h>
#include<assert.h>
void my_strcpy(char* dest, char* src)
{
assert(dest != NULL);//断言
assert(src != NULL);
while (*dest++ = *src++)
{
;
}
}

int main()
{
char arr1[] = "#########";
char arr2[] = "ajfhk";
my_strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}

通过assert判断,并且及时报错

但是,当程序员写反时*src++=*dest++,依然有可能运行成功(只要arr1<arr2)

#include<stdio.h>
#include<assert.h>
void my_strcpy(char* dest, char* src)
{
assert(dest != NULL);
assert(src != NULL);
while (*src++=*dest++)
{
;
}
}

int main()
{
char arr1[] = "#####";
char arr2[] = "ajfhk";
my_strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}

【C语言有这个就够了】七.实用调试技巧_解决bug_13

9分

#include<stdio.h>
#include<assert.h>
void my_strcpy(char* dest, const char* src)//加上const,反了会报错。
{
assert(dest != NULL);
assert(src != NULL);
while (*dest++ = *src++)
{
;
}
}

int main()
{
char arr1[] = "#####";
char arr2[] = "ajfhk";
my_strcpy(arr1, arr2);
printf("%s\n", arr1);
return 0;
}

const使变量不能改变,注意

#include<stdio.h>
int main()
{
const int num = 10;
int* p = &num;
*p = 20;
printf("%d\n", num);
return 0;
}

这里p改变了一个我们主观上不想改变的值,

#include<stdio.h>
int main()
{
const int num = 10;
int n=100;
const int* p = &num;//即使写错了,也能报错
//const放在*左边时,修饰*p,也就是说:不能通过p来改变*p(num)的值
*p = 20;
printf("%d\n", num);
return 0;
}
#include<stdio.h>
int main()
{
const int num = 10;
int*const p = &num;
//const放在*右边时,修饰p,也就是说:不能改变p的值
*p = 20;
int n=10;
p=&n;
printf("%d\n", num);
return 0;
}


10分

#include<stdio.h>
#include<assert.h>
char*my_strcpy(char* dest, const char* src)//加上const,反了会报错。
{
char*ret=dest;
assert(dest != NULL);
assert(src != NULL);
while (*dest++ = *src++)//把src指向的字符串拷贝到dest指向的字符串,包含'\0'
{
;
}
return ret;
}

int main()
{
char arr1[] = "#####";
char arr2[] = "ajfhk";
printf("%s\n",my_strcpy(arr1, arr2));//返回值时另一个函数的参数
return 0;
}

4.案例模拟实现strlen

#include<stdio.h>
#include<assert.h>

int my_strlen(const char* str)//*str指向的内容不会被改变,但是指针的位置可以改变
{
int count = 0;
assert(str != NULL);
while (* str != '\0')
{
count++;
str++;
}
return count;
}

int main()
{
char arr[] = "abcdef";
int len = my_strlen(arr);
printf("%d\n", len);
return 0;
}

​(七)编程常见的错误

1.编译型错误

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

2.链接型错误

看错误提示信息,主要在代码中找到错误信息中的标识符,然后定位问题所在。一般是标识符名不

存在或者拼写错误。

3.运行时错误

借助调试,逐步定位问题,最难搞。



标签:return,int,就够,C语言,char,dest,arr1,my,调试
From: https://blog.51cto.com/u_15796276/5760462

相关文章

  • C语言循环
    #include<stdio.h>intmain(){int i=0;printf("去卖烤红薯\n");while(i<200){printf("卖出的烤红薯:%d\n",i);  i++;}if(i>=200)printf("成为千万富翁\n");  retu......
  • 用C语言实现两个值交换的四种方法
    一.题中已给两个值的数值二.随意输出两个整数(变量)的数值为避免麻烦,我在这里统一用变量(就是第二种)来敲一遍,希望可以给各位解决些麻烦,仅供参考,希望指正。另外,下面的代码我用了......
  • C语言的学习——零基础学习(1)
    C语言是一门计算机语言计算机语言指的是人与计算机交流的语言。学习C语言时,我所用的编程软件是微软的VisualStudio通过VS进行编写人生中的第一个程序,这个程序就是所有课本中......
  • C语言基础学习1
    //day1!!!!!#define_CRT_SECURE_NO_WARNINGS1#include<stdio.h>//意思是包含stdio.h里面的头文件包含输入输出里面的函数intmain(){printf("hellowwold.\n");//pri......
  • C语言笔记
    Part41.程序语言的功能是:数据表达与数据处理。     数据表达就是变量定义,对数据进行定义。例如:inta,就是对a这个变量进行整型的定义。     数据处理就......
  • 实验一 C语言开发环境使用和编程初体验
    //实验一#include<stdio.h>intmain(){printf("OO\n");printf("<H><H>\n");printf("IIII\n");return0;}//task1_1.c#include<......
  • 【leetcode_C语言_数组_day2】977.有序数组的平方&&209.长度最小的子数组&&59. 螺旋矩
    977.有序数组的平方1.题目给你一个按非递减顺序排序的整数数组nums,返回每个数字的平方组成的新数组,要求也按非递减顺序排序。示例1:输入:nums=[-4,-1,0,3,10]......
  • keil 常用调试方法
    1、内存调试方法,参考链接:    https://blog.51cto.com/u_4029519/5423341 2、汇编调试方法   常用到bootlader和应用程序的调试   1、fromelf ......
  • C语言之字符串与字符数组的区别
     1.字符串的定义:(1)单个字符:charch='i';//单个字符的定义(2)一维字符串数组:chararr[]="love";(这种方法定义的一维字符串数组必须赋值)chararr[4];(想内存申请创建可以......
  • 前后端分离接口规范 ,看这一份就够了 !
    随着互联网的高速发展,前端页面的展示、交互体验越来越灵活、炫丽,响应体验也要求越来越高。后端服务的高并发、高可用、高性能、高扩展等特性的要求也愈加苛刻,从而导致前后端......