首页 > 其他分享 >C语言深度剖析--不定期更新的第四弹

C语言深度剖析--不定期更新的第四弹

时间:2024-09-07 21:53:13浏览次数:13  
标签:函数 -- void 不定期 C语言 int 编译器 返回值 栈帧

在这里插入图片描述

void关键字

void关键字不能用来定义变量,原因是void本身就被编译器解释为空类型,编译器强制地不允许定义变量
在这里插入图片描述
定义变量的本质是:开辟空间

而void 作为空类型,理论上不应该开辟空间(针对编译器而言),即使开辟了空间,也只是作为一个占位符看待(针对Linux来说)

所以,既然无法开辟空间,也无法作为正常变量使用,既然无法使用,干脆编译器不让它编译变量

void修饰函数返回值和参数

需要注意的点是:C语言中函数可以不带返回值,默认的返回值是int

但是我们平常在编写函数相关的代码的时候还是得带上函数的返回值类型,否则人家会在猜测究竟是默认?还是忘了没有写返回值?

所以在前面用void函数修饰的作用是起到一个提醒和占位的作用

void修饰函数返回值:1.占位符,让用户明确不需要返回值2.告知编译器,这个返回值无法被接受

void充当函数的形参列表:告知用户或编译器,该函数不需要传参

结论:如果一个函数没有参数,将参数列表设置为void,是一个不错的习惯,因为可以将错误提前发现

void指针

void指针可以创建变量,原因在于void*是指针,是指针,空间大小就能明确出来

void*可以被任何类型的指针接受,void * 可以接受任意类型指针(常用)

进一步来说就是库,系统接口的设计上,尽量设计成通用接口

如这样的:
在这里插入图片描述

#include <stdio.h>
int main()
{
    void*p=NULL;
    int*x=NULL;
    double*y=NULL;
    p=x;//虽然类型不同,但是编译器不会报错
    p=y;//同上
    
    x=p;
    y=p;//编译器也不会报错
	return 0;
}

这里产生了一个问题:void类型的指针是否可以计算呢?

在不同的平台上是不一样的,在VS的环境下,是不可以的,但是在Linux的环境下是可以的,主要原因出现在两个平台对于void大小的理解,VS认为void大小为0,但是Linux认为是sizeof(void)

void*指针不可以解引用,虽然void *可以接受任意类型,但是还是不可以解引用

return关键字

两个问题的区别:C语言有没有字符串类型VS C语言有没有字符串

C语言有字符串,但是C语言没有字符串类型

注意点:求字符串长度是不包括‘\0’的,求字符串容量是包括’\0’

计算机中是否真的需要将所有的数据清零?

计算机中清空数据,只需要设置该数据无效即可。

这句话的意思其实不太准确,只是因为我们所学的知识还没有这么多而已,打个比方,一个10GB的文件,可能只需要十个比特位大小,一个比特位代表1GB

接下来,来看如何正确理解下面的代码:

#include <stdio.h>
char*show()
{
    char str[]="hello cosmic love";
	return str;
}
int main()
{
    char*s=show();
    printf("%s\n",s);
	return 0;
}

在这里插入图片描述
打印结果是一串乱码

这里我们需要懂得函数栈帧相关的知识。

调用函数,形成栈帧;函数返回,释放栈帧

在这里插入图片描述
在这里插入图片描述
原因有下面几点:

1.计算机并不清空数据

2.printf也是函数,也要遵守这些规则,所以就二次覆盖了show的栈区

补充2个点:

1.怎样保证栈帧申请的空间是够的?

因为编译器会根据关键字大小预估充足的空间大小

2.栈帧的结构是怎样的?

可以联想我们之前学过的递归的概念,栈帧的创建也是一个不断向下创建的过程

有个问题:临时变量为什么具有临时性?

因为临时变量在函数栈帧中创建,栈帧结构在函数调用完毕之后要被释放

书写规范上的注意:

return语句不可返回指向“栈内存”的指针,因为该内存在函数体结束的时候会被销毁

可以看下面几行代码:

int GetData()
{
	int x=0x11223344;
    printf("run get data!\n");
    return x;
}
int main()
{
	int y=GetData();
    printf("ret:%x\n",y);
}

在这里插入图片描述
在这里插入图片描述
在上面的代码做一点小小的修改:

int GetData()
{
	int x=0x11223344;
    printf("run get data!\n");
    return x;
}
int main()
{
	GetData();
    printf("ret:%x\n",y);
}

在这里插入图片描述
需要注意一个概念:函数的返回值具有常性

结论

一个函数如何返回给外部调用方,本质是通过寄存器;

当我们返回,没有对应的接收时,调用return 会生成同等汇编语言,如果对应的接收方,就会继续往下走

小彩蛋:
main函数的返回值给谁?为什么main函数的返回值基本上是0?
因为main函数的返回值是被系统捕获的,可以看程序是否正常结束,如果正常结束的话,一般返回的是0,返回的是非零数的话,一般就不是一个正常结束的状态

标签:函数,--,void,不定期,C语言,int,编译器,返回值,栈帧
From: https://blog.csdn.net/Mr_Xuhhh/article/details/142005095

相关文章

  • 开题报告撰写的四大难点与应对策略
    AIPaperGPT,论文写作神器~https://www.aipapergpt.com/对于每个即将进入毕业论文阶段的学生来说,开题报告是一道必经的门槛。开题报告不仅决定了你的论文方向,还对后续的研究和写作起到重要的引导作用。然而,许多学生在撰写开题报告时常常会遇到各种难题,如选题模糊、研究方法不......
  • CP AUTOSAR标准之EthernetInterface(AUTOSAR_SWS_EthernetInterface)(更新中……)
    1简介和功能概述  该规范指定了AUTOSAR基础软件模块以太网接口的功能、API和配置。  在AUTOSAR分层软件架构[1]中,以太网接口属于ECU抽象层,或者更准确地说,属于通信硬件抽象。  这表明了以太网接口的主要任务:  为上层提供独立于硬件的以太网通信系统接口,该系统由......
  • 什么是MVCC
    MVCC(Multi-VersionConcurrencyControl,多版本并发控制)是一种数据库管理系统中用于实现并发控制的技术。它通过在数据库中为每个数据行保存多个版本,使得不同的事务可以看到不同版本的数据,从而避免了并发事务之间的冲突,提高了数据库的并发性能。一、基本原理版本存储:MVCC为......
  • ABC370掉分寄
    在数月不打ABC后,我为了找回打比赛的手感开始打ABC,结果挂得不堪入目。开场前15min,在360的可爱操作下我的AtcoderBetter被卸了,我就重装,然后在油叉里一不小心点了两遍,重装了俩,一登界面发现两个还一块使,导致交替的时候完全找不到提交按钮,极速换浏览器,可是看不了中文题面了。......
  • Mininet MAC地址学习:通过Mininet模拟二层交换机和两个主机,通过两个主机通信来了解交换
    一.MAC地址学习1.登录我们创建mininet的虚拟机,创建一个线型拓扑,控制器设置为无。2.查看全部节点,查看链路信息,然后查看节点信息3.再打开一个终端(Terminal窗口2),然后打开交换机s1和交换机s2的二层(因为交换机s1和交换机s2是两个SDN交换机,在启动Mininet时没有指定任何控制器,交......
  • 解锁智慧校园科研管理系统的获奖成果功能
    在智慧校园科研管理系统的框架下,获奖成果这一功能模块扮演着极其重要的角色。它不仅有助于学校或研究机构全面地追踪和记录教职工及学生在科研领域取得的各项荣誉,还能够为学校的科研管理工作提供有力的数据支持。通过这个系统,学校可以更高效地管理科研成果,促进学术交流与合作,提升整......
  • Python循环语句
    1-While循环语法:变量=初始值while条件判断:循环体(要循环执行的代码)条件控制语句注意:如果条件恒成立或者直接写True,就会出现无限循环示例:#打印99次,“我爱你”#变量先定义再使用i=1whilei<100:print("我爱你")i+=1whileTrue:......
  • (19-2)基于生成对抗网络假人脸生成系统:实现生成对抗网络(GAN)
    2.3 实现生成对抗网络(GAN)生成对抗网络是一种深度学习模型,由生成器和判别器组成,生成器负责创造虚拟图像,而判别器则负责判断这些图像的真实性。通过这种对抗性训练,生成器逐渐提升其生成图像的质量,以至于可以生成接近真实的图像。在本项目中将对生成器进行训练,使其能够从随机噪......
  • lunix磁盘挂载
    查看磁盘情况,如果  mountpoint 没有显示则表示还没挂载lsblk第二步: 格式化磁盘fdisk/dev/vdb第三步:创建分区 命令: mkfs.ext4/dev/vdb第四步: 挂载分区mkdir/data#创建文件夹mount/dev/vdb/data#将vdb这个硬盘挂载成为/data第五步:将信息写入fstab,让系统......
  • SpringBoot兼容SpringMVC带有.do后缀的请求
    背景MVC框架请求的都是.do后缀,但controller控制层拦截的是没有后缀的链接。如controller请求/111/222,当请求/111/222.do时,可以正常进入。当我们将存量一些旧工程(SpringMVC框架)升级到Springboot后,发现无法进入,此处我们针对这块进行最丝滑的适配。版本信息Springboot:2.7.17方......