调试技巧实例分析以及数据在内存中的存储

目录

调试技巧

调试实例

关于assert

数据基本类型

整形家族

分类

存储方式

大小端

浮点数家族

float

double

构造类型/自定义类型

数组类型

结构体类型 struct

枚举类型 enum

联合类型 union

指针类型 *

空类型 void

数据存储进阶

char/signed char//-128~127

unsigned char//0~255

signed short//-32768~32767

unsigned short//0~65535

signed int//-2147483648~2147483647

unsigned int//0~4,294,967,295


调试技巧

调试实例

#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;
}

我第一眼看到这个代码的反应是 越界了!跑不了吧!

实际上,可以跑,而且一直跑。(死循环)

分析:在vs编译器中,变量i和arr数组在内存中存储的时候,隔着8个字节,就是2个int类型。 当i=10,11,12时,数组越界访问了,会把i的地址的内容变成0。 又开始重新从arr[0]开始循环。

注意:不同的编译器中,变量间存储隔着的空间不一样,上述代码在gcc中就隔着一个整形,这意味着,如果想让代码死循环,可以将for循环中的条件改为i<=11。

以上代码中,变量是存储在栈区的,栈区是从高地址向低地址增长,数组随着下标的增长,从低地址向高地址处增长。

高地址————————————————————————————————————
            i
            0xcc cc cc cc
            0xcc cc cc cc
            arr[9]
            ...
            arr[1]
            arr[0]
低地址————————————————————————————————————

关于assert

aeert在 release版本,就被优化掉了。只在debug中起作用。

建议在程序里对指针判空时,使用assert。

头文件为<assert.h>

数据基本类型

整型类型的取值范围在limits.h头文件中。

浮点数类型的取值范围在float.h头文件中。

char //字符数据类型 1字节
short //短整型 2字节
int //整形 4字节
long //长整型 4/8字节
long long //更长的整形 8字节
float //单精度浮点数 4字节
double //双精度浮点数 8字节
long double//大于double

注:long的定义是比int大的都算long,所以有些平台是4字节,有些平台是8字节。为避免争议,可以直接用long long。

整形家族

分类

char

分成3类,①char,②signed char,③unsigned char。

①char取决于编译器,可能是无符号或者有符号

short

分成2类,①unsigned short,②signed short。

写成short,表示的是②有符号short,两者完全等价。

int

分成2类,①unsigned int,②signed int。

写成int,表示的是②有符号int,两者完全等价。

long

分成2类,①unsigned long,②signed long。

写成long,表示的是②有符号long,两者完全等价。

存储方式

三种:原码、反码、补码。在内存中存储的是补码

正整数的原反补相同,最高位符号位为0;

负整数 原码--符号位不变,其余按位取反得到反码--+1得到补码,最高位符号位为1;

原码到补码

原码取反,+1得到补码

补码到原码 2种方式 1、补码-1,再取反,得到原码 2、补码取反,+1,得到原码

大小端

内存中最小单位是一个字节。当1个数值超过1个字节了,要存储到内存中,就有顺序问题。

大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址 中; 小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地 址中。

浮点数家族

float

double

构造类型/自定义类型

数组类型

结构体类型 struct

枚举类型 enum

联合类型 union

指针类型 *

空类型 void

void* p = NULL; 只能往里面存放,当作一个临时存储变量。不能进行解引用或者算数运算。 (因为不知道指针所指向类型,无法决定要往后走几步)

在使用前,要先强制转换成具体类型的指针。

数据存储进阶

char/signed char//-128~127

00000000//0
00000001//1
...
01111111//127
10000000//-128
10000001//-127
...
11111110//-2
11111111//-1

关于-128的转换。10000000规定死了,就是128

10000000//-128
​
1 1000 0000//-128原码
1 0111 1111//-128反码
1 1000 0000//-128补码

unsigned char//0~255

00000000//0
00000001//1
...
01111111//127
10000000//128
10000001//129
...
11111110//254
11111111//255

signed short//-32768~32767

00000000 00000000//0
00000000 00000001//1
...
01111111 11111111//32767
10000000 00000000//-32768
10000000 00000001//-32767
...
11111111 11111110//-2
11111111 11111111//-1

unsigned short//0~65535

signed int//-2147483648~2147483647

unsigned int//0~4,294,967,295

%u是打印无符号整型,系统会认为内存中存放的补码对应的是一个无符号数

%d是打印有符号整型,系统会认为内存中存放的补码对应的是一个有符号数

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值