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

2024-09-08 02:12

本文主要是介绍C语言深度剖析--不定期更新的第四弹,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在这里插入图片描述
哈哈哈哈哈哈,今天一天两更!

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

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

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

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

在这里插入图片描述
在这里插入图片描述
但是在调试的时候,s指向的值还在

从12行调试到13行的时候发生了变化
在这里插入图片描述
原因有下面几点:

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

来看运行结果:

在这里插入图片描述
貌似跟前面有点悖论

这里拿到的不是X,拿到的是里面的内容

看一下里面的反汇编代码:
得到了下面的结论:

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

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

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

结论

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

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

这篇关于C语言深度剖析--不定期更新的第四弹的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1146816

相关文章

深度解析Nginx日志分析与499状态码问题解决

《深度解析Nginx日志分析与499状态码问题解决》在Web服务器运维和性能优化过程中,Nginx日志是排查问题的重要依据,本文将围绕Nginx日志分析、499状态码的成因、排查方法及解决方案展开讨论... 目录前言1. Nginx日志基础1.1 Nginx日志存放位置1.2 Nginx日志格式2. 499

C语言进阶(预处理命令详解)

《C语言进阶(预处理命令详解)》文章讲解了宏定义规范、头文件包含方式及条件编译应用,强调带参宏需加括号避免计算错误,头文件应声明函数原型以便主函数调用,条件编译通过宏定义控制代码编译,适用于测试与模块... 目录1.宏定义1.1不带参宏1.2带参宏2.头文件的包含2.1头文件中的内容2.2工程结构3.条件编

Go语言并发之通知退出机制的实现

《Go语言并发之通知退出机制的实现》本文主要介绍了Go语言并发之通知退出机制的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1、通知退出机制1.1 进程/main函数退出1.2 通过channel退出1.3 通过cont

Go语言编译环境设置教程

《Go语言编译环境设置教程》Go语言支持高并发(goroutine)、自动垃圾回收,编译为跨平台二进制文件,云原生兼容且社区活跃,开发便捷,内置测试与vet工具辅助检测错误,依赖模块化管理,提升开发效... 目录Go语言优势下载 Go  配置编译环境配置 GOPROXYIDE 设置(VS Code)一些基本

SpringBoot中六种批量更新Mysql的方式效率对比分析

《SpringBoot中六种批量更新Mysql的方式效率对比分析》文章比较了MySQL大数据量批量更新的多种方法,指出REPLACEINTO和ONDUPLICATEKEY效率最高但存在数据风险,MyB... 目录效率比较测试结构数据库初始化测试数据批量修改方案第一种 for第二种 case when第三种

深入理解Go语言中二维切片的使用

《深入理解Go语言中二维切片的使用》本文深入讲解了Go语言中二维切片的概念与应用,用于表示矩阵、表格等二维数据结构,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧... 目录引言二维切片的基本概念定义创建二维切片二维切片的操作访问元素修改元素遍历二维切片二维切片的动态调整追加行动态

Go语言中make和new的区别及说明

《Go语言中make和new的区别及说明》:本文主要介绍Go语言中make和new的区别及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1 概述2 new 函数2.1 功能2.2 语法2.3 初始化案例3 make 函数3.1 功能3.2 语法3.3 初始化

深度解析Java DTO(最新推荐)

《深度解析JavaDTO(最新推荐)》DTO(DataTransferObject)是一种用于在不同层(如Controller层、Service层)之间传输数据的对象设计模式,其核心目的是封装数据,... 目录一、什么是DTO?DTO的核心特点:二、为什么需要DTO?(对比Entity)三、实际应用场景解析

深度解析Java项目中包和包之间的联系

《深度解析Java项目中包和包之间的联系》文章浏览阅读850次,点赞13次,收藏8次。本文详细介绍了Java分层架构中的几个关键包:DTO、Controller、Service和Mapper。_jav... 目录前言一、各大包1.DTO1.1、DTO的核心用途1.2. DTO与实体类(Entity)的区别1

Go语言中nil判断的注意事项(最新推荐)

《Go语言中nil判断的注意事项(最新推荐)》本文给大家介绍Go语言中nil判断的注意事项,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1.接口变量的特殊行为2.nil的合法类型3.nil值的实用行为4.自定义类型与nil5.反射判断nil6.函数返回的