实用调试技巧 Debug Release F10 F11 初始化 越界访问 堆栈 模拟实现库函数
目录
- 一、什么是bug
- 二、调试是什么?有多重要?
- 1、调试
- 2、调试的基本步骤
- 三、Debug和Release
- 四、windows环境调试介绍
- 1、调试环境的准备
- 2、学会快捷键
- Ctrl+U 改大小 Ctrl+Shift+U
- F5 启动调试
- F9 启用/关闭断点
- F10 逐过程
- F11 逐语句
- CTRL + F5 开始执行(不调试)
- 其他快捷键
- 3、调试的时候查看程序当前信息
- 3.1、查看临时变量的值
- 3.2、查看内存信息
- 3.3、查看调用堆栈
- 3.4、查看汇编信息
- 3.4、查看寄存器信息
- 五、一些调试的实例
- 1、求 1!+2!+3! ...+ n! 不考虑溢出。
- 2、越界访问
- NICE 笔试题
- 3、Debug版本对比
- 六、编程常见的错误
- 常见的错误分类:
- 1、编译型错误
- 2、链接型错误
- 3、运行时错误
- 七、如何写出好(易于调试)的代码。
- 一、模拟实现库函数:strcpy
- 1、strcpy
- 2、my_strcpy
- 1
- 2优化 后置++
- 3优化
- 4优化 判断空指针
- const
- 用法
- const修饰指针 *左右
- 5优化 const
- 6优化 返回类型
- 数组的错误情况
- 打印字符串 解引用打印一个字符
- 常量字符串首字符地址存放在指针
- 二、模拟实现strlen函数
- strlen返回类型是无符号数
- 八、练习
- 1、前置 / 后置++
- 2、统计二进制中1的个数
- 2.1、用&1和>>方法
- 2.2、用%2方法
- 2.3、用n-1&
- 3、写一个代码,判断一个数是不是2的次方数
- 4、统计二进制中1的个数
- 5、求两个数二进制中不同位的个数
- 循环
- 函数
- 对应的二进制位^ 同为0异为1
- 6、打印整数二进制的奇数位和偶数位
- 7、判断是元音还是辅音
- 循环判断
- 字符数组判断
- 8、矩阵相等判断
- 优化 读一个判断一个
- 9、矩阵转置
- short解引用
- 10、VS小端存储
- 11、sizeof返回
- 12、使用指针打印数组内容
- 12、计算求和
- 13、求a的n项
- 14、打印水仙花数
- 判断i是否是自幂数
- 求位数函数
一、什么是bug
第一次被发现的导致计算机错误的飞蛾,也是第一个计算机程序错误。
指代计算机上存在的漏洞 软件缺陷
二、调试是什么?有多重要?
所有发生的事情都一定有迹可循,如果问心无愧,就不需要掩盖也就没有迹象了,如果问心有 愧,就必然需要掩盖,那就一定会有迹象,迹象越多就越容易顺藤而上,这就是推理的途径。顺 着这条途径顺流而下就是犯罪,逆流而上,就是真相。
1、调试
调试
(英语:Debugging / Debug),又称除错,是发现和减少计算机程序或电子仪器设备中程 序错误的一个过程。
2、调试的基本步骤
- 发现程序错误的存在
- 程序员
- 测试人员 --> 发布
- 用户
- 以隔离、消除等方式对错误进行定位
- 确定错误产生的原因
- 提出纠正错误的解决方法
- 对程序错误予以改正,重新测试
三、Debug和Release
Debug - 调试版本 - 可以调试
Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。
Release - 发布版本 - 用户使用的,不能调试
Release 称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优 的,以便用户很好地使用。
四、windows环境调试介绍
1、调试环境的准备
在环境中选择 debug 选项,才能使代码正常调试
2、学会快捷键
Ctrl+U 改大小 Ctrl+Shift+U
VS改大小写的快捷键
改成小写:Ctrl+U
改成大写:Ctrl+Shift+U
记得要选中要修改的一段英文。
F5 启动调试
启动调试,经常用来直接跳到断点处,
在执行流程中的断点,想要跳到下一个断点,取消当前循环的断点,F5跳到下一个循环的断点处。
F9 启用/关闭断点
创建断点和取消断点 (F5要和F9配合使用 )
断点的重要作用,可以在程序的任意位置设置断点。
这样就可以使得程序在 想要的位置随意停止执行,继而一步步执行下去。
点住断点 右击 条件断点 可以设置条件 不用一一循环
F10 逐过程
逐过程,通常用来处理一个过程,一个过程可以是一次函数调用,或者是一条语句。
F11 逐语句
逐语句,就是每次都执行一条语句,但是这个快捷键可以使我们的执行逻辑进入函数内部(这是 最常用的)。
CTRL + F5 开始执行(不调试)
开始执行不调试,如果你想让程序直接运行起来而不调试就可以直接使用。
#include <stdio.h>void test() //F11 进入函数内部
{printf("hehe\n");
}int main()
{int arr[10] = {0};int i = 0;test(); //F11for(i=0; i<10; i++){scanf("%d", arr[i]);}for(i=0; i<10; i++){printf("%d ", arr[i]);}return 0;
}
其他快捷键
Ctrl+F5:查找
Ctrl+H: 替换
Ctrl G:转到行
Ctrl+K C: 注释选定内容
Ctrl+K U: 取消选定注释内容
END选择至行尾
HOME选择至行开始处
3、调试的时候查看程序当前信息
3.1、查看临时变量的值
监视 delete删除
#include <stdio.h>void test() //F11 进入函数内部
{printf("hehe\n");
}int main()
{int arr[10] = {0};int i = 0;test(); //F11for(i=0; i<10; i++){scanf("%d", arr[i]);}for(i=0; i<10; i++){printf("%d ", arr[i]);}return 0;
}
3.2、查看内存信息
3.3、查看调用堆栈
通过调用堆栈,可以清晰的反应函数的调用关系以及当前调用所处的位置。
#include <stdio.h>void test2()
{printf("test2\n");
}void test1()
{test2();
}void test()
{test1();
}int main()
{test();return 0;
}
3.4、查看汇编信息
在调试开始之后,有两种方式转到汇编:
(1)第一种方式:右击鼠标,选择【转到反汇编】:
(2)第二种方式:调试 窗口 反汇编
3.4、查看寄存器信息
可以查看当前运行环境的寄存器的使用信息。
五、一些调试的实例
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;
}
这时候我们如果3,期待输出9,但实际输出的是15。
通过调试发现是ret没有初始化
初始化后:
int main()
{int i = 0;int sum = 0;//保存最终结果int n = 0;scanf("%d", &n);for (i = 1; i <= n; i++){int ret = 1;//保存n的阶乘int j = 0;for (j = 1; j <= i; j++){ret *= j;}sum += ret;}printf("%d\n", sum);return 0;
}
2、越界访问
#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;
}
越界访问,有可能访问到i,死循环
i<=10时报错,因为一直在循环,没有时间报错
NICE 笔试题
3、Debug版本对比
int main()
{int i = 0;int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };printf("%p\n", &i);printf("%p\n", &arr[0]);printf("%p\n", &arr[9]);return 0;
}
Debug
此时,i 的地址比数组最后一个元素还大,说明如果越界访问,有可能虎访问到i,导致错误。
–
Release版本
没有报错,打印了 个hehe,没有死循环,
Release数组的地址比 i 的地址大,
因为进行了优化,把i放在arr之后,
《C陷阱与缺陷》
六、编程常见的错误
常见的错误分类:
1、编译型错误
直接看错误提示信息(双击),解决问题。或者凭借经验就可以搞定。相对来说简单。
2、链接型错误
看错误提示信息,主要在代码中找到错误信息中的标识符,然后定位问题所在。一般是标识符名 不存在或者拼写错误。
3、运行时错误
借助调试,逐步定位问题。最难搞。
–
七、如何写出好(易于调试)的代码。
优秀的代码:
- 代码运行正常
- bug很少
- 效率高
- 可读性高
- 可维护性高
- 注释清晰
- 文档齐全
常见的coding技巧:
- 使用assert
- 尽量使用const
- 养成良好的编码风格
- 添加必要的注释
- 避免编码的陷阱
一、模拟实现库函数:strcpy
Null - \0
null - \0
NULL - 空指针
1、strcpy
#include <stdio.h>
#include <string.h>int main()
{//strcpy - string copy - 字符串拷贝char arr1[] = "abcdef";char arr2[10] = { 0 };strcpy(arr2, arr1); //arr2目标数组 printf("%s\n", arr2);return 0;
}
2、my_strcpy
1
//dest 是指向目标空间的
//src 是指向原字符串的
void my_strcpy(char* dest, char* src)//目标 源头
{while (*src != '\0') // \0=0 当指向\0时停止{*dest = *src;dest++;src++;}*dest = *src; //strcpy把\0一起拷贝 出循环指向的是\0 拷贝\0
}int main()
{//strcpy - string copy - 字符串拷贝char arr1[] = "abcdef";char arr2[10] = { 0 };my_strcpy(arr2, arr1); //arr2目标数组 printf("%s\n", arr2);return 0;
}
2优化 后置++
void my_strcpy(char* dest, char* src)
{while (*src != '\0'){*dest++ = *src++; //后置++}*dest = *src; // \0
}
3优化
void my_strcpy(char* dest, char* src)
{//1. 拷贝字符//2. 遇到\0 循环停止while (*dest++ = *src++){;}
}
4优化 判断空指针
#include <assert.h>void my_strcpy(char* dest, char* src)
{/*if (src == NULL || dest == NULL){return;}*/assert(src != NULL); //断言 - release版本可以优化掉assert(dest != NULL);//assert发现问题会告诉我们/*assert(src);assert(dest);assert(src && dest);*/while (*dest++ = *src++){;}
}
const
用法
int main()
{const int num = 10; //num是常变量//num = 20; //errint* p = #*p = 20; //可以修改printf("%d\n", num);
}
const修饰指针 *左右
int main()
{const int num = 10;//const修饰指针//const 放在*的左边//修饰的是指针指向的内容(*p),指针指向的内容,不能通过指针来改变了//但是指针变量本身(p)是可以改变的int n = 100;const int* p = # //写法相同int const * p = #*p = 20;p = &n;printf("%d\n", num); //修饰的是p 此时p不能存放n的地址//const 放在*的右边//修饰的是指针变量本身(p),指针变量本身(p)不能修改了//指针指向的内容(*p)可以修改,int n = 100;int * const p = # //修饰的是*p 指针所指向的对象 *p = 20;p = &n;printf("%d\n", num);
}
5优化 const
健壮性/鲁棒性 - 抗风险
#include <assert.h>void my_strcpy(char* dest, const char* src) //修饰*src 保护src不被修改
{assert(src != NULL);assert(dest != NULL);while (*src++ = *dest++) //如果写反{;}
}
6优化 返回类型
#include <assert.h>char* my_strcpy(char* dest, const char* src)
{assert(src != NULL);assert(dest != NULL);char* ret = dest; //先存起来 下面已经指向src对应得\0的位置 不是起始位置while (*dest++ = *src++){;}return ret; //返回目标起始位置
}int main()
{char arr1[] = "abcdef";char arr2[10] = "xxxxxxxxxx";char* ret = my_strcpy(arr2, arr1); //arr2目标数组 printf("%s\n", ret); //只打印abcdef 没有打印后面的xxxx是因为字符串的结束标志是\0return 0;
}
数组的错误情况
int main()
{//1char arr1[] = "abcdef"; //[a b c d e f \0]char arr2[] = "xxxxxxxxx";//2 - 原字符串中一定要有\0char arr1[] = { 'a', 'b', 'c' };char arr2[10] = "xxxxxxxxx";//3 - 目标空间一定要足够大char arr1[] = "abcdef";char arr2[3] = { 0 };//4 - 目标空间必须可修改char arr1[] = "abcdef";const char* arr2 = "xxxxxxxxxxxxxxx"; //指针指向的内容 不希望被修改时 加const 更严谨安全//arr2是指针 指向常量字符串,常量字符串是放在常量区,是不能修改的//不能拷贝,因为目标空间arr2不能被修改char* ret = my_strcpy(arr2, arr1);printf("%s\n", ret);return 0;
}
打印字符串 解引用打印一个字符
int main()
{char arr[] = "abcdef";const char* str = "kel";//打印字符串printf("%s\n", arr);printf("%s\n", str);//字符指针 解引用 只能访问一个字符 //arr访问的是a 打印的是字符%cprintf("%c\n", *arr); //aprintf("%c\n", *str); //kreturn 0;
}
常量字符串首字符地址存放在指针
int main()
{const char* str = "abcdef";//常量字符串abcdef在内存的常量区里 //把常量字符串首字符a的地址存放在str中printf("%s\n", str); //abcdefprintf("%c\n", *str); //areturn 0;
}
二、模拟实现strlen函数
#include <assert.h>//size_t - unsigned int 扩大范围
unsigned int my_strlen(const char* str)
{assert(str != NULL);int count = 0;while (*str){count++;str++;}return count;
}int main()
{char arr[] = "abcdef";int ret = my_strlen(arr);printf("%d", ret);return 0;
}
strlen返回类型是无符号数
int main()
{//3-6 = -3//10000000000000000000000000000011 - 原//11111111111111111111111111111100 - 反//11111111111111111111111111111101 - -3补码//在内存中被解析为无符号数 全都是有效位//补码即原码 是一个很大的正数if (strlen("abc") - strlen("abcdef") > 0){printf("hehe\n"); //hehe}else{printf("haha\n");}return 0;
}
八、练习
1、前置 / 后置++
#include <stdio.h>int main()
{int a, b, c;a = 5;c = ++a;b = ++c, c++, ++a, a++;b += a++ + c;printf("a = %d b = %d c = %d\n:", a, b, c);//a:9, b:23, c:8return 0;
}
2、统计二进制中1的个数
写一个函数返回参数二进制中 1 的个数。
比如: 15 0000 1111 4 个 1
2.1、用&1和>>方法
size_t count_bit_one(int n)
{int i = 0;int count = 0;for (i = 0; i < 32; i++) //i==31时 最高位来到最低位{//最低位和1按位与 如果是1按位与后结果就是1//00000000000000000000000000001111 - 15//00000000000000000000000000000001 - 1//00000000000000000000000000000001 - &1 最低位是1 结果就是1//按位与后>>if (((n >> i) & 1) == 1) //当i=0时 没有右移{count++;}}return count;
}int main()
{int num = 0;scanf("%d", &num);int ret = count_bit_one(num);printf("%d\n", ret);return 0;
}
2.2、用%2方法
十进制%10 /10可以得到每一位
123%10=3
12/10=12
12%10=2
//负数算不了 用无符号数
size_t count_bit_one(unsigned int n) //把负数当成无符号数求
{int count = 0;while (n){if (n % 2 == 1){count++;}n /= 2;}return count;
}int main()
{int num = 0;scanf("%d", &num);int ret = count_bit_one(num);printf("%d\n", ret);return 0;
}
2.3、用n-1&
size_t count_bit_one(int n)
{int count = 0;while (n){n = n & (n - 1);count++;}return count;
}int main()
{int num = 0;scanf("%d", &num);int ret = count_bit_one(num);printf("%d\n", ret);return 0;
}
3、写一个代码,判断一个数是不是2的次方数
2 – 0010
4 – 0100
8 – 1000
16 – 10000
int main()
{int n = 0;scanf("%d", &n);if ((n & (n - 1)) == 0){printf("YES\n");}else{printf("N0\n");}return 0;
}
IO型 - 自己写输入,输出
接口型 - 只要完成指定接口就可以了
4、统计二进制中1的个数
题目内容:
写一个函数返回参数二进制中 1 的个数。
比如: 15 0000 1111 4 个 1
//C++
class Solution {public:int NumberOf1(int n) {int count = 0;while (n){n = n & (n - 1);count++;}return count;}
};
5、求两个数二进制中不同位的个数
题目内容:
编程实现:两个int(32位)整数m和n的二进制表达中,有多少个位(bit)不同?
输入例子 :
1999 2299
输出例子 : 7
循环
int main()
{int n1 = 0;int n2 = 0;scanf("%d %d", &n1, &n2);int count = 0;int i = 0;for (i = 0; i < 32; i++){if (((n1 >> i) & 1) != ((n2 >> i) & 1)){count++;}}printf("%d\n", count);return 0;
}
函数
int count_diff_bit(int n1, int n2)
{int count = 0;int i = 0;for (i = 0; i < 32; i++){if (((n1 >> i) & 1) != ((n2 >> i) & 1)){count++;}}return count;
}int main()
{int n1 = 0;int n2 = 0;scanf("%d %d", &n1, &n2);int count = count_diff_bit(n1, n2);printf("%d\n", count);return 0;
}
对应的二进制位^ 同为0异为1
int NumberOf1(int n) //求一个数二进制有多少个1
{int count = 0;while (n){n = n & (n - 1);count++;}return count;
}int count_diff_bit(int n1, int n2)
{int count = 0;int t = n1 ^ n2;count = NumberOf1(t);return count;}int main()
{int n1 = 0;int n2 = 0;scanf("%d %d", &n1, &n2);int count = count_diff_bit(n1, n2);printf("%d\n", count);return 0;
}
6、打印整数二进制的奇数位和偶数位
题目内容:
获取一个整数二进制序列中所有的偶数位和奇数位,分别打印出二进制序列
/偶数位 1 3 5 7。。。31
奇数位 0 2 4 6 。。。30
倒着打印 所以从后开循环
int main()
{int num = 0;scanf("%d", &num);int i = 0;printf("偶数位:");for (i = 31; i >= 1; i -= 2){printf("%d ", (num >> i) & 1);}printf("\n奇数位:");for (i = 30; i >= 0; i -= 2){printf("%d ", (num >> i) & 1);}printf("\n");return 0;
}
7、判断是元音还是辅音
多组输入,每行输入一个字母。
输出描述:
针对每组输入,输出为一行,如果输入字母是元音(包括大小写),
输出“Vowel”,如果输入字母是非元音,输出“Consonant”。
循环判断
int main()
{int ch = 0;//循环判断部分其实是在读取字符while ((ch = getchar()) != EOF){//判断是否为元音字母if (ch == 'A' || ch == 'E' || ch == 'I' || ch == 'O' || ch == 'U' || ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u'){printf("Vowel\n");}else{printf("Consonant\n");}getchar(); //清理 \n}return 0;
}
字符数组判断
int main()
{int ch = 0;char vowel[] = "aeiouAEIOU";while ((ch = getchar()) != EOF){int i = 0;int flag = 0;for (i = 0; i < 10; i++){if (ch == vowel[i]){flag = 1;break;}}if (flag == 1){printf("Vowel\n");}else{printf("Consonant\n");}getchar(); //清理 \n}return 0;
}
//3.改大小写
//4.strstr
–
8、矩阵相等判断
第一行包含两个整数n和m,表示两个矩阵包含n行m列,用空格分隔。
从2到n + 1行,每行输入m个整数(范围 - 231~231 - 1),用空格分隔,共输入n * m个数,表示第一个矩阵中的元素。
从n + 2行到2n + 1,每行输入m个整数(范围 - 231~231 - 1),用空格分隔,共输入n * m个数,表示第二个矩阵中的元素。
1 < n, m < 10
输出描述:
一行,如果两个矩阵相等输出"Yes"并换行,否则输出"No"并换行。
int main()
{int arr1[10][10] = { 0 };int arr2[10][10] = { 0 };int n = 0;int m = 0;scanf("%d %d", &n, &m);int i = 0;int j = 0;//输入了矩阵1//n行for (i = 0; i < n; i++){//m列for (j = 0; j < m; j++){scanf("%d", &arr1[i][j]);}}//输入了矩阵2for (i = 0; i < n; i++){//m列for (j = 0; j < m; j++){scanf("%d", &arr2[i][j]);}}//判断int flag = 1; //默认相同for (i = 0; i < n; i++){for (j = 0; j < m; j++){if (arr1[i][j] != arr2[i][j]){flag = 0;break;}}}if (flag == 1){printf("Yes\n");}else{printf("No\n");}return 0;
}
优化 读一个判断一个
int main()
{int arr1[10][10] = { 0 };int arr2[10][10] = { 0 };int n = 0;int m = 0;scanf("%d %d", &n, &m);int i = 0;int j = 0;for (i = 0; i < n; i++){for (j = 0; j < m; j++){scanf("%d", &arr1[i][j]);}}int flag = 1; //默认相同for (i = 0; i < n; i++){for (j = 0; j < m; j++){scanf("%d", &arr2[i][j]);if (arr1[i][j] != arr2[i][j]){flag = 0;break;}}}if (flag == 1){printf("Yes\n");}else{printf("No\n");}return 0;
}
9、矩阵转置
第一行包含两个整数n和m,表示一个矩阵包含n行m列,用空格分隔。 (1≤n≤10,1≤m≤10)
从2到n+1行,每行输入m个整数(范围-231~231-1),用空格分隔,共输入n*m个数,表示第一个矩阵中的元素。
输出描述:
输出m行n列,为矩阵转置后的结果。每个数后面有一个空格。
int main()
{int n = 0;int m = 0;int arr[10][10] = { 0 };scanf("%d %d", &n, &m);int i = 0;int j = 0;//输入for (i = 0; i < n; i++){for (j = 0; j < m; j++){scanf("%d", &arr[i][j]);}}//转置输出for (i = 0; i < m; i++) //打印3行2列{for (j = 0; j < n; j++){printf("%d ", arr[j][i]);}printf("\n");}return 0;
}
short解引用
#include <stdio.h>int main()
{int arr[] = { 1,2,3,4,5 };short* p = (short*)arr;int i = 0;for (i = 0; i < 4; i++){*(p + i) = 0;}for (i = 0; i < 5; i++){printf("%d ", arr[i]);}return 0;
}
1 2 3 4 5
short 解引用每次访问2个字节
00 00 3 3 5
10、VS小端存储
#include <stdio.h>int main()
{int a = 0x11223344;char* pc = (char*)&a;*pc = 0;printf("%x\n", a);return 0;
}
低位放在低地址 高位放在高地址
// 44 33 22 11
// %d - 10进制
// %o - 8进制
// %x - 16进制
11、sizeof返回
#include <stdio.h>int i; //全局变量,没有给初始值时,编译其会默认将其初始化为0
int main()
{i--; // -1if (i > sizeof(i)){printf(">\n");}else{printf("<\n");}return 0;
}
sizeof - 返回的是无符号整数
i和sizeof(i)比较 算术转换 int强制类型转化为size_t
-1对应的无符号整形是一个非常大的数字
12、使用指针打印数组内容
写一个函数打印arr数组的内容,不使用数组下标,使用指针。
arr是一个整形一维数组
#include <assert.h>void print(const int* p, int sz)
{int i = 0;assert(p);for (i = 0; i < sz; i++){printf("%d ", *(p + i));}
}int main()
{int arr[] = { 1,2,3,4,5,6,7,8,9,10 };int sz = sizeof(arr) / sizeof(arr[0]);//数组在内存中是连续存放的 只要知道起始位置 就能找到数组print(arr, sz);return 0;
}
12、计算求和
求Sn=a+aa+aaa+aaaa+aaaaa的前5项之和,其中a是一个数字,
例如:2+22+222+2222+22222
int main()
{int i = 0;int a = 0;int tmp = 0;int Sn = 0;scanf("%d", &a);for (i = 0; i < 5; i++){tmp = tmp * 10 + a;Sn = Sn + tmp;}printf("%d\n", Sn);return 0;
}
13、求a的n项
int main()
{int a = 0;int n = 0;int i = 0;int sum = 0;int k = 0;scanf("%d %d", &a, &n);for (i = 0; i < n; i++){k = k * 10 + a;sum += k;}printf("%d\n", sum);return 0;
}
14、打印水仙花数
求出0~100000之间的所有“水仙花数”并输出。
“水仙花数”是指一个n位数,其各位数字的n次方之和确好等于该数本身,如:153=13+53+3^3,则153是一个“水仙花数”
判断i是否是自幂数
#include <math.h>int main()
{int i = 0;for (i = 0; i <= 100000; i++){ int tmp = i; //计算位数后i会改变 用tmp求//1. 计算i的位数 - nint cnt = 1;int sum = 0;while (tmp /= 10){cnt++;}//2. 计算i的每一位的n次方之后tmp = i;while (tmp){sum += (int)pow(tmp % 10, cnt);tmp /= 10;}//3. 判断if (sum == i){printf("%d ", i);}}return 0;
}
求位数函数
#include <math.h>int count(int tmp)
{int cnt = 1;while (tmp /= 10){cnt++;}return cnt;
}int main()
{int i = 0;for (i = 0; i <= 100000; i++){int tmp = i;//1. 计算i的位数 - nint sum = 0;int cnt = count(i);//2. 计算i的每一位的n次方之后while (tmp){sum += (int)pow(tmp % 10, cnt);tmp /= 10;}//3. 判断if (sum == i){printf("%d ", i);}}return 0;
}
实用调试技巧 Debug Release F10 F11 初始化 越界访问 堆栈 模拟实现库函数相关推荐
- C语言:实用调试技巧
目录 C语言:实用调试技巧 1.什么是bug? 2.调试是什么?有多重要? 3.debug和release的介绍 4.Windows环境调试介绍 5.一些调试的实例 6.如何写出好(易于调试)的代码 ...
- C语言第二十课:实用调试技巧
目录 前言: 一.Bug: 二.调试: 1.调试是什么: 2.调试的基本步骤: 3. Debug 与 Release : 三.在Windows环境下进行调试: 1.调试环境的准备: 2.调试的快捷键: ...
- C语言之实用调试技巧
什么是bug? 调试是什么?有多重要? debug和release的介绍. windows环境调试介绍. 一些调试的实例. 如何写出好(易于调试)的代码. 编程常见的错误. 一. 什么是bug? 第一 ...
- VS2017实用调试技巧
目录 历史上的第一个Bug,什么是bug 调试的重要性 现实中的你是会是这样子的吗? 调试的基本步骤 1.发现程序错误的存在 2.以隔离.消除等方式对错误进行定位 3.确定错误产生的原因 4.提出纠正 ...
- ACM/OI中C++常用优化(实用/调试/技巧)代码(语法)
一.C++万能编译头文件 #include<bits/stdc++.h> 从 #include <iostream> #include <cstdio> #incl ...
- C语言初阶——实用调试技巧
- 【C语言】实用调试技巧与const函数提升代码健壮性
作者简介:大家好我是狂暴于涛侠
- 实用调试的技巧,VS编译器常用调试详解
实用调试技巧 文章目录 实用调试技巧 什么是bug? 调试是什么?有多重要? Debug和Release的介绍 windows环境调试介绍 一些调试的实例 如何写出好的代码 const 什么是bug? ...
- 还在肉眼找bug??赶紧进来!!!程序员一定要学的调试技巧.
本文介绍了什么是bug,什么是调试,调试重要性,如何调试解决bug,各种常用的调试快捷键,如何写出好代码以及const关键字,assert断言库函数介绍,写代码各种遇见的错误, 调试训练 实用调试技巧 ...
最新文章
- Python time库的使用总结
- oracle12c无法访问em精简版,Oracle12C的EM无法访问怎么办?
- server2008r2/2012R2遠程桌面-企业协议号
- 我的Go语言学习之旅五:Go循环输出的另类实现
- 往邮箱里发python怎么发_Python 超简单的邮件发送方法
- 【HDU - 1026 】Ignatius and the Princess I (bfs + 记录路径)
- 20200327:最大矩形(leetcode85)
- 适用于中小型公司代理服务器的IPTABLES脚本
- 网络七层协议的形象说明
- PHP为什么是最好的编程语言?
- 修改macOS中鼠标滚轮方向
- 随机数字表法计算机分配,随机数字表法
- C语言位操作中的置0和置1
- ddl是什么意思网络语_DDL(数据定义语言)
- 双色汉诺塔算法的证明——数学归纳法
- tensorflow2.X, TensorFlow Addons 版本的匹配选择
- 【客户服务】客户流失该如何应对
- 2016 -Nginx的负载均衡 - 一致性哈希 (Consistent Hash)
- cdn 中移集采_中兴通讯中标中国移动融合CDN四期集采新建项目
- 在Windows上编译FreeRDP