目录

    • 一、什么是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、调试的基本步骤

  1. 发现程序错误的存在

    • 程序员
    • 测试人员 --> 发布
    • 用户
  2. 以隔离、消除等方式对错误进行定位
  3. 确定错误产生的原因
  4. 提出纠正错误的解决方法
  5. 对程序错误予以改正,重新测试

三、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、运行时错误

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




七、如何写出好(易于调试)的代码。

优秀的代码:

  1. 代码运行正常
  2. bug很少
  3. 效率高
  4. 可读性高
  5. 可维护性高
  6. 注释清晰
  7. 文档齐全

常见的coding技巧:

  1. 使用assert
  2. 尽量使用const
  3. 养成良好的编码风格
  4. 添加必要的注释
  5. 避免编码的陷阱

一、模拟实现库函数: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 = &num;*p = 20; //可以修改printf("%d\n", num);
}

const修饰指针 *左右

int main()
{const int num = 10;//const修饰指针//const 放在*的左边//修饰的是指针指向的内容(*p),指针指向的内容,不能通过指针来改变了//但是指针变量本身(p)是可以改变的int n = 100;const int* p = &num; //写法相同int const * p = &num;*p = 20;p = &n;printf("%d\n", num); //修饰的是p 此时p不能存放n的地址//const 放在*的右边//修饰的是指针变量本身(p),指针变量本身(p)不能修改了//指针指向的内容(*p)可以修改,int n = 100;int * const p = &num; //修饰的是*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 初始化 越界访问 堆栈 模拟实现库函数相关推荐

  1. C语言:实用调试技巧

    目录 C语言:实用调试技巧 1.什么是bug? 2.调试是什么?有多重要? 3.debug和release的介绍 4.Windows环境调试介绍 5.一些调试的实例 6.如何写出好(易于调试)的代码 ...

  2. C语言第二十课:实用调试技巧

    目录 前言: 一.Bug: 二.调试: 1.调试是什么: 2.调试的基本步骤: 3. Debug 与 Release : 三.在Windows环境下进行调试: 1.调试环境的准备: 2.调试的快捷键: ...

  3. C语言之实用调试技巧

    什么是bug? 调试是什么?有多重要? debug和release的介绍. windows环境调试介绍. 一些调试的实例. 如何写出好(易于调试)的代码. 编程常见的错误. 一. 什么是bug? 第一 ...

  4. VS2017实用调试技巧

    目录 历史上的第一个Bug,什么是bug 调试的重要性 现实中的你是会是这样子的吗? 调试的基本步骤 1.发现程序错误的存在 2.以隔离.消除等方式对错误进行定位 3.确定错误产生的原因 4.提出纠正 ...

  5. ACM/OI中C++常用优化(实用/调试/技巧)代码(语法)

    一.C++万能编译头文件 #include<bits/stdc++.h> 从 #include <iostream> #include <cstdio> #incl ...

  6. C语言初阶——实用调试技巧

  7. 【C语言】实用调试技巧与const函数提升代码健壮性

    作者简介:大家好我是狂暴于涛侠

  8. 实用调试的技巧,VS编译器常用调试详解

    实用调试技巧 文章目录 实用调试技巧 什么是bug? 调试是什么?有多重要? Debug和Release的介绍 windows环境调试介绍 一些调试的实例 如何写出好的代码 const 什么是bug? ...

  9. 还在肉眼找bug??赶紧进来!!!程序员一定要学的调试技巧.

    本文介绍了什么是bug,什么是调试,调试重要性,如何调试解决bug,各种常用的调试快捷键,如何写出好代码以及const关键字,assert断言库函数介绍,写代码各种遇见的错误, 调试训练 实用调试技巧 ...

最新文章

  1. Python time库的使用总结
  2. oracle12c无法访问em精简版,Oracle12C的EM无法访问怎么办?
  3. server2008r2/2012R2遠程桌面-企业协议号
  4. 我的Go语言学习之旅五:Go循环输出的另类实现
  5. 往邮箱里发python怎么发_Python 超简单的邮件发送方法
  6. 【HDU - 1026 】Ignatius and the Princess I (bfs + 记录路径)
  7. 20200327:最大矩形(leetcode85)
  8. 适用于中小型公司代理服务器的IPTABLES脚本
  9. 网络七层协议的形象说明
  10. PHP为什么是最好的编程语言?
  11. 修改macOS中鼠标滚轮方向
  12. 随机数字表法计算机分配,随机数字表法
  13. C语言位操作中的置0和置1
  14. ddl是什么意思网络语_DDL(数据定义语言)
  15. 双色汉诺塔算法的证明——数学归纳法
  16. tensorflow2.X, TensorFlow Addons 版本的匹配选择
  17. 【客户服务】客户流失该如何应对
  18. 2016 -Nginx的负载均衡 - 一致性哈希 (Consistent Hash)
  19. cdn 中移集采_中兴通讯中标中国移动融合CDN四期集采新建项目
  20. 在Windows上编译FreeRDP

热门文章

  1. java返回空集合对象_返回null或空集合更好吗?
  2. 虚拟机的管理(libvirtd)、移植和快照
  3. MySQL工作中的实际用_总结工作中经常用到的mysql基础知识
  4. java操作Linux 调用shell命令,shell脚本
  5. Linux硬链接和软链接
  6. P1155 双栈排序
  7. 说说你对Jdk并发包中的CAS实现的了解?
  8. Android SDK上手指南:项目清单
  9. how hurt my eggs are, if two, please deep two.
  10. 实现一个shell程序