当前位置: 首页 > article >正文

指针的进化—sizeof和strlen对比(字符串和字符数组的区分)

1.前言

        如果你对各个数组的内容存放是什么没有个清晰的概念,对指针偏移之后的数量算不出来或者模棱两可,那么本篇就来详细介绍sizeof和strlen来具象化的显示数组的内容存放了多少内容,偏移量变化后的变化,这个数组进行运算后会不会构成越界访问......看完这篇你就懂了。

2.sizeof和strlen的对比

        sizeof,是关键字,它只计算变量所占的内存空间大小,不在乎内存存放的内容,要是把类型放进去,就会计算该类型所创建的变量所占内存的大小。需要注意的是,sizeof里面的操作数,不会真的参与计算。

        strlen,是库函数,是专门求字符串长度的,即从首字符开始,计算到“\0”之前的字符串个数,要是所创建字符串没有带有"\0",那么极有可能会存在一个问题:越界访问。因为strlen会一直往后访问直接遇到"\0"字符为止。

        这是它的函数形式。

size_t strlen ( const char * str );
strlen库函数

2.1 sizeof

#inculde <stdio.h>
int main()
{int a = 10;printf("%d\n", sizeof(a));printf("%d\n", sizeof a);printf("%d\n", sizeof(int));return 0;
}

2.2 strlen

strlen 计算的是字符串的长度,计算'\0'之前的,是库函数
int main()
{char arr1[3] = { 'a', 'b', 'c' };char arr2[] = "abc";printf("%d\n", strlen(arr1));//随机printf("%d\n", strlen(arr2));//3printf("%d\n", sizeof(arr1));//3printf("%d\n", sizeof(arr2));//4return 0;
}

         arr1是字符数组,不带'\0',\0'的位置是随机的,在vs2022,x86的情况下,第一个打印的是随机值,arr2数组是个字符串数组,自带'\0'字符。不相信的话可以按一下F10,打开监视窗口看看。

        那么既然strlen是返回的是开头到null终止符'\0'之前,arr1是没有'\0'的,看作一个npc一样随机刷新的,所以是随机值。arr2是有的,返回abc三个字符,sizeof返回的是内存空间大小。abc'\0',4个字符,每个1个字节,所以就是4。

arr1和arr2的数组内容

3.数组和指针题目解析

        了解,清楚sizeof和srlen的区别与使用,那么本篇文章的重点就来了,就是在不同数组类型下sizeof和strlen显示数组有多少内容,其内在还是熟悉对数组的内容存放是什么,偏移量的变化,是否构成越界访问了如指掌。上练习题,看代码来说话。

3.1一维数组 

        这里首先要说明2个规则:

  1. 数组名表示数组首元素的地址
  2. 以下两种情况下除外:

        数组名单独放在sizeof内部,表示计算的是整个数组的大小。

        &数组名,表示为取出整个数组的地址。

int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a+0));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(a[1]));
printf("%d\n",sizeof(&a));
printf("%d\n",sizeof(*&a));
printf("%d\n",sizeof(&a+1));
printf("%d\n",sizeof(&a[0]));
printf("%d\n",sizeof(&a[0]+1));

         依次来看,(a)数组名单独放在siezof内部,计算整个数组大小,这是个一维整形数组,4个元素,每个元素int类型,4个字节,4*4=16。

        第二个,(a+0) a不是单独放在内部,即使是+0也不算是单独放置,所以是首元素的地址+0,是1这个元素地址的大小,是地址,地址是指针,大小就是4/8,32位是4个字节,64位是8个字节。

        第三个,(*a)数组名没有单独放,是首元素地址,对它解引用,得到第一个元素的内容1,1是个整形,大小是4。

        第四个,(a+1)根据第二个类推,首元素地址+1,是第二个元素的地址的大小,是地址,大小就是4/8。

        第五个,很简单吧,a[1]不就是下标为1的元素2吗,对它计算大小,肯定是4了。

        第六个,(&a)对数组名进行取地址,取出整个数组的地址,计算大小,是地址,大小也是4/8.

        第七个,(*&a)取地址后解引用,取出整个数组地址,加上*,那就是得到整个数组的内容了,计算它的大小,和第一个一样,4*4=16。

        第八个,&a是整个元素的地址,&a+1,跳过这个数组到下一个数组的地址,指向数组后面的空间。这里没有构成非法访问,虽然指向的是没有初始化的空间,但是我们没有对他进行实际操作,只是访问了一下而已。

        第九个,&a[0],对第一个元素取地址,得到第一个元素的地址,是地址大小就是4/8。

        第十个,&a[0]+1,对第二个元素取地址,是地址大小就是4/8。

        如下图,在x86环境下,指针的大小是4位的,那么但凡涉及地址大小的,其实也就是指针大小,2,4,6,8,9,10都是计算指针大小,所以都是4,和我们上面的解释一样。

        在64位环境下就比较清楚了,无论什么类型的指针,大小都是8个字节,所以 2,4,6,8,9,10。是8,计算元素大小是4,整个数组大小是16,图例多了一个元素,所以显示20。

3.2字符数组

        讨论完一维整形数组,那么接下来就讨论以下字符数组,这里会分两种,一种是字符数组,一种是字符串。

3.2.1 字符串和字符数组区别

        这两者虽然只一字相差,但却是区别甚大。字符数组与字符串在本质上的区别就在于“字符串结束标志”的使用。字符数组中的每个元素都可以存放任意的字符,最后一个字符可以是‘\0’,也可以不是。但作为字符串使用时,就必须以‘\0’结束,因为很多有关字符串的处理都要以‘\0’作为操作时的辨别标志,缺少这一标志,系统并不会报错,有时甚至可以得到看似正确的运行结果,只会报个警告。但这种潜在的错误可能会导致严重的后果。程序在未遇到'\0'之前,会一直访问,所以会超出空间,形成越界访问

        那么定义字符数组的形式不是唯一的,不同情况,系统会自动或不会补'\0',没有补的话就一定要我们添加才可以,没有添加结束标志的只能看作字符,而不能看作字符串。

(1)所赋值的个数少于数组元素大小时,系统会补'\0'。形成字符串。

char c[10]={‘p’,‘r’,‘o’,‘g’,‘r’,‘a’,‘m’};

        当然你不放心也可以自己补上,但是效果是一样的 。

(2)所赋值个数和数组元素一样大。 数组里面7个字符,元素也是7个,就没有空余空间留给'\0' 来存放了。不形成字符串,是个字符数组

char c[7]={‘p’,‘r’,‘o’,‘g’,‘r’,‘a’,‘m’};

(3)当你想用单个字符赋值来决定你的数组大小时,系统是不会给你添加'\0'的,你需要自己添加上去才可以。这里会形成字符串。

char c[ ]={‘p’,‘r’,‘o’,‘g’,‘r’,‘a’,‘m’,’\0’};

         这样子则只会给你申请7个空间,不会预留位置给'\0',那么也就不能作为字符串来使用,只是一个字符数组。

char c[ ]={‘p’,‘r’,‘o’,‘g’,‘r’,‘a’,‘m’};

(4)直接赋值常量字符串,这几种都可以,不用人为去添加'\0',但是得存放空间足够大,系统会自动补上的。

char str1[15]={“I am happy”};

        以字符串常量赋值来决定数组大小,10个字符加一个'\0',一共11个字符大小。 

char str1[]=“I am happy”;

        可以去掉花括号 

char str1[15]=“I am happy”;

        但是下面这个定义就错,虽然系统会自动补'\0        ',但是因为空间不够,没有存放'\0'的位置,也构不成字符串。

char str3[10]=“I am happy”;

     3.2.2 字符数组

  来看看例题:

         一组是sizeof,一组是strlen,注意这里是没有写明数组大小,也没有看到有'\0'字符,所以构不成字符串。那么根据规则来仔细思考吧。

第一组 第一个,根据规则和sizeof的特点,计算的是整个数组的大小,共6个,每个1个字节。

            第二个,arr + 0是数组首元素的地址,大小是4/8。

            第三个,*arr是数组的首元素,计算的是首元素的大小-1字节。

            第四个,arr[1]第二个元素大小,当然是1了。

            第五个,取出的数组的地址,数组的地址也是地址,是地址大小就是4/8

            第六个,&arr+1是跳过整个,指向数组后边空间的地址,4/8。

            第七个,&arr[0] + 1是数组第二个元素的地址,是地址4/8字节。

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));

这里就以注释来说明了 。

char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", strlen(arr));//随机值,没有结束标识符,会一直访问直到出现'\0'
printf("%d\n", strlen(arr+0));//随机值
printf("%d\n", strlen(*arr));//strlen('a')->strlen(97),非法访问-err
printf("%d\n", strlen(arr[1]));//'b'==98,和上面的代码类似,是非法访问 - err
printf("%d\n", strlen(&arr));//&arr虽然是数组地址,但是也是从数组起始位置开始的,计算的还是随机值
printf("%d\n", strlen(&arr+1));//&arr是数组的地址,&arr+1是跳过整个数组的地址,求字符串长度也是随机值
printf("%d\n", strlen(&arr[0]+1));//&arr[0] + 1是第二个元素的地址,是'b'的地址,求字符串长度也是随机值

       由此可见,在以单个字符来赋值字符数组的时候,'\0'的添加是很有必要的,很可能就会造成越界访问导致随机值的出现。那么接下来就看看字符串。

3.2.3 字符串

        字符串,系统是自动补'\0'的,而且没有写明数组大小,所以是以字符串常量来决定数组大小的。

char arr[] = "abcdef";//数组是7个元素
printf("%d\n",strlen(arr));//6,arr是数组首元素的地址,strlen从首元素的地址开始统计\0之前出现的字符个数
printf("%d\n", strlen(arr+0));//arr + 0是数组首元素的地址,同第一个,结果是6
printf("%d\n", strlen(*arr));//*arr是'a',是97,传给strlen是一个非法的地址,造成非法访问
printf("%d\n", strlen(arr[1]));//同上
printf("%d\n",strlen(&arr));//取出的是整个数组的地址,从首元素开始算,一共6个
printf("%d\n", strlen(&arr+1));//&arr + 1是跳过数组后的地址,是没有被赋值的,统计字符串的长度是随机值
printf("%d\n", strlen(&arr[0]+1));//&arr[0]+1是b的地址,从第二个字符往后统计字符串的长度,大小是5
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));//7 - 数组名单独放在sizeof内部,计算的是数组的总大小,单位是字节
printf("%d\n", sizeof(arr+0));//arr+0是首元素的地址,大小是4/8
printf("%d\n", sizeof(*arr));//*arr是数组首元素,大小是1字节
printf("%d\n", sizeof(arr[1]));//arr[1]是数组的第二个元素,大小是1字节
printf("%d\n", sizeof(&arr));//&arr是数组的地址,是4/8字节
printf("%d\n", sizeof(&arr+1));//&arr + 1是跳过整个数组的地址,是4/8字节
printf("%d\n", sizeof(&arr[0]+1));//&arr[0] + 1是第二个元素的地址,是4/8字节

 3.3.4 把字符常量存放在指针

char *p = "abcdef";
printf("%d\n", sizeof(p));//p是指针变量,大小就是4/8字节
printf("%d\n", sizeof(p+1));//p + 1是b的地址,就是4/8个字节
printf("%d\n", sizeof(*p));//*p是'a',sizeof(*p)计算的是字符的大小,是1字节
printf("%d\n", sizeof(p[0]));//p[0]->*(p+0) -> *p  就同上一个,1字节
printf("%d\n", sizeof(&p));//&p是二级指针,是指针,大小就是4/8
printf("%d\n", sizeof(&p+1)); //&p + 1是跳过p变量后的地址,4/8字节
printf("%d\n", sizeof(&p[0]+1));//p[0]就是‘a’,&p[0]就是a的地址,+1,就是b的地址,就是4/8
char *p = "abcdef";
printf("%d\n", strlen(p));//6- 求字符串长度
printf("%d\n", strlen(p+1));//p + 1是b的地址,字符串长度从b到f就是5
printf("%d\n", strlen(*p));//err,*p是'a'
printf("%d\n", strlen(p[0]));//err
printf("%d\n", strlen(&p));&p拿到的是p这个指针变量的起始地址,从这里开始求字符串长度完全是随机值
printf("%d\n", strlen(&p+1));//&p+1是跳过p变量的地址,从这里开始求字符串长度也是随机值
printf("%d\n", strlen(&p[0]+1));//&p[0] + 1是b的地址,从b的地址向后数字符串的长度是5

3.3 二维数组

        二维数组需要注意的在sizeof中,a表示什么,a[0]表示什么,a[0][0]表示什么,第一个,单独放,表示整个数组的大小,没有什么问题,第二个呢,是表示第一行的大小还是什么?a[0][0]表示的是数组第一行第一个元素应该也是没问题。

        想不明白的话,简单,用代码测一下不就能倒推了吗

int a[3][4] = {0};
printf("%d\n",sizeof(a));//48 
printf("%d\n",sizeof(a[0][0]));//4
printf("%d\n",sizeof(a[0]));//16
printf("%d\n",sizeof(a[0]+1));//4
printf("%d\n",sizeof(*(a[0]+1)));//4
printf("%d\n",sizeof(a+1));//4
printf("%d\n",sizeof(*(a+1)));//16
printf("%d\n",sizeof(&a[0]+1));//4
printf("%d\n",sizeof(*(&a[0]+1)));//16
printf("%d\n",sizeof(*a));//16
printf("%d\n",sizeof(a[3]));//16

        由显示可以看出,a[0]是二维数组中第一行的数组名,数组名是首元素地址,规则是不变的,a[0]单独放在sizeof里面,求的是整个第一行数组的大小,16个字节;而第四个a[0]作为第一行的数组名,没有单独放在sizeof内部,没有取地址,表示的就是数组首元素的地址,那就是第一行第一个元素a[0][0]的地址,a[0]+1就是第一行第二个元素的地址,是地址就是4/8个字节。其他应该都是比较熟悉的了。

        注意最后一个,感觉是越界访问了,其实没有,如果数组存在第四行,a[3]就是第四行的数组名,数组名单独放在sizeof内部,计算的是第四行的大小。

再次强调下数组名的意义:

        1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。

        2. &数组名,这⾥的数组名表示整个数组,取出的是整个数组的地址。

        3. 除此之外所有的数组名都表示首元素的地址。  

4.总结

        诸如上述的各种环境各种数组下的练习题,需要时不时就去翻看,复习,最好是不同形式的代码都手撕一遍代码,这样有助于我们复习,增加印象。

        不是常有一句话吗,自己写的代码,比较复杂的情况下,如果你没有经常看,甚至没有注释解释,第一天写完你的代码你能看懂,天也能看懂,三天,五天后,只有天知道了。虽然这是个网上的玩笑话,但是我一开始也会懒得写注释,导致一星期后我看着我好久前的代码迷惑不已,还得重新思考,然后我就开始不偷懒,勤快点好,良好的习惯需要去养成:

        一是要加注释,勤注释,增加自己理解,方便自己复习。也方便日后自己要去修改很早之前的代码的时候,能看懂自己当初写了啥是吧。二是要形成良好的书写规范,便于自己,也方便别人观摩,莫一天别人看到你的代码感到惊叹,也是一件好事呀,最后的最后祝大家新年快乐,新的一年在技术上又突飞猛进!

相关文章:

指针的进化—sizeof和strlen对比(字符串和字符数组的区分)

1.前言 如果你对各个数组的内容存放是什么没有个清晰的概念&#xff0c;对指针偏移之后的数量算不出来或者模棱两可&#xff0c;那么本篇就来详细介绍sizeof和strlen来具象化的显示数组的内容存放了多少内容&#xff0c;偏移量变化后的变化&#xff0c;这个数组进行运算后会不会…...

TensorFlow简单的线性回归任务

如何使用 TensorFlow 和 Keras 创建、训练并进行预测 1. 数据准备与预处理 2. 构建模型 3. 编译模型 4. 训练模型 5. 评估模型 6. 模型应用与预测 7. 保存与加载模型 8.完整代码 1. 数据准备与预处理 我们将使用一个简单的线性回归问题&#xff0c;其中输入特征 x 和标…...

【memgpt】letta 课程1/2:从头实现一个自我编辑、记忆和多步骤推理的代理

llms-as-operating-systems-agent-memory llms-as-operating-systems-agent-memory内存 操作系统的内存管理...

6-图像金字塔与轮廓检测

文章目录 6.图像金字塔与轮廓检测(1)图像金字塔定义(2)金字塔制作方法(3)轮廓检测方法(4)轮廓特征与近似(5)模板匹配方法6.图像金字塔与轮廓检测 (1)图像金字塔定义 高斯金字塔拉普拉斯金字塔 高斯金字塔:向下采样方法(缩小) 高斯金字塔:向上采样方法(放大)…...

深入理解Java引用传递

先看一段代码&#xff1a; public static void add(String a) {a "new";System.out.println("add: " a); // 输出内容&#xff1a;add: new}public static void main(String[] args) {String a null;add(a);System.out.println("main: " a);…...

925.长按键入

目录 一、题目二、思路三、解法四、收获 一、题目 你的朋友正在使用键盘输入他的名字 name。偶尔&#xff0c;在键入字符 c 时&#xff0c;按键可能会被长按&#xff0c;而字符可能被输入 1 次或多次。 你将会检查键盘输入的字符 typed。如果它对应的可能是你的朋友的名字&am…...

【Rust自学】15.2. Deref trait Pt.1:什么是Deref、解引用运算符*与实现Deref trait

喜欢的话别忘了点赞、收藏加关注哦&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 15.2.1. 什么是Deref trait Deref的全写是Dereference&#xff0c;就是引用的英文reference加上"de"这个反义前缀&#xff0c…...

图书管理系统 Axios 源码__新增图书

目录 功能介绍 核心代码解析 源码&#xff1a;新增图书功能 总结 本项目基于 HTML、Bootstrap、JavaScript 和 Axios 开发&#xff0c;实现了图书的增删改查功能。以下是新增图书的功能实现&#xff0c;适合前端开发学习和项目实践。 功能介绍 用户可以通过 模态框&#xf…...

吴恩达深度学习——超参数调试

内容来自https://www.bilibili.com/video/BV1FT4y1E74V&#xff0c;仅为本人学习所用。 文章目录 超参数调试调试选择范围 Batch归一化公式整合 Softmax 超参数调试 调试 目前学习的一些超参数有学习率 α \alpha α&#xff08;最重要&#xff09;、动量梯度下降法 β \bet…...

【赵渝强老师】K8s中Pod探针的ExecAction

在K8s集群中&#xff0c;当Pod处于运行状态时&#xff0c;kubelet通过使用探针&#xff08;Probe&#xff09;对容器的健康状态执行检查和诊断。K8s支持三种不同类型的探针&#xff0c;分别是&#xff1a;livenessProbe&#xff08;存活探针&#xff09;、readinessProbe&#…...

如何对系统调用进行扩展?

扩展系统调用是操作系统开发中的一个重要任务。系统调用是用户程序与操作系统内核之间的接口,允许用户程序执行内核级操作(如文件操作、进程管理、内存管理等)。扩展系统调用通常包括以下几个步骤: 一、定义新系统调用 扩展系统调用首先需要定义新的系统调用的功能。系统…...

ChatGPT与GPT的区别与联系

ChatGPT 和 GPT 都是基于 Transformer 架构的语言模型&#xff0c;但它们有不同的侧重点和应用。下面我们来探讨一下它们的区别与联系。 1. GPT&#xff08;Generative Pre-trained Transformer&#xff09; GPT 是一类由 OpenAI 开发的语言模型&#xff0c;基于 Transformer…...

安卓(android)订餐菜单【Android移动开发基础案例教程(第2版)黑马程序员】

一、实验目的&#xff08;如果代码有错漏&#xff0c;可查看源码&#xff09; 1.掌握Activity生命周的每个方法。 2.掌握Activity的创建、配置、启动和关闭。 3.掌握Intent和IntentFilter的使用。 4.掌握Activity之间的跳转方式、任务栈和四种启动模式。 5.掌握在Activity中添加…...

Python安居客二手小区数据爬取(2025年)

目录 2025年安居客二手小区数据爬取观察目标网页观察详情页数据准备工作&#xff1a;安装装备就像打游戏代码详解&#xff1a;每行代码都是你的小兵完整代码大放送爬取结果 2025年安居客二手小区数据爬取 这段时间需要爬取安居客二手小区数据&#xff0c;看了一下相关教程基本…...

happytime

happytime 一、查壳 无壳&#xff0c;64位 二、IDA分析 1.main 2.cry函数 总体&#xff1a;是魔改的XXTEA加密 在main中可以看到被加密且分段的flag在最后的循环中与V6进行比较&#xff0c;刚好和上面v6数组相同。 所以毫无疑问密文是v6. 而与flag一起进入加密函数的v5就…...

深度学习 DAY3:NLP发展史

NLP发展史 NLP发展脉络简要梳理如下&#xff1a; (远古模型&#xff0c;上图没有但也可以算NLP&#xff09; 1940 - BOW&#xff08;无序统计模型&#xff09; 1950 - n-gram&#xff08;基于词序的模型&#xff09; (近代模型&#xff09; 2001 - Neural language models&am…...

前端知识速记:节流与防抖

前端知识速记&#xff1a;节流与防抖 什么是防抖&#xff1f; 防抖是一种控制事件触发频率的方法&#xff0c;通常用于处理用户频繁触发事件的场景。防抖的核心思想是将多个连续触发事件合并为一个事件&#xff0c;以减少执行次数。它在以下场景中特别有效&#xff1a; 输入…...

家居EDI:Hom Furniture EDI需求分析

HOM Furniture 是一家成立于1977年的美国家具零售商&#xff0c;总部位于明尼苏达州。公司致力于提供高品质、时尚的家具和家居用品&#xff0c;满足各种家庭和办公需求。HOM Furniture 以广泛的产品线和优质的客户服务在市场上赢得了良好的口碑。公司经营的产品包括卧室、客厅…...

【3】阿里面试题整理

[1]. ES架构&#xff0c;如何进行路由以及选主 路由&#xff1a;在Elasticsearch&#xff08;ES&#xff09;中&#xff0c;默认的路由算法是基于文档的_id。具体来说&#xff0c;Elasticsearch会对文档的_id进行哈希计算&#xff0c;然后对分片数量取模&#xff0c;以确定该文…...

【08-飞线和布线与输出文件】

导入网表后 1.复制结构图(带板宽的) 在机械一层画好外围线 2.重新定义板子形状(根据选则对象取定义) 选中对象生成板子线条形状 3.PCB和原理图交叉选择模式 过滤器选择原理图里的元器件 过滤器"OFF",只开启Componnets,只是显示元器件 4. 模块化布局 PCB高亮元…...

python 从知网的期刊导航页面抓取与农业科技相关的数据

要从知网的期刊导航页面抓取与农业科技相关的数据&#xff0c;并提取《土壤学报》2016年06期的结果&#xff0c;可以使用requests库来获取网页内容&#xff0c;BeautifulSoup库来解析HTML。由于知网页面结构可能会发生变化&#xff0c;在实际使用中&#xff0c;需要根据页面结构…...

【单细胞第二节:单细胞示例数据分析-GSE218208】

GSE218208 1.创建Seurat对象 #untar(“GSE218208_RAW.tar”) rm(list ls()) a data.table::fread("GSM6736629_10x-PBMC-1_ds0.1974_CountMatrix.tsv.gz",data.table F) a[1:4,1:4] library(tidyverse) a$alias:gene str_split(a$alias:gene,":",si…...

机器学习优化算法:从梯度下降到Adam及其变种

机器学习优化算法&#xff1a;从梯度下降到Adam及其变种 引言 最近deepseek的爆火已然说明&#xff0c;在机器学习领域&#xff0c;优化算法是模型训练的核心驱动力。无论是简单的线性回归还是复杂的深度神经网络&#xff0c;优化算法的选择直接影响模型的收敛速度、泛化性能…...

.NET Core 中依赖注入的使用

ASP.NET Core中服务注入的地方 在ASP.NET Core项目中一般不需要自己创建ServiceCollection、IServiceProvider。在Program.cs的builder.Build()之前向builder.Services中注入。在Controller中可以通过构造方法注入服务。 低使用频率的服务 把Action用到的服务通过Action的参…...

XML Schema 数值数据类型

XML Schema 数值数据类型 引言 XML Schema 是一种用于描述 XML 文档结构的语言。它定义了 XML 文档中数据的有效性和结构。在 XML Schema 中,数值数据类型是非常重要的一部分,它定义了 XML 文档中可以包含的数值类型。本文将详细介绍 XML Schema 中常用的数值数据类型,以及…...

【机器学习理论】生成模型和判别模型

生成模型和判别模型是机器学习中两种不同的建模方式。生成模型关注的是联合概率分布 P ( X , Y ) P(X, Y) P(X,Y)&#xff0c;即同时考虑数据 X X X和标签 Y Y Y的关系&#xff1b;判别模型则直接学习条件概率 P ( Y ∣ X ) P(Y|X) P(Y∣X)或决策边界。 生成模型 生成模型的目…...

ZZNUOJ(C/C++)基础练习1031——1040(详解版)

1031 : 判断点在第几象限 题目描述 从键盘输入2个整数x、y值&#xff0c;表示平面上一个坐标点&#xff0c;判断该坐标点处于第几象限&#xff0c;并输出相应的结果。 输入 输入x&#xff0c;y值表示一个坐标点。坐标点不会处于x轴和y轴上&#xff0c;也不会在原点。 输出 输出…...

使用PyTorch实现逻辑回归:从训练到模型保存与性能评估

1. 引入必要的库 首先&#xff0c;需要引入必要的库。PyTorch用于构建和训练模型&#xff0c;pandas和numpy用于数据处理&#xff0c;scikit-learn用于计算性能指标。 import torch import torch.nn as nn import torch.optim as optim import pandas as pd import numpy as …...

【C语言】main函数解析

文章目录 一、前言二、main函数解析三、代码示例四、应用场景 一、前言 在学习编程的过程中&#xff0c;我们很早就接触到了main函数。在Linux系统中&#xff0c;当你运行一个可执行文件&#xff08;例如 ./a.out&#xff09;时&#xff0c;如果需要传入参数&#xff0c;就需要…...

本地部署 DeepSeek 模型并使用 WebUI 调用

概述 本文将详细介绍如何在本地部署 DeepSeek 模型,并通过 WebUI 调用该模型。我们将使用 open-webui 作为 Web 界面工具,展示如何将 DeepSeek 模型集成到 WebUI 中,并提供一个用户友好的交互界面。 环境准备 在开始之前,请确保你的系统满足以下要求: Python 3.11 或更高…...