C语言知识之结构体及实用调试技巧

一.结构体

定义:

一些值的集合,这些值称为成员变量,结构体的每个成员可以是不同类型的变量

1.结构体(结构)的声明

struct  Book(结构体名称)
{
    Member-list(成员列表)
}variable-list(变量列表);

1.1结构体的作用:

之前笔记中的类型都是内置型:
char short int ……

所以就有结构体来描述复杂对象
结构体可以是任何类型

1.2结构体变量的创建

1.2.1

struct (结构体名称) (变量名)

struct Stu s1;
1.2.2

在1中的变量列表处直接创建变量s1、s2……
注意:此处的变量是全局变量

struct Stu
{
	 Member-list
} s1, s2;
1.2.3

使用typedef,就能简写struct成自定义的类型名,如Stu

typedef struct Stu
{
	 //Member - list
}Stu;//Stu 是重命名产生的新的类型


int main()
{
	Stu s1,s2;
	return 0;
}

1.3结构体变量的初始化

使用{}进行赋值,有两种方式,如:

struct B
{
	char c;
	int i;
};

struct S
{
	char c;
	int num;
	int arr[10];
	double* pd;
	struct B sb;
	struct B* pb;
}s1;//s1是全局变量
	
struct S s2;//s2是全局变量
	
int main()
{
	double d = 3.14;
	//按照顺序初始化
	struct S s3 = { 'q', 100, {1,2,3}, &d, {'a', 99}, NULL };
	//指定成员来初始化
	struct S s4 = { .num = 1000, .arr = {1,2,3,4,5} };
	return 0;
}

2.结构体成员的访问

分为两种
结构体变量.成员名

结构体指针->成员名

3.结构体变量的传参

推荐传址调用:
a 传址调用能实现的作用比传值调用更大。
b 节省占用栈区空间的大小,行能更高。

二实用调试技巧

1.bug

指飞蛾
事件链接:
点击此处跳转
有兴趣的可以了解一下
请添加图片描述

由此,飞蛾(bug)就引申为计算机程序的错误

2.调试

2.1定义

寻找错误并解决的过程就是调试

2.2步骤

2.3debug和release

debug:

debug(调试)版本:
不进行优化,由于进行调试

release:

release(发布)版本:
自动进行优化,不能调试,给用户使用的版本

3.windows环境调试介绍

3.1环境准备

debug版本

3.2快捷方式

下面介绍五个最常用的快捷键。
提示:部分机器需要加上Fn键。
在这里插入图片描述
补充:
F11更细致:能进入函数内部,并逐条执行其中的语句。
F9创建断点
F5跳过断点前的代码,便于调试
F5还可以使用条件断点,更快捷
如图:
在这里插入图片描述

提示:
当循环中存在断点时,F5只会跳到下一次循环中的断点

3.3调试过程中查看当前代码的信息

在这里插入图片描述

提示:
1.

推荐使用监视,自己确定要监视的对象,不建议用自动窗口。

2.

部分VS2022在运行前点窗口是看不到上图中的选项的,此时可以先开始调试,再点击窗口,就能看到那些选项了。

调用堆栈:

反映的是函数的调用逻辑,即运行过程
在这里插入图片描述
从这里可以看出,函数的运行逻辑:从下往上逐层调用。

概念介绍:

在存储数据时,分为两种,栈和队列

栈:一种数据结构,后进先出,后进的元素在栈区的上面,结束时就先出
队列:先进先出

4.实例

下面向大家介绍两段代码,以便于大家更好的理解调试的重要以及用处。

A

先用一个简单的题目吧:
求1~n的阶乘之和

int main()
{
	int i = 0;
	int n = 0;
	int ret = 1;
	int sum = 0;
	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;
}

我们运行之后会发现结果错误,
这时候我们进行调试,会发现:
在这里插入图片描述
ret的值不是我们预期的,
这时我们逐步查找后发现每次循环ret的值都在随之增大,所以应在循环内部加上

ret = 1;

B

观察下面这个程序,并用调试解释其错误的原因。
注意:
这段代码是在VS 上,X86,debug模式下运行的,在解释完这段代码后,会单独进行说明。

#include <stdio.h>

int main()
{
	int i = 0;
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };

	for (i = 0; i <=12; i++)
	{
		arr[i] = 0;
		printf("hehe\n");
	}

	return 0;
}

运行结果:
死循环的打印“hehe”

常识介绍:

数组,随着下标的增长,地址是由低向高变化的,即向下扩展

解释:

在此环境下,数组arr是存储在i地址向上8个字节的地址,所以当其越界至i=12时,arr[12]其地址与i相同,所以改变arr[12]就会改变i,即i也变为0,所以就陷入了死循环。
图解:
在这里插入图片描述
图二

编译器的说明

这个代码在VC 6.0下,arr和i之间没有空隙
在gcc下二者之间有一个空隙

提示:

当在release下运行程序时,程序不会报错,因为它自动进行优化,即把i存储在比数组小的地址中,使数组越界也不会访问到i

结语

今天的知识点就介绍到这里,我们下次见。

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值