【C语言进阶笔记】

news2024/11/28 4:35:49

文章目录

  • 1. const(常量指针、指针常量)
  • 2. static
  • 3. extern
  • 4. 指针数组和数组指针
  • 5. 结构体对齐
  • 6. int / uint取值范围、二进制形式与转换、负数表示
  • 7. '\0','0',"0",0之间的区别
  • 8. 类型自动转换
  • 9. 内存结构
  • 10. 大小端
  • 参考资料

1. const(常量指针、指针常量)

int *p1;						// p1是一个指针,指向int类型
const int *p2;					// p2是一个常量指针,指向const int类型,p2可指向其他地址
int const *p3;					// p3和p2相同,只是写法不同
int *const p4 = addr;			// p4是一个指针常量,指向int类型,p4不能再指向其他地址
const int *const p5 = addr;		// p5是一个指针常量,它指向常量,const同时修饰类型与指针,p5和p5指向的地址均不可修改
  • 指针常量
    本质上一个常量,指针用来说明常量的类型,表示该常量是一个指针类型的常量
    在指针常量中,指针自身的值是一个常量,不可改变,始终指向同一个地址。
    在定义的同时必须初始化。
  • 常量指针
    常量指针本质上是一个指针,常量表示指针指向的内容,说明该指针指向一个“常量”
    在常量指针中,指针指向的内容是不可改变的指针看起来好像指向了一个常量

2. static

通常有两种情况:

  • 修饰变量
    静态全局变量:全局变量前加static修饰,该变量就成为了静态全局变量。全局变量在整个工程都可以被访问(一个文件中定义,其它文件使用的时候添加extern关键字声明 ),而在添加了static关键字之后,这个变量就只能在本文件内被访问了。因此,在这里,static的作用就是限定作用域
    静态局部变量:局部变量添加了static修饰之后,该变量就成为了静态局部变量。局部变量在离开了被定义的函数后,就会被销毁,而当使用static修饰之后,它的作用域就一直到整个程序结束。因此,在这里static的作用就是限定生命周期
  • 修饰函数
    修饰函数则该函数成为静态函数,只能被本文件中的其他函数调用,不能被同一程序的其他文件中的函数调用,即函数的作用域仅限于本文件,而不能被其它文件调用。(限定作用域

  • 在C语言中,关键字static有三个明显的作用:
    (1) 在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变
    (2) 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所有函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量
    (3) 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。这个函数被限制在声明它的模块的本地范围内使用。

3. extern

函数的声明和定义方式默认都是extern的,即函数默认是全局的。因此,为了修饰当前文件中的内部函数,static关键字出场了。
使用static和extern修饰变量的时候,变量的生命周期是一样的,不同的是变量的作用域

关键字生命周期作用域
extern静态(程序结束后释放)外部(整个程序)
static静态(程序结束后释放)内部(仅编译单元,一般指单个源文件)
auto, register函数调用(调用结束后释放)
  • extern函数的目的
    (1)extern可置于变量或者函数前,以表示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义;
    (2)取代include "*.h"来声明函数;
    (3)extern “C”,C++在编译时为解决函数多态问题,会将函数名和参数联合起来生成一个中间的函数名,而C语言则不会,因此会造成链接时找不到对应的函数的情况,故在C++中采用extern“C”{ }声明,可以让.cpp文件使用.c文件中的函数。

4. 指针数组和数组指针

核心是看符号优先级来区分是指针还是数组:()>[]> *
一个数组里含有的元素是指针类型时,它就是指针数组。

// 注意优先级:()>[]> *
int (*p)[5];	// (数组指针)定义一个指向含有5个元素的一维数组的指针,即它是一个指针,指向一维数组
int *p[5];		// (指针数组)定义一个含有5个int型指针的数组,即它是一个数组,内部元素是指针
  • 解析
    由于优先级()>[]> *,(*p)是一个整体,表示指针,它指向int [5]数组;p[5]是一个整体,表示数组,数组元素是int *。

5. 结构体对齐

  • 对齐步骤
    (1)首先,结构体各成员对齐;
    (2)然后,结构体总体对齐。
  • 对齐规则
    (1)第一个数据成员存放的地址为结构体变量偏移量为0的地址处;
    (2)其他结构体成员存放的地址为min{自身对齐值,指定对齐值}最小整数倍的地址处;
    (3)总体对齐时,字节大小为min{所有成员中自身对齐值最大的,指定对齐值}的整数倍。
  • 基本概念
    数据自身对齐值:char为1,short为2,float为4,int通常为4等。
    结构体或类的自身对齐值:其成员中自身都旗帜最大的那个值。
    指定对齐值#pragma pack(value)时指定的对齐value。
    数据成员、结构体有效对齐值min{自身对齐值,指定对齐值}
  • 实例
    在一个四字节对齐的32位系统中,有如下结构体,其中sizeof(SmartFlag)=?
struct tagSmart
{
	char flag1;							// 自身对齐值为1字节
	int (*left_tree)[3];				// 数组指针,其本身是一个指针,因此指针的自身对齐值为4字节
	struct tagSmart *right_tree[2];		// 指针数组,此数组中含有2个struct tagSmart *型元素,自身对齐值为2*sizeof(struct tagSmart *)=2*4=8字节
	char flag3;							// 自身对齐值为1字节
	char flag4;							// 自身对齐值为1字节
} SmartFlag[4];

首先,进行结构体各成员对齐,遵循原则min{自身对齐值,指定对齐值}最小整数倍的地址处,其中指定对齐值为4字节:
flag1的有效对齐值为min{1,4}=1,存放地址:1*0=0,它放在结构体偏移量为0的地址处;
(*left_tree)的有效对齐值为’min{4,4}=4’,存放地址:4*0=0,不可用,4*1=4可用,即放在偏移量为4的地址处;
right_tree[2]的有效对齐值为min{8,4}=4,存放地址:4*2=8可用,即放在偏移量为8的地址处;
flag3同上,有效对齐值为1,存放地址:1*16=16,即放在偏移量为16的地址处;
flag4放在偏移量为17的地址处;
其中整体占18字节;
然后,进行总体对齐,字节大小为min{8,4}=4的整数倍,4*5=20,因此结构体对齐占20字节;
最后sizeof(SmartFlag)=20*4=80字节。

6. int / uint取值范围、二进制形式与转换、负数表示

  • int / uint的取值范围
int8:   -128 ~ 127
int16:  -32768 ~ 32767
int32:  -2147483648 ~ 2147483647
int64:  -9223372036854775808 ~ 9223372036854775807
 
uint8:  0 ~ 255
uint16: 0 ~ 65535
uint32: 0 ~ 4294967295
uint64: 0 ~ 18446744073709551615

理解:

  • 有符号
    int8占1个字节(Byte) ,即8个二进制位(Bit);
    8个二进制位就有2^8 = 256种组合(可以存储256个数);
    int8为有符号,所以正数和负数将平分256个数。256 / 2 = 128
    负数为128个,最小为-128,正数为128个,0占一个,最大为127。
  • 无符号:
    如果是uint8(8Bit无符号-没有负数) 2^8 = 256
    0占一个数,所以最大是255。

  • 基础知识
    正数的原码、反码、补码相同。等于真值对应的机器码。
    负数的原码等于机器码,反码为原码的符号位不变,其余各位按位取反。补码为反码+1。
  • 负数的互转
    负数以绝对值的补码形式表达。
    需要先获得其绝对值的原码,再得反码,再得补码。
    原码:一个整数,按照绝对值大小转换成的二进制数,称为原码。
    反码:将二进制数按位取反(1变0,0变1),所得的新二进制数称为原二进制数的反码。
    补码:反码加1称为补码。

-29的二进制为:
绝对值:29
原码:00011101
反码:11100010
补码:11100010 + 00000001
表达:11100011

想要反推出负数的十进制,只需要按同样的方法将表达反推原码,原码的十进制数 * -1 即可:

-29的原码二进制为:
表达:11100011
反码:00011100
补码:00011100 + 00000001
原码:00011101
换算成10进制为 从低位到高位开始计算:
0 0 0 1 1 1 0 1
0*2^7 + 0*2^6 + 0*2^5 + 1*2^4 + 1*2^3 + 1*2^2 + 0*2^1 + 1*2^0
0 +0 +0 +16 +8 +4 +0 +1
=29 * -1
= -29

7. ‘\0’,‘0’,“0”,0之间的区别

其中'\0''0'是字符,"0"是字符串常量,0是整形常量。
对于字符,C语言中依据ASCII码对应进行存储,\0对应的是空字符,即ASCII码表中的0(Null),'0'对应的是表中的48,它可以参与相关运算,例如字符和数字的转换时:8+'0','8'-3
字符常量由单引号括起来;字符串常量由双引号括起来。
字符常量只能是单个字符;字符串常量则可以含一个或多个字符。

  • sizeof和strlen中的区别和用法
    \0是字符串的结束符,sizeof和strlen中到底算不算\0字符,容易搞混淆。
    sizeof是C语言中的一个单目运算符,用来计算数据类型所占空间的大小,单位为字节,在计算字符串的空间大小时,包含了结束符\0的位置;
    strlen是一个函数,用来计算字符串长度,使用时需要引用头文件#include <string.h>,不包含\0,即计算\0之前的字符串长度。

8. 类型自动转换

  • 类型转换原则
    (1)参与运算的类型不同,先转换为相同类型再运算;
    (2)数据类型向数据长度增长的方向转换,char->short->int->unsigned int ->longfloat->double
    (3)赋值运算时,赋值号右侧的类型向左侧的类型转换;
    (4)同一类型,有符号数和无符号数运算时,有符号数向无符号数转变。
  • 实例
    在C语言中下面哪些表达式为真?
unsigned int a = 20;
int b = 13;
int k = b - a;

// b - a运算时首先b会转为无符号整形计算,并通过补码进行计算,得到一个很大的数,即k是一个很大的负数。
k < (unsigned int)b + a;	// 右侧是无符号数,因此k要先转为无符号数再进行运算,k转换后得到一个很大的无符号数,大于右侧,假
k < (int)(b + a);			// b+a被强制转为int,因此两边采用int型进行比较,k为负数,真
k < b + (int)a;				// 同上
  • 无符号数之间的运算
    无符号数之间进行的加减法运算,是通过补码来进行的。比如a - b,实质上是a补 + (-b补)。
    0

9. 内存结构

BSS段(存放未初始化的全局变量,不占用执行程序大小,内容由操作系统初始化)
数据段(存放已初始化的全局变量,包含初始化的静态变量,即全局变量和static变量)
代码段(存放程序执行代码的内存区域,大小在程序运行前已经确定,且通常属于只读)
堆(存放进程运行中被动态分配的内存段,大小不固定,malloc分配的为此内存)
栈(临时创建的局部变量(不含static声明的变量),在函数被调用时,其参数也会被压栈)
  • .bss段存放
    未初始化的全局变量(算数类型和指针类型);
    未初始化的static变量(不论在函数外部还是在函数内部定义);
    未初始化的常量;
    初始化为0的全局算数类型变量,初始化为NULL的全局指针类型变量;
    初始化为0的static变量(不论在函数内部定义还是在函数外部定义);
  • .data段存放
    有初始值(不为0)的全局变量;
    有初始值(不为0)的static变量,(不论static变量在函数内部定义还是在函数外部定义);
  • .text段存放
    可执行指令
    有初始值(不论初始值是否是0)的常量

10. 大小端

大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址
中;
小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,保存在内存的高地
中。

参考资料

  1. 指针常量和常量指针
  2. c语言中的static关键字的作用
  3. C/C++中的 extern 和extern“C“关键字的理解和使用(对比两者的异同)
  4. 指针数组和数组指针(非常易懂)
  5. C语言–结构体内存对齐规则
  6. C语言中sizeof()和strlen()的区别(详解版)
  7. int / uint 的 取值范围、二进制表示形式、与十进制转换方法
  8. 无符号数的减法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/597938.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【前端之旅】nvm-Node版本管理工具

一名软件工程专业学生的前端之旅,记录自己对三件套(HTML、CSS、JavaScript)、Jquery、Ajax、Axios、Bootstrap、Node.js、Vue、小程序开发(Uniapp)以及各种UI组件库、前端框架的学习。 【前端之旅】Web基础与开发工具 【前端之旅】手把手教你安装VS Code并附上超实用插件…

【HttpRunnerManager】搭建接口自动化测试平台操作流程

一、需要准备的知识点 1. linux: 安装 python3、nginx 安装和配置、mysql 安装和配置 2. python: django 配置、uwsgi 配置 二、我搭建的环境 1. Centos7 &#xff08;配置 rabbitmq、mysql 、Supervisord&#xff09; 2. python 3.6.8 &#xff08;配置 django、uwsgi&am…

自然语言处理实战9-大语言模型的训练与文本生成过程

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下自然语言处理实战9-大语言模型的训练与文本生成过程&#xff0c;以下是本文的目录结构&#xff1a; 文章目录 1.引言 2.大语言模型概述 3.大语言模型的应用项目 3.1 语言生成 3.2 机器翻译 3.3 问答系统 3.4 自动…

Express框架从入门到如土

目录 前言一&#xff0c;初体验二&#xff0c;路由2.1 什么是路由2.2. 路由的使用2.3 获取请求报文参数2.4 id的通配2.5 响应的设置 三&#xff0c;中间件3.1 中间件概述3.2 全局中间件与路由中间件的比对3.3 全局中间件的使用3.4 局部中间件的使用3.5 静态资源中间件&#xff…

“邮件营销新趋势,这个平台让你收获颇丰!

随着各媒体平台的迅速发展&#xff0c;2023年大家更专注于视频营销、网红营销、直播营销等营销方式。可以见得&#xff0c;数字媒介手段的发展&#xff0c;对于营销方式也产生了巨大的影响。但是&#xff0c;企业在拥抱新兴的营销方式的同时&#xff0c;也不要忽视传统的营销方…

好用的Chrome浏览器插件推荐(不定期更新)

好用的Chrome浏览器插件推荐 1.1 CSDN-浏览器助手1.2 Google 翻译1.3 JSON Viewer1.4 ModHeader - Modify HTTP headers1.5 Octotree - GitHub code tree 1.1 CSDN-浏览器助手 CSDN-浏览器助手 是一款集成本地书签、历史记录与 CSDN搜索(so.csdn.net) 的搜索工具 推荐&#x…

碳中和背景下我国空调系统发展趋势2022(李先庭)

碳中和背景下我国空调系统发展趋势 摘要 我国建筑空调系统在运行阶段的年碳排放量约为&#xff19;&#xff0e;&#xff19;亿&#xff54;二氧化碳&#xff0c;降低其碳排放是实现碳达峰碳中和目标的重要挑战之一。本文对我国当前空调系统碳排放量进行了拆解&#xff0c;分…

node-exporter,prometheus,grafana三者之间的联系

一、node-exporter与节点机 用于收集节点机器的数据信息&#xff0c;那么node-exporter与节点机器的连接在哪里&#xff1f; node-exporter.yaml apiVersion: apps/v1 kind: DaemonSet metadata:name: node-exporternamespace: kube-systemlabels:k8s-app: node-exporter spe…

调整直线导轨间隙有什么方法?

直线导轨作为机械行业中非常重要的传动部件&#xff0c;应用范围当然相当广泛&#xff0c;尤其是自动化设备&#xff0c;基本上我们都能看到它的作用。 在机械行业待得久的人都知道&#xff0c;直线导轨在使用的过程中&#xff0c;为了保证直线导轨的正常工作&#xff0c;直线导…

C++ string类-2

at at 函数是在C还没有支持运算符重载的时候提供的。 他可以像 [] 重载运算符一样&#xff0c;找到某个位置的字符&#xff1a; string s1("hello world");s1.at(0) x;cout << s1 << endl; 输出&#xff1a; [] 重载运算符和 at&#xff08;&#x…

GIT常见报错以及解决方法

GIT常见报错以及解决方法 Changes not staged for commit问题复现原理解决 warning: adding embedded git repository问题复现原理解决 error: src refspec master does not match any问题复现 Changes not staged for commit问题复现&#xff1a;解决 Changes not staged for …

软考A计划-电子商务设计师-电子商务基础知识

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&am…

chatgpt赋能python:Python为什么成为不可或缺的编程语言?

Python为什么成为不可或缺的编程语言&#xff1f; Python语言在过去的十年间&#xff0c;已经成为编程领域中不可或缺的一种语言。Python语言是一种高级、通用、面向对象语言&#xff0c;并且在数据科学、机器学习、网站开发等众多领域中广泛应用。本文将探讨为什么Python成为…

保护密码安全:ADSelfService Plus的重要性与优势

引言&#xff1a; 在当今数字化时代&#xff0c;密码安全对于个人和组织而言变得愈发重要。随着互联网的普及和数据泄露事件的频发&#xff0c;传统的用户名和密码已经不再足够保护我们的个人和机密信息。为了解决这个问题&#xff0c;许多组织开始采用密码管理工具&#xff0…

Fourier分析入门——第13章——信号分析

目录 第13章 信号分析 13.1 引言 13.2 加窗(windowing) 13.3 用一系列窗口采样(Sampling with an array of windows) 13.4 混叠现象(Aliasing) 13.5 通过插值重建(Reconstruction by interpolation) 13.6 非点采样(Non-point sampling) 13.7 覆盖系数规则(The coverage …

Yolov8轻量级:VanillaNet一种新视觉Backbone,极简且强大!华为诺亚2023

简到极致、浅到极致!深度为6的网络即可取得76.36%@ImageNet的精度,深度为13的VanillaNet甚至取得了83.1%的惊人性能。 1.VanillaNet 论文:https://arxiv.org/pdf/2305.12972.pdf 来自华为诺亚、悉尼大学的研究者们提出了一种极简的神经网络模型 VanillaNet,以极简主义的设…

第十三篇、基于Arduino uno,获取薄膜压力传感器的值——结果导向

0、结果 说明&#xff1a;先来看看串口调试助手显示的结果&#xff0c;第一个值是上电后检测到的平均压力值&#xff0c;第二个值是实时的压力值&#xff0c;第三个值是平均压力值和实时压力值的差值。如果是你想要的&#xff0c;可以接着往下看。 1、外观 说明&#xff1a;…

windows上简单部署flink

Windows上部署flink1.17 flink的下载链接 进入页面后下滑找到Apache Flink&#xff0c;然后找到对应版本&#xff0c;之后点击Binaries 找到xxx-bin-scala-xxx.tgz文件下载 下载完成后直接本地解压 解压后进入bin目录新增两个.bat文件&#xff08;直接复制下面内容<注意命名…

扩展dlink-connector-phoenix使其phoenix-5.0.0支持flink1.16

感慨&#xff1a;玩大数据java必须要精通,不然遇到眼花缭乱的框架以及插件拓展的时候就会一下子傻眼了。各种框架之间版本不同有现成的插件或者方案到还可以但是没有就需要自己扩展。目前我使用的是CDH6.3.2&#xff0c;flink使用的是1.6&#xff0c;Phoenix版本的是5.0.0这有在…

数据结构入门7-1(查找)

目录 注 查找的基本概念 线性表的查找 顺序查找 折半查找 分块查找 树表的查找 二叉排序树 平衡二叉树 平衡二叉树的定义 平衡二叉树的平衡调整方式 平衡二叉树的实现 B-树 B-树的定义 B-树的示意性实现 B树 注 本笔记参考&#xff1a;《数据结构&#xff08;C…