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 10
    int 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))

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

TCP/IP通信demo

TCP/IP&#xff08;Transmission Control Protocol/Internet Protocol&#xff09;是一组通信协议&#xff0c;用于在网络上实现数据传输。它是互联网的基础&#xff0c;也被广泛用于局域网和广域网中。TCP/IP协议族由多个协议组成&#xff0c;其中最重要的是TCP和IP。 IP&…

JAVAEE之Spring, Spring Boot 和Spring MVC的关系以及区别

1.Spring, Spring Boot 和Spring MVC的关系以及区别 Spring: 简单来说, Spring 是⼀个开发应⽤框架&#xff0c;什么样的框架呢&#xff0c;有这么⼏个标签&#xff1a;轻量级、⼀ 站式、模块化&#xff0c;其⽬的是⽤于简化企业级应⽤程序开发 Spring的主要功能: 管理对象&am…

【2024红明谷】三道Web题目的记录

红明谷 文章目录 红明谷Web1 | SOLVED LaterWeb2 | UNSOLVEDWeb3 | SOLVED 容器已经关咯&#xff0c;所以有些场景只能靠回忆描述啦&#xff0c;学习为主&#xff0c;题目只是一个载体~ 本次比赛学习为主&#xff0c;确实再一次感受到久违的web题目的魅力了&#xff0c;可能也是…

【SpringCloud】Ribbon 负载均衡

目 录 一.负载均衡原理二.源码跟踪1. LoadBalancerIntercepor2. LoadBalancerClient3. 负载均衡策略 IRule4. 总结 三.负载均衡策略1.负载均衡策略2.自定义负载均衡策略 四.饥饿加载 在 order-service 中 添加了 LoadBalanced 注解&#xff0c;即可实现负载均衡功能&#xff0c…

网络安全基础之网络协议与安全威胁

OSI(OpenSystem Interconnect)&#xff0c;即开放式系统互联。 一般都叫OSI参考模型&#xff0c;是ISO(国际标准化组织)组织在1985年研究的网络互联模型。 网络协议的简介&#xff1a; 定义&#xff1a;协议是网络中计算机或设备之间进行通信的一系列规则集合。 什么是规则?…

Leetcode442. 数组中重复的数据

Every day a Leetcode 题目来源&#xff1a;442. 数组中重复的数据 解法1&#xff1a;将元素交换到对应的位置 由于给定的 n 个数都在 [1,n] 的范围内&#xff0c;如果有数字出现了两次&#xff0c;就意味着 [1,n] 中有数字没有出现过。 因此&#xff0c;我们可以尝试将每一…

【Pt】马灯贴图绘制过程 04-玻璃脏迹

目录 效果 步骤 一、透明玻璃 二、烟熏痕迹 三、粗糙 四、浮尘 效果 步骤 一、透明玻璃 1. 打开纹理集设置&#xff0c;着色器链接选择“新的着色器链接” 在着色器设置中可以看到此时名称为“Main shader &#xff08;Copy&#xff09;” 这里修改名称为“玻璃” 在…

redis群集有三种模式

目录 redis群集有三种模式 redis群集有三种模式 分别是主从同步/复制、哨兵模式、Cluster ●主从复制&#xff1a;主从复制是高可用Redis的基础&#xff0c;哨兵和集群都是在主从复制基础上实现高可用的。主从复制主要实现了数据的多机备份&#xff0c;以及对于读操作的负载均…

C++ 静态库与动态库的生成和使用:基于 VS Studio 生成 newmat 矩阵库的静态库与动态库

文章目录 Part.I IntroductionChap.I 预备知识Chap.II 静态库与动态库区分 Part.II 静态库的生成与使用 (newmat)Chap.I 生成静态库Chap.II 使用静态库 Part.III 动态库的生成与使用 (newmat)Chap.I 生成动态库Chap.II 使用动态库 Part.IV 文件内容Chap.I test.cpp (静态库)Cha…

5G智慧地铁数字孪生可视化平台,推进铁路行业数字化转型

随着科技的快速发展&#xff0c;5G智慧地铁数字孪生可视化平台正逐渐成为铁路行业数字化转型的重要推动力。巨蟹数科数字孪生平台集成了5G通信技术、大数据分析、云计算和人工智能等先进技术&#xff0c;通过构建数字孪生模型&#xff0c;实现对地铁运营全过程的实时监控、预测…

rocketmq的运维

1. admintool创建topic的时候 -o 的用法含义 https://rocketmq.apache.org/zh/docs/4.x/producer/03message2/ 有关orderMessageEnable和returnOrderTopicConfigToBroker的设置可以参考 https://blog.csdn.net/sdaujsj1/article/details/115741572 -c configFile通过-c命令指…

大模型prompt技巧——思维链(Chain-of-Thought)

1、Zero-shot、One-shot、Few-shot 与fintune prompt的时候给出例子答案&#xff0c;然后再让模型回答。 2、zero-shot-CoT “Let’s think step by step”有奇迹效果 3、多数投票提高CoT性能——自洽性&#xff08;Self-consistency&#xff09; 多个思维链&#xff0c;然后取…

【深度学习】sdwebui的token_counter,update_token_counter,如何超出77个token的限制?对提示词加权的底层实现

文章目录 前言关于token_counter关于class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing)如何超出77个token的限制&#xff1f;对提示词加权的底层实现Overcoming the 77 token limit in diffusers方法1 手动拼方法2 compel 问询、帮助请看&#xff1a; 前言 …

跟着Kimi Chat学习提示工程Prompt Engineering!让AI更高效地给你打工!

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;所以创建了“AI信息Gap”这个公众号&#xff0c;专注于分享AI全维度知识…

【JavaWeb】百度地图API SDK导入

百度地图开放平台 | 百度地图API SDK | 地图开发 (baidu.com) 登录注册&#xff0c;创建应用&#xff0c;获取AK 地理编码 | 百度地图API SDK (baidu.com) 需要的接口一&#xff1a;获取店铺/用户 所在地址的经纬度坐标 轻量级路线规划 | 百度地图API SDK (baidu.com) 需要的…

Fastjson 1.2.47 远程命令执行漏洞复现分析环境

Fastjson 1.2.47 远程命令执行漏洞 1、靶机环境安装 1.1、虚机机linux环境参数 1、操作系统&#xff1a;CentOS Linux release 7.4.1708 (Core) 2、IP&#xff1a;192.168.127.1321.1、docker与docker compose安装 1.2、下载https://github.com/vulhub/vulhub/tree/master/…

Golang | Leetcode Golang题解之第8题字符串转换整数atoi

题目&#xff1a; 题解&#xff1a; func myAtoi(s string) int {abs, sign, i, n : 0, 1, 0, len(s)//丢弃无用的前导空格for i < n && s[i] {i}//标记正负号if i < n {if s[i] - {sign -1i} else if s[i] {sign 1i}}for i < n && s[i] >…

java数据结构与算法刷题-----LeetCode417. 太平洋大西洋水流问题

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 深度优先遍历 深度优先遍历 解题思路&#xff1a;时间复杂度O( …

【计算机视觉】四篇基于Gaussian Splatting的SLAM论文对比

本文对比四篇论文&#xff1a; [1] Gaussian Splatting SLAM [2] SplaTAM: Splat, Track & Map 3D Gaussians for Dense RGB-D SLAM [3] Gaussian-SLAM: Photo-realistic Dense SLAM with Gaussian Splatting [4] GS-SLAM: Dense Visual SLAM with 3D Gaussian Splatting …

RTX RTOS 操作实例分析之---线程(thread)

0 Preface/Foreword 1 线程&#xff08;thread&#xff09; 1.1 线程定义 1.1.1 USE_BASIC_THREADS&#xff08;宏定义&#xff09; 经过以上步骤&#xff08;makefile包含&#xff09;&#xff0c;USE_BASIC_THREADS在编译阶段被定义到相应的模块中。 1.1.2 定义线程ID变量…