快捷键
F11 细粒度 也会进入函数逐行
F10 把函数当作一条语句,略过
F5+断点,只在断点停
- 查看临时变量:
// 创建全部a10个,全部为0
int a[10] = {0};
局部变量和自动窗口:自动显示上下文临时变量
自动窗口和局部变量作用差不多
按F10打开局部变量窗口会显示该行附近变量
- 监视:想看谁看谁:
监视在名称下面输入要查的变量得到值 - 内存:打开后可能显示不完全,拉长,输入格式:&i
- 反汇编:打开汇编文件,在运行主文件时两边文件同时在运行
- 寄存器也有
- 查看函数调用关系(堆栈,技术术语:栈==堆栈):
F10后打开调用堆栈,随着不断调用函数,新函数名显示在上层,像栈一样,且左边箭头指在上面的现在处于的函数中,且随着程序运行,函数新进去的在上面,最后出函数的时候,新进去的在最上层也先出,栈结构符合实际。
main()函数也是被其它函数调用的 - 特别的死循环代码:招聘题
死循环
表明原因:
结果是死循环:发现arr[12]=12,而之前arr[11]已经越界,但会执行,arr[11]是内存中特别大的随机值,而arr[12]=12,很奇怪,查地址发现arr[12]地址和i是一样的,所以因为把i变成了0,所以i=12后又置0了,造成死循环。
解释:
内存中有三部分:
栈区(局部变量、函数参数)
堆区(动态内存分配)、
静态区(静态变量、全局变量)
内存中大的编号叫高地址、小的编号叫低地址
图示:如数组,先开辟一片空间,从低到高使用,即下标小的在下面先赋值,比如a[0]、a[1]
因为都是临时变量,存在栈区,所以因为栈区先使用高地址再用低。
先定义了i变量在高地址,而再创建数组使用的低地址,开辟的数组和临时变量i之间留着位置,往后a[11],a[12]正好撞到了了i,结果就把i给改了,变量之间的预留空间看编译器
如图:
这道题出自:《C陷进与缺陷》
C/C++对数组越界不做检查,不同编译器在内存预留给的不同,VC6.0和linux下给预留一个大小,visual studio预留了两个位置
良好编码风格:(高质量c-c++编程)
- 使用assert
- 尽量使用const
strcpy()实现
预知识:char a[10] = “hello”;
利用string的""做数组赋值时,自动给尾加\0
库函数strcpy也会拷贝\0
被复制对象有:const
****最差写法:解引用str_dest,*desst=*src,且循环外单独赋值\0 ****:
****好写法:解引用str_dest,*desst=*src ****:
void my_strcpy(char* dest, char* src)
{
// 赋值表达式也有值,最后\0是while的值,使得while不成立
while(*dest++ = *src++)
{
}
}
如果main()传入my_strcpy(dest, src):中dest是NULL,my_strcpy不会执行,所以在my_strcpy中加入:assert(dest!=NULL),会把错误直接提示,条件为假会提示
assert是宏(断言),需要《assert.h》
*解释原始的src前是 char src
如果我在str的while中写反了,运行起的时候会报错,而对src加const会使得while中直接报错,
解释const:
//加上const不能直接改变
const int num = 10;
num = 20; // const使得num不能改变,但利用指针能改掉,但这样不好,因为cosnt就希望永远不能变
如何使得指针也不能改变const变量
const int *p = #
给指针加上const,*p也不能改变num
但p的指向可改变,即:指针可改变指向谁,但不能改变内存
p = &n; 可执行
*p = 30; 不可执行
const如果放在int后面
int *const p = #
这样限制的是p,即p不能改变指向对象;
**const放在左边,表示指针指向变量的值不能改变, p=x,不可,但是p的指向可以改变
const在右边,指针指向的内容不能改变
而上面strcpy实现中,使用 const char src:*在右边,即 cosnt(不变) *src:即内容不可以改变,所以dest和src写反就会报错,因为 *Src是违法操作
const:加上变量不能再通过赋值改变,但是指针可以,可是实际加const不希望变量改变,所以有了cosnt加在指针上
my_strlen(char* str)
每次解引用,都应该害怕指针为空
// 只是求长度不能改变它的内容,所以保护起来 const char* str
int my_strlen(const char* str)
{
int count = 0;
assert(str!=NULL); // 所以加断言程序更加健壮,这样空了直接报错 不会往下执行,更好判断在哪里出错
while(str!=NULL) // ↑↑↑↑每次有指针循环遍历,就应该害怕有NULL ↑↑↑↑
{
count++;
str++;
}
}