C语言杂谈

在这里插入图片描述
努力扩大自己,以靠近,以触及自身以外的世界

文章目录

  • 什么是定义?什么是声明?什么是赋值?什么是初始化?
  • 什么是生命周期?什么是作用域?全局变量?局部变量?
  • sizeof是函数吗?关键字!!!
  • signed、unsigned 关键字
  • static关键字
  • abs函数和fabs函数
  • 空结构体占多大空间?
  • 柔性数组
  • union
  • enum
  • typedef
  • 取整和取模
  • 内存对齐——为什么需要内存对齐?
  • 宏定义#define
  • 指针和数组的关系?
  • 向特定地址中写入数据?
  • #和##
  • assert是宏而不是函数
  • malloc申请0字节空间
  • 函数参数的传递发生在函数调用之前
  • 可变参数列表

什么是定义?什么是声明?什么是赋值?什么是初始化?

定义:定义就是创建一个对象,为这个对象分配一块内存并给它取上一个名字,这个名字就是我们经常所说的变量名或对象名

声明:告知编译器这个变量名已经被占用,所有的变量声明时不能设置初始值,因为声明时并没有给出存储空间

赋值:给开辟好的空间赋上数据

初始化:一种特殊的赋值,在变量创建的阶段给上数据,初始化只能有一次

// 定义并初始化全局变量
int global = 10;// 函数声明
void myFunction();int main() 
{// 声明并初始化局部变量int local;local = 20;// 调用函数myFunction();// 打印全局变量和局部变量的值printf("Global: %d\n", global);printf("Local: %d\n", local);return 0;
}// 函数定义
void myFunction() 
{// 赋值操作global = 30;
}

什么是生命周期?什么是作用域?全局变量?局部变量?

生命周期:从开辟到释放所经历的这一时间段

作用域:变量的有效作用范围

全局变量:在整个程序的任何地方都是可用和可访问的

局部变量:只能在变量特定的作用域内起作用

// 全局变量,定义在函数外部,可以在整个程序中使用
int global = 10;// 函数定义
void myFunction() 
{// 局部变量,定义在函数内部,只能在函数内部使用int local = 20;// 访问全局变量和局部变量,并打印它们的值printf("Global: %d\n", global);printf("Local: %d\n", local);
}int main() 
{// 调用函数myFunction();// 尝试访问局部变量,会导致编译错误// printf("Local in main: %d\n", local);// 访问全局变量printf("Global in main: %d\n", global);return 0;
}

sizeof是函数吗?关键字!!!

说来惭愧,当听到问sizeof是函数吗?第一时间就想到它后面接的是(),理所当然的认为sizeof就是函数…

可是sizeof也可以不加()使用啊

int main()
{int val = 100;printf("sizeof() : %d\nsizeof : %d\n", sizeof(val), sizeof val);return 0;
}

在这里插入图片描述

但是!!!sizeof 在计算变量所占空间大小时,括号可以省略,而计算类型(模子)大小时不能省略。

在这里插入图片描述

signed、unsigned 关键字

直接上代码

int main()
{char a[1000];int i;for(i=0; i<1000; i++){a[i] = -1-i;}printf("%d",strlen(a));return 0;
}

乍一看,很简单,再一看,嘶~~~好像要思考一下,看到负数就想到负数在计算机中的存储形式,以补码的形式存储,最高位符号位为1。char类型占1字节即8比特位,所以是从-128~127一共256个数,但是strlen是以\0为结尾,所以一共255个数。

正数的原码反码补码都是一样,没什么好说,而负数的存储是以补码的形式存储,所以负数的存储首先就需要将源码转换为补码,然后在将其存入到内存中。注意!!!!就是这么一个过程,先转换,然后存入。所以我数据的存储是不关注你存放在哪里,存放好之后我能够读取出来就行,所以signed和unsigned两种类型的区别就是我是否关注符号位,然后进行不同的读取。

正数负数我该怎么存就怎么存,有无符号是你读取的方式,读出来多少是你的事

再来一段代码

int i = -20;
unsigned j = 10;

i+j 的值为多少?为什么?

此时的结果随着你读取的方式而变化,如果使用printf(“%d”, i + j)的话,结果为-10。当使用printf(“%u”, i + j)的话,结果为42亿多。

static关键字

static关键字在修饰变量时有两种情况:修饰全局变量,修饰局部变量

修饰全局变量:被修饰的全局变量也称静态全局变量,改变了该全局变量的作用域,使得该变量只在声明它的源文件中可见,而在其他源文件中是不可见的

修饰局部变量:生命周期扩展到整个程序的执行期间,但作用域仍限于声明它的函数内部,整个执行期间只初始化一次,且默认为0

修饰函数:函数的作用域限定在声明它的文件内部,使得该函数对于其他文件是不可见的

void function() 
{static int x; // 静态变量x++;printf("x: %d\n", x);
}

abs函数和fabs函数

abs用于整形的绝对值,fabs用于浮点型的绝对值

空结构体占多大空间?

struct empty
{};int main()
{empty emp;printf("empty struct size : %d\n", sizeof(emp));return 0;
}

一般而言空结构体的大小是给1字节,但是具体是多少还是依编译器。编译器认为任何一种数据类型都有其大小,用它来定义一个变量能够分配确定大小的空间。(vs中直接报错…)

柔性数组

在C99中,结构中的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员,但结构中的柔性数组成员前面必须至少有一个其他成员,且一个结构体只能有一个柔性数组。

柔性数组在定义时动态开辟空间,不影响结构体的大小

struct array1
{int lenth;int arr[];
};struct array2
{int lenth;int *arr;
};int main()
{struct array1 a;struct array2 b;printf("size : %d\n", sizeof(a));printf("size : %d\n", sizeof(b));return 0;
}

在这里插入图片描述

union

union也称联合体或者共用体,顾名思义,就是联合体内所有数据共用一块内存,这块内存大小是成员类型最大的字节数。

可以用union来验证大小端

union U
{int a;char b;
};int main()
{union U u1;u1.a = 1;  //0x0001;if (u1.b == 1){printf("小端机\n");}else{printf("大端机\n");}return 0;
}

enum

enum枚举类型允许对一批整形变量进行命名,提高代码可读性

不需要实例化对象

enum Weekday {Monday = 1,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday
};

sizeof枚举类型的大小是多少?

enum类型的大小并不是固定的,enum类型的大小是由编译器来决定的,可能是4字节也可能是8字节,并且还与你给出的值有关

enum Week  //demo1
{day1 = 0x11223344,day2,day3
};
// sizeof(enum Week) = 4
enum Week  //demo2
{day1 = 0x1122334455,day2,day3
};
// sizeof(enum Week) = 8

typedef

给一个已经存在的数据类型(注意:是类型不是变量)取一个别名,而非定义一个新的数据类型

注意:typedef在给类型取别名时,完全继承了原始类型的属性,但是不能和其他类型修饰符进行组合使用来修改这些属性

typedef int int32;
int main()
{// unsigned int32 a = 0; // 错误int32 b = 1;
}    

在这里插入图片描述

取整和取模

整数除法中,C语言的行为规则是向零取整

当求模运算中至少一个操作数为负数时,C语言的求模运算结果的符号由被除数的符号决定。

内存对齐——为什么需要内存对齐?

简要的说,数据按照特定的规则放到对应的地址上就是内存对齐,内存对齐可以增强系统性能,因为对于没有对齐的数据,操作系统读取数据可能需要多次的内存访问,而内存对齐后数据就在对齐边界上,操作系统一次内存访问就可以读取数据,提高性能

在这里插入图片描述

宏定义#define

宏定义的常量或者宏函数都是在预处理阶段直接进行机械替换,因此使用宏函数可以免去函数调用的开销,提高性能。但是定义的这些都没有类型安全检查,并且存在优先级问题,需要谨慎使用

宏的作用域:宏的作用域是在其定义的地方向后

void func1()
{int num = M; //不替换
}
int main()
{#define M 10int num = M; //替换func1();func2();return 0;
}
void func2()
{int num = M; // 替换
}

指针和数组的关系?

指针和数组没有关系!!!指针的大小为4/8字节,数组的大小为(类型 * 数据)

指针存放地址,该地址是数据存放的地址。数组存放数据,只是数组名类似于指针,是数组中第一个元素的地址

指针是一个变量,可以指向任何数据类型,而数组是一个固定长度的数据集合

指针可以被重新赋值指向不同的内存地址,而数组名则不能被重新赋值

向特定地址中写入数据?

指针指向某个地址,如果权限允许,我们可以向该地址中写入数据。一般来说关注的都是数据而不是地址,当想向特定地址写入数据的话那该怎么做呢?

假设向0x12ff7c的地址中写入数据

int main()
{int *p = (int*)0x12ff7c;*p = 10;//又或者 *(int*)0x12ff7c = 10;return 0;
}

#和##

#号:在宏定义中,#号用于将参数转换为字符串字面值。这个过程称为字符串化。当#号放在宏参数前面时,它将该参数转换为一个以双引号包围的字符串字面值

#define STRINGIZE(x) #x
printf("%s\n", STRINGIZE(hello)); // 将输出 "hello"

##号:在宏定义中,##号用于连接两个标识符或符号

#define CONCAT(x, y) x##y
int ab = 10;
printf("%d\n", CONCAT(a, b)); // 将输出 10

##号只能用于连接标识符或符号,不能用于连接字符串或数字

assert是宏而不是函数

    _ACRTIMP void __cdecl _wassert(_In_z_ wchar_t const* _Message,_In_z_ wchar_t const* _File,_In_   unsigned       _Line);#define assert(expression) (void)(                                                       \(!!(expression)) ||                                                              \(_wassert(_CRT_WIDE(#expression), _CRT_WIDE(__FILE__), (unsigned)(__LINE__)), 0) \)

assert只存在于debug版本中,不存在release版本中,assert的作用是定位错误,而不是排除错误

malloc申请0字节空间

申请0字节函数返回的是正常地址,因为函数的返回值规定了返回NULL代表申请失败,而申请0字节是成功的,但是返回的地址是不可以使用的,强制使用会导致未定义行为

malloc除了给到你申请的空间外,还会额外给你更多的空间来存放元信息

函数参数的传递发生在函数调用之前

int addNum(int num1, int num2)
{return num1 + num2;
}int main()
{int ret = addNum(1, 2, 3, 4);printf("ret = %d\n", ret);return 0;
}

在这里插入图片描述

在C语言中,如果函数没有参数,那么对该函数进行传参也是可以,因为参数传递发生在函数调用之前

void Empty()
{}int main()
{Empty(1, 2, "123");return 0;
}

可变参数列表

使用C语言的可变参数列表需要包含<stdarg.h>这个头文件,里面包含有几个宏,例如va_start、va_arg、va_end和va_copy,大致的使用流程:

#include <stdio.h>
#include <stdarg.h>Myadd(int n, ...)
{va_list args; //1. 定义va_list类型变量va_start(args, n); //2. 初始化args变量int sum = 0;for (int i = 0; i < n; i++){sum += va_arg(args, int); //去除参数}va_end(args); //args置空return sum;
}int main()
{int ret1 = Myadd(4, 1, 2, 3, 4);int ret2 = Myadd(3, 2, 3, 4);printf("ret1=%d   ret2=%d\n", ret1, ret2);return 0;
}

其中va_list是typedef的,原型为char*

在这里插入图片描述

其他几个都是宏函数

在这里插入图片描述

    //这个宏通常用于确定参数在堆栈上的对齐方式。	#define _INTSIZEOF(n)          ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1)) #define _ADDRESSOF(v)           (&(v))#define __crt_va_start_a(ap, v) ((void)(ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v)))#define __crt_va_arg(ap, t)     (*(t*)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)))#define __crt_va_end(ap)        ((void)(ap = (va_list)0))

在这里插入图片描述

    //这个宏通常用于确定参数在堆栈上的对齐方式。	#define _INTSIZEOF(n)          ((sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1)) #define _ADDRESSOF(v)           (&(v))#define __crt_va_start_a(ap, v) ((void)(ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v)))#define __crt_va_arg(ap, t)     (*(t*)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)))#define __crt_va_end(ap)        ((void)(ap = (va_list)0))

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++进阶】AVL树(来自二叉搜索树的复仇)

&#x1fa90;&#x1fa90;&#x1fa90;欢迎来到程序员餐厅&#x1f4ab;&#x1f4ab;&#x1f4ab; 主厨&#xff1a;邪王真眼 主厨的主页&#xff1a;Chef‘s blog 所属专栏&#xff1a;c大冒险 总有光环在陨落&#xff0c;总有新星在闪烁 引言&#xff1a; 之前我们学…

从0配置React

在本地安装和配置React项目&#xff0c;您可以使用create-react-app这个官方推荐的脚手架工具。以下是安装React的步骤&#xff0c;包括安装Node.js、使用create-react-app创建React应用&#xff0c;以及启动开发服务器。 下载安装node.js运行以下命令&#xff0c;验证Node.js…

字符分类函数

字符分类函数 C语言中有⼀系列的函数是专门做字符分类的&#xff0c;也就是⼀个字符是属于什么类型的字符的。这些函数的使用都需要包含⼀个头文件是 ctype.h 这些函数的使用方法非常类似&#xff0c;我们就讲解⼀个函数的事情&#xff0c;其他的非常类似&#xff1a; int i…

用Vue仿了一个类似抖音的App

大家好&#xff0c;我是 Java陈序员。 今天&#xff0c;给大家介绍一个基于 Vue3 实现的高仿抖音开源项目。 关注微信公众号&#xff1a;【Java陈序员】&#xff0c;获取开源项目分享、AI副业分享、超200本经典计算机电子书籍等。 项目介绍 douyin —— 一个基于 Vue、Vite 实…

【软件工程】详细设计(二)

这里是详细设计文档的第二部分。前一部分点这里 4. 学生端模块详细设计 学生端模块主要由几个组件构成&#xff1a;学生登录界面&#xff0c;成绩查询界面等界面。因为学生端的功能相对来说比较单一&#xff0c;因此这里只给出两个最重要的功能。 图4.1 学生端模块流程图 4.…

女大三抱金砖?看完这篇起诉状就明白:猜疑乃婚姻之大敌

女大三抱金砖&#xff1f;看完这篇起诉状就明白&#xff1a;猜疑乃婚姻之大敌 阿勇与阿芳&#xff0c;一对年过四十的夫妻&#xff0c;且有一对已成年的儿女&#xff0c;如今走到了婚姻的尽头。原告阿勇指控双方感情早已破裂&#xff0c;受父母包办婚姻影响&#xff0c;两人经常…

应用方案D78040场扫描电路,偏转电流可达1.7Ap-p,可用于中小型显示器

D78040是一款场扫描电路&#xff0c;偏转电流可达1.7Ap-p&#xff0c;可用于中小型显示器。 二 特 点 1、有内置泵电源 2、垂直输出电路 3、热保护电路 4、偏转电流可达1.7Ap-p 三 基本参数 四 应用电路图 1、应用线路 2、PIN5脚输出波形如下&#xff1a;

makefile01

什么是makefile Makefile 文件描述了 Linux 系统下 C/C 工程的编译规则&#xff0c;它用来自动化编译 C/C 项目。一旦写编写好 Makefile 文件&#xff0c;只需要一个 make 命令&#xff0c;整个工程就开始自动编译&#xff0c;不再需要手动执行 GCC 命令。一个中大型 C/C 工程…

Unity类银河恶魔城学习记录12-2 p124 Character Stats UI源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili UI_Statslot.cs using System.Collections; using System.Collections.Gen…

云计算的安全需求

目录 一、概述 二、云安全服务基本能力要求 三、信息安全服务&#xff08;云计算安全类&#xff09;资质要求 3.1 概述 3.2 资质要求内容 3.2.1 组织与管理要求 3.2.2 技术能力要求 四、云安全主要合规要求 4.1 安全管理机构部门的建立 4.2 安全管理规范计划的编制 4…

回溯算法|78.子集

力扣题目链接 class Solution { private:vector<vector<int>> result;vector<int> path;void backtracking(vector<int>& nums, int startIndex) {result.push_back(path); // 收集子集&#xff0c;要放在终止添加的上面&#xff0c;否则会漏掉自…

linux 回收站机制(笔记)

Linux下回收站机制https://mp.weixin.qq.com/s/H5Y8VRcaOhFZFXzR8yQ7yg 功能 &#xff1a;设立回收站&#xff0c;并且可定时清空回收站。 一、建议将alias rm 改成别的。 比如alias rmm &#xff0c;同时修改rm -rf ~/.trash/* 改成 rmm -rf ~/.trash/* 不然影响rm 的正常使…