C语言1.调试使用技巧 + strcpy()实现

本文详细解析了C/C++编程中栈、堆、静态区的区别,展示了栈溢出导致的死循环实例,并介绍了良好编码实践,如使用assert和const。还涵盖了内存管理、监视和调试技巧,如监视变量、反汇编和函数调用堆栈分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

快捷键

F11 细粒度 也会进入函数逐行
F10 把函数当作一条语句,略过
F5+断点,只在断点停

  1. 查看临时变量:
// 创建全部a10个,全部为0
int a[10] = {0};

局部变量和自动窗口:自动显示上下文临时变量
自动窗口和局部变量作用差不多

按F10打开局部变量窗口会显示该行附近变量

  • 监视:想看谁看谁:
    监视在名称下面输入要查的变量得到值
  • 内存:打开后可能显示不完全,拉长,输入格式:&i
  • 反汇编:打开汇编文件,在运行主文件时两边文件同时在运行
  • 寄存器也有
  1. 查看函数调用关系(堆栈,技术术语:栈==堆栈):
    F10后打开调用堆栈,随着不断调用函数,新函数名显示在上层,像栈一样,且左边箭头指在上面的现在处于的函数中,且随着程序运行,函数新进去的在上面,最后出函数的时候,新进去的在最上层也先出,栈结构符合实际。
    main()函数也是被其它函数调用的
  2. 特别的死循环代码:招聘题
    死循环
    请添加图片描述
    表明原因:
    结果是死循环:发现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++编程)

  1. 使用assert
  2. 尽量使用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++;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值