【C语言系列】深入理解指针(5)
深入理解指针(5)
- 一、sizeof和strlen的对比
- 1.1sizeof
- 1.2strlen
- 1.3sizeof和strlen的对比
- 二、数组和指针笔试题解析
- 2.1 一维数组
- 2.2 字符数组
- 2.2.1代码1:
- 2.2.2代码2:
- 2.2.3代码3:
- 2.2.4代码4:
- 2.2.5代码5:
- 2.2.6代码6:
- 2.3 二维数组
- 三、指针运算笔试题解析
- 3.1题目1:
- 3.2题目2:
- 3.3题目3:
- 3.4题目4:
- 3.5题目5:
- 3.6题目6:
- 3.7题目7:
- 四、总结
- 1. `sizeof`与`strlen`的区别
- 2. 数组和指针的关系
- 3. 字符数组与字符串
- 4. 指针运算
- 总结
一、sizeof和strlen的对比
1.1sizeof
sizeof是单目操作符(绝不是函数!!!),sizeof计算变量所占内存空间的大小的,单位是字节。
如果操作数是类型的话,计算的是使用类型创建的变量所占内存空间的大小。
注: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;}
1.2strlen
strlen是C语言库函数,功能是求字符串长度。
函数原型是:
size_t strlen ( const char * str );
统计的是从strlen函数的参数str中这个地址开始向后,\0之前字符串中字符的个数。
注:strlen 函数会一直向后找 \0 字符,直到找到为止,所以可能存在越界查找。
代码如下:
#include <stdio.h>
int main()
{char arr1[3] = {'a', 'b', 'c'};char arr2[] = "abc";printf("%d\n", strlen(arr1));printf("%d\n", strlen(arr2));printf("%d\n", sizeof(arr1));printf("%d\n", sizeof(arr2));return 0;
}
运行结果如下:
1.3sizeof和strlen的对比
sizeof | strlen |
---|---|
1.sizeof是操作符 | 1.strlen是库函数,使用需要包含头文件string.h |
2.sizeof计算操作数所占内存的大小,单位是字节 | 2.strlen是求字符串长度的,统计的是\0之前字符的个数 |
3.不关注内存中存放什么数据 | 3.关注内存中是否有\0,如果没有\0,就会持续往后找,可能会越界 |
4.sizeof括号中有表达式的话,表达式是不参与计算的!!! |
用代码检验4,代码如下:
#include <stdio.h>
int main()
{
int a = 8;
short s = 4;
printf("%d\n",sizeof(s = a + 2));//2
printf("%d\n",s);//4
return 0;
}
运行结果如下:
那么为什么sizeof中的表达式不计算?
C语言是编译型语言,在编译期这个表达式并不会被执行,sizeof 运算的结果是在编译期间就已知的常数值,并不需要等到运行时才求解。因此,对于其中涉及到的操作数或者操作本身都不需要实际执行。
二、数组和指针笔试题解析
2.1 一维数组
*a == a[0] == *(a + 0)
数组名的理解:数组名是数组首元素(第一个元素)的地址。
但是有2个是例外:1.sizeof(数组名) —— 数组名表示整个数组,计算的是整个数组的大小,单位是字节。
2.&数组名 —— 数组名表示的是整个数组,取出的是整个数组的地址。
除此之外,所有的数组名是数组首元素(第一个元素)的地址。
笔试题代码和解析如下:
#include <stdio.h>
int main()
{
int a[] = {1,2,3,4};//数组有几个元素?//4
printf("%zd\n",sizeof(a));//16
printf("%zd\n",sizeof(a + 0));//a是首元素的地址 —— 类型是int*,a + 0还是首元素的地址,是地址大小就是4/8。
printf("%zd\n",sizeof(*a));//a是首元素的地址,*a是首元素,大小就是4个字节。
printf("%zd\n",sizeof(a + 1));//a是首元素地址,类型是int*,a + 1跳过1个整型,a + 1就是第二个元素的地址,是地址大小就是4/8。
printf("%zd\n",sizeof(a[1]));//a[1]就是第二个元素,大小是4个字节。
printf("%zd\n",sizeof(&a));//&a是数组的地址,数组的地址也是地址,是地址大小就是4/8字节。
printf("%zd\n",sizeof(*&a));//1.*&互相抵消了,等价于sizeof(a),16
//2.&a是数组的地址,类型是int(*)[4],对数组指针解引用访问的是数组,计算的是数组的大小,16
//char* —— 解引用访问的是char
//int* —— 解引用访问的是int
printf("%zd\n",sizeof(&a + 1));//&a + 1是跳过这个数组后的那个位置的地址,是地址大小就是4/8字节。
printf("%zd\n",sizeof(&a[0]));//首元素的地址,大小就是4/8字节。
printf("%zd\n",sizeof(&a[0] + 1));//&a[0] + 1 —— 数组第二个元素的地址,大小就是4/8字节。
return 0;
}
运行结果如下图:
2.2 字符数组
2.2.1代码1:
笔试题代码和解析如下:
#include <stdio.h>
int main()
{
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n",sizeof(arr));//数组名单独放在sizeof内部,计算的是数组的大小,单位为字节,6。
printf("%d\n",sizeof(arr + 0));//arr是数组名表示首元素的地址,arr + 0还是首元素的地址,是地址就是4/8字节。
printf("%d\n",sizeof(*arr));//arr是首元素的地址,*arr就是首元素,大小就是1个字节。
//*arr == arr[0] == *(arr + 0)
printf("%d\n",sizeof(arr[1]));//arr[1]是第二个元素,大小也是1个字节。
printf("%d\n",sizeof(&arr));//&arr是数组的地址,数组的地址也是地址,是地址大小就是4/8个字节。
//&arr —— char(*)[6]
printf("%d\n",sizeof(&arr + 1));//4/8个字节,&arr + 1,跳过整个数组,指向了数组后边的空间。
printf("%d\n",sizeof(&arr[0] + 1));//第二个元素的地址,是地址就是4/8个字节。
return 0;
}
运行结果如下图:
2.2.2代码2:
笔试题代码和解析如下:
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n",strlen(arr));//arr是首元素的地址,数组中没有\0,就会导致越界访问,结果就是随机的。
printf("%d\n",strlen(arr + 0));//arr + 0是数组首元素的地址,数组中没有\0,就会导致越界访问,结果就是随机的。
printf("%d\n",strlen(*arr));//arr是首元素的地址,*arr是首元素,就是'a','a'的ASCII码值是97,就相当于97作为地址传递给了strlen,strlen得到的就是野指针,代码是有问题的。
printf("%d\n",strlen(arr[1]));//arr[1] —— 'b' —— 98,传给strlen函数也是错误的。
printf("%d\n",strlen(&arr));//&arr是数组的地址,起始位置是数组的第一个元素的位置,随机值。
printf("%d\n",strlen(&arr + 1));//随机值。
printf("%d\n",strlen(&arr[0] + 1));//从第二个元素开始向后统计的,得到的也是随机值。
return 0;
}
运行结果如下图:
2.2.3代码3:
笔试题代码和解析如下:
#include <stdio.h>
int main()
{
char arr[] = "abcdef";
printf("%d\n",sizeof(arr));//7,计算的是数组总大小,数组名单独放在sizeof内部。
printf("%d\n",sizeof(arr + 0));//arr表示数组首元素的地址,arr + 0还是首元素的地址,4/8字节。
printf("%d\n",sizeof(*arr));//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是数组的地址,是地址就是4/8字节。
printf("%d\n",sizeof(&arr[0] + 1));//&arr是数组的地址,+1跳过整个数组,还是地址,是地址就是4/8字节。
return 0;
}
运行结果如下图:
2.2.4代码4:
笔试题代码和解析如下:
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = "abcdef";
printf("%d\n",strlen(arr));//6
printf("%d\n",strlen(arr + 0));//arr首元素的地址,arr + 0还是首元素的地址,向后统计在\0之前的字符个数。//6
printf("%d\n",strlen(*arr));//'a' —— 97,出错。
printf("%d\n",strlen(arr[1]));//'b' —— 98.出错。
printf("%d\n",strlen(&arr));//&arr是数组的地址,也是从数组第一个元素开始向后找,6。
printf("%d\n",strlen(&arr + 1));//随机值。
printf("%d\n",strlen(&arr[0] + 1));//5
//&arr —— char(*)[7]
//size_t strlen(const char*s);
return 0;
}
运行结果如下图:
2.2.5代码5:
笔试题代码和解析如下:
#include <stdio.h>
int main()
{
const 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的类型是char*,*p就是char类型了,1个字节。
printf("%d\n",sizeof(p[0]));//1.p[0]->*(p + 0)->*p->'a',大小1个字节。
//1.把常量字符串想象成数组。
//2.p可以理解为数组名,p[0],就是首元素。
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));//4/8,取出首元素的地址,+1是第二个字符的地址。
return 0;
}
运行结果如下图:
2.2.6代码6:
笔试题代码和解析如下:
#include <stdio.h>
#include <string.h>
int main()
{
char*p ="abcdef";
printf("%d\n",strlen(p));//6
printf("%d\n",strlen(p + 1));//5
printf("%d\n",strlen(*p));//*p就是'a' —— 97,err
printf("%d\n",strlen(p[0]));//p[0]->*(p + 0)->*p//err
printf("%d\n",strlen(&p));//&p是指针变量p的地址,和字符串“abcdef”关系就不大了,从p这个指针变量的起始位置开始向后数的,p变量存放的地址是什么,不知道,所以答案是随机值。
printf("%d\n",strlen(&p + 1));//随机值
printf("%d\n",strlen(&p[0] + 1));//5
return 0;
}
运行结果如下图:
2.3 二维数组
二维数组笔试题代码和解析如下:
#include <stdio.h>
int main()
{
int a[3][4] = {0};
printf("%d\n",sizeof(a));//a是数组名,单独放在sizeof内部,计算的是数组的大小,单位是字节 —— 48 = 3*4*sizeof(int)。
printf("%d\n",sizeof(a[0][0]));//a[0][0]第一行第一个元素,大小是4个字节。
printf("%d\n",sizeof(a[0]));//a[0]是第一行的数组名,数组名单独放在sizeof内部了,计算的是数组的总大小16个字节。
printf("%d\n",sizeof(a[0] + 1));//a[0]并没有单独放在sizeof内部,所以这里的数组名a[0]就是数组首元素的地址,即a[0]->&a[0][0],+1后是&a[0][1]的地址,大小是4/8个字节。
printf("%d\n",sizeof(*(a[0] + 1)));//第一行第一个元素,大小是4
printf("%d\n",sizeof(a + 1));//a作为数组名并没有单独放在sizeof内部,a表示数组首元素的地址,是二维数组首元素的地址,也就是第一行的地址,a + 1,跳过一行,指向了第二行,a + 1是第二行的地址,a + 1是数组指针,是地址大小就是4/8个字节。
printf("%d\n",sizeof(*(a + 1)));//1.a + 1是第二行的地址,*(a + 1)就是第二行,计算的是第二行的大小 —— 16。2.*(a + 1) == a[1],a[1]是第二行的数组名,sizeof(*(a + 1))就相当于sizeof(a[1]),意思就是把第二行的数组名单独放在sizeof内部,计算的是第二行的大小。
printf("%d\n",sizeof(&a[0] + 1));//a[0]是第一行的数组名,&a[0]取出的就是数组的地址,就是第一行的地址,&a[0] + 1就是第二行的地址,是地址大小就是4/8字节。
printf("%d\n",sizeof(*(&a[0] + 1)));//对第二行地址解引用,访问的就是第二行,大小是16个字节。
printf("%d\n",sizeof(*a));//a作为数组名并没有单独放在sizeof内部,a表示数组首元素的地址,是二维数组首元素的地址,也就是第一行的地址,*a就是第一行,计算的就是第一行的大小,16个字节。
printf("%d\n",sizeof(a[3]));//a[3]无需真实存在,仅仅通过类型的推断就能算出长度,a[3]是第四行的数组名,单独放在sizeof内部,计算第四行的大小,16个字节。
//sizeof(int);//4
//sizeof(3+5);//4
return 0;
}
运行结果如下图:
三、指针运算笔试题解析
3.1题目1:
指针运算笔试题代码和解析如下:
#include <stdio.h>
int main()
{
int a[5] = {1,2,3,4,5};
int*ptr = (int*)(&a + 1);//&a —— int(*)[5]
printf("%d %d",*(a + 1),*(ptr - 1));//ptr跳过了原来a数组指向下一个位置,*(ptr-1)访问的就是数组a中的5。
return 0;
}
运行结果如下图:
3.2题目2:
在X86(32位)环境下,假设结构体的大小是20个字节,程序输出的结果是什么?
指针运算笔试题代码和解析如下:
#include <stdio.h>
struct Test
{
int Num;
char*PcName;
short sDate;
char cha[2];
short sBa[4];
}*p = (struct Test*)0x100000;//结构体指针+1,跳过一个结构体;整型值+1,就是+1。
//指针+-整数
int main()
{
printf("%p\n",p + 0x1);//0x100000 + 20 -> 00100014
printf("%p\n",(unsigned long)p + 0x1);//0x100000 + 1 ->0x100001 -> 00100001
printf("%p\n",(unsigned int*)p + 0x1);//0x100000 + 4 -> 0x100004 -> 00100004
return 0;
}
运行结果如下图:
3.3题目3:
指针运算笔试题代码和解析如下:
#include <stdio.h>
int main()
{
int a[3][2] = {(0,1),(2,3),(4,5)};//1 3 5//初始化
int*p;
p = a[0];//&a[0][0];
printf("%d",p[0]);//1//*(p + 0) -> *p
return 0;
}
运行结果如下图:
3.4题目4:
假设环境是X86环境,程序的输出结果是什么?
指针运算笔试题代码和解析如下:
#include <stdio.h>
int main()
{//%d —— 是打印有符号的整数
//%p —— 是打印地址的
int a[5][5];//a —— 类型是:int(*)[5]
int(*p)[4];//p —— 类型是:int(*)[4]//p是一个数组指针,p指向的数组是4个整型元素的
p = a;//类型的差异 —— 警告
printf("%p,%d\n",&p[4][2] - &a[4][2],&p[4][2] - &a[4][2]);//FFFFFFFC,-4
return 0;
}
//指针-指针绝对值得到的是指针和指针之间的元素个数
运行结果如下图:
3.5题目5:
指针运算笔试题代码和解析如下:
#include <stdio.h>
int main()
{
int aa[2][5] = {1,2,3,4,5,6,7,8,9,10};
int*ptr1 = (int*)(&aa + 1);
int*ptr2 = (int*)(*(aa + 1));
printf("%d %d",*(ptr1 - 1),*(ptr2 - 1));//10 5
return 0;
}
//*(aa + 1)->aa[1],aa[1]是第二行的数组名,数组名表示首元素的地址。
//aa[1]也是&aa[1][0]
//*(aa + 1)->aa[1],&aa[1]->第二行的地址
//sizeof(aa[1])->计算的是第二行的大小
运行结果如下图:
3.6题目6:
指针运算笔试题代码和解析如下:
#include <stdio.h>
int main()
{
char*a[] = {"work","at","alibaba"};//a是指针数组
char**pa = a;
pa++;
printf("%s\n",*pa);//at//%s是打印字符串,给一个地址,从这个地址向后打印字符串,直到\0
return 0;
}
画图分析:
运行结果如下图:
3.7题目7:
指针运算笔试题代码和解析如下:
#include <stdio.h>
int main()
{
char*c[] = {"ENTER","NEW","POINT","FIRST"};
char**cp[] = {c + 3,c + 2, c + 1,c};
char***cpp = cp;
printf("%s\n",**++cpp);//POINT
printf("%s\n",*--*++cpp + 3);//ER
printf("%s\n",*cpp[-2] + 3);//**(cpp - 2) + 3//ST
printf("%s\n",cpp[-1][-1] + 1);//*c*(cpp-1) - 1//EW
return 0;
}
运行结果如下图:
四、总结
本文深入探讨了C语言中关于sizeof
、strlen
、数组和指针的一些基础概念,并通过代码示例进行了详细的讲解。以下是对主要内容的总结:
1. sizeof
与strlen
的区别
sizeof
是一个运算符,用于计算变量或类型所占的内存空间大小,单位是字节。它与数据存储内容无关,只关注内存的占用。例如,sizeof(int)
会返回一个整数类型的大小,而sizeof(a)
会返回数组a
的总字节数。需要注意的是,sizeof
中的表达式不会被计算,仅仅是编译时确定的常量。
与此不同,strlen
是C标准库中的一个函数,用于计算以'\0'
(空字符)结尾的字符串的长度。它统计的是字符串中的字符个数,而不包括'\0'
字符。因此,strlen
在处理字符串时,必须确保字符串正确地以'\0'
结尾,否则可能导致越界访问。
2. 数组和指针的关系
数组和指针是C语言中常见的概念,它们密切相关。数组名通常被认为是指向数组首元素的指针。通过数组名,可以访问数组的元素,但是数组名和指针在某些情况下也有所不同。例如,sizeof(a)
计算的是整个数组的大小,而sizeof(a + 1)
计算的是数组中某个元素的指针大小。此外,数组名也可以通过&a
表示整个数组的地址,&a[0]
表示数组首元素的地址。
3. 字符数组与字符串
字符数组在内存中的存储方式可能导致不同的行为。在没有'\0'
结尾的情况下,使用strlen
函数可能会导致越界访问,进而产生随机结果。通过具体的代码示例,文章展示了不同数组类型在使用sizeof
和strlen
时的差异,特别是字符数组和字符串常量。
4. 指针运算
指针运算是C语言中强大的功能之一。指针可以进行加减操作,指向内存中的不同位置。通过对数组指针进行运算,可以访问数组中的不同元素。指针间的运算遵循指针类型的大小,比如int*
指针加1时会跳过一个int
类型的大小,指向下一个int
类型的数据。文章通过一系列例子展示了指针和数组在内存中的操作,包括指针的解引用、指针数组的运算等。
总结
本篇文章深入分析了sizeof
、strlen
、数组与指针等概念,并通过一系列代码示例加深了对这些概念的理解。对于初学者来说,掌握这些基础知识是学习C语言的关键。文章不仅揭示了这些基本概念的使用方法,还通过具体例子帮助理解如何避免常见的错误,如越界访问和指针运算中的误解。
相关文章:

【C语言系列】深入理解指针(5)
深入理解指针(5) 一、sizeof和strlen的对比1.1sizeof1.2strlen1.3sizeof和strlen的对比 二、数组和指针笔试题解析2.1 一维数组2.2 字符数组2.2.1代码1:2.2.2代码2:2.2.3代码3:2.2.4代码4:2.2.5代码5&#…...

mysql自连接 处理层次结构数据
MySQL 的自连接(Self Join)是一种特殊的连接方式,它允许一个表与自身进行连接。自连接通常用于处理具有层次结构或递归关系的数据,或者当同一张表中的数据需要相互关联时。以下是几种常见的场景,说明何时应该使用自连接…...

##__VA_ARGS__有什么作用
##__VA_ARGS__ 是 C/C 中宏定义(Macro)的一种特殊用法,主要用于可变参数宏(Variadic Macros)的场景,解决当可变参数为空时可能导致的语法错误问题。以下是详细解释: 核心作用 消除空参数时的多余…...

鸿蒙 router.back()返回不到上个页面
1. 检查页面栈(Page Stack) 鸿蒙的路由基于页面栈管理,确保上一个页面存在且未被销毁。 使用 router.getLength() 检查当前页面栈长度: console.log(当前页面栈长度: ${router.getLength()}); 如果结果为 1,说明没有上…...

深度学习模型蒸馏技术的发展与应用
随着人工智能技术的快速发展,大型语言模型和深度学习模型在各个领域展现出惊人的能力。然而,这些模型的规模和复杂度也带来了显著的部署挑战。模型蒸馏技术作为一种优化解决方案,正在成为连接学术研究和产业应用的重要桥梁。本文将深入探讨模…...

STM32G0B1 ADC DMA normal
目标 ADC 5个通道,希望每1秒采集一遍; CUBEMX 配置 添加代码 #define ADC1_CHANNEL_CNT 5 //采样通道数 #define ADC1_CHANNEL_FRE 3 //单个通道采样次数,用来取平均值 uint16_t adc1_val_buf[ADC1_CHANNEL_CNT*ADC1_CHANNEL_FRE]; //传递…...

<tauri><rust><GUI>基于rust和tauri,在已有的前端框架上手动集成tauri示例
前言 本文是基于rust和tauri,由于tauri是前、后端结合的GUI框架,既可以直接生成包含前端代码的文件,也可以在已有的前端项目上集成tauri框架,将前端页面化为桌面GUI。 环境配置 系统:windows 10 平台:visu…...

模型 冗余系统(系统科学)
系列文章分享模型,了解更多👉 模型_思维模型目录。为防故障、保运行的备份机制。 1 冗余系统的应用 1.1 冗余系统在企业管理中的应用-金融行业信息安全的二倍冗余技术 在金融行业,信息安全是保障业务连续性和客户资产安全的关键。随着数字化…...

Deepseek部署的模型参数要求
DeepSeek 模型部署硬件要求 模型名称参数量显存需求(推理)显存需求(微调)CPU 配置内存要求硬盘空间适用场景DeepSeek-R1-1.5B1.5B4GB8GB最低 4 核(推荐多核)8GB3GB低资源设备部署,如树莓派、旧…...

AI-学习路线图-PyTorch-我是土堆
1 需求 PyTorch深度学习快速入门教程(绝对通俗易懂!)【小土堆】_哔哩哔哩_bilibili PyTorch 深度学习快速入门教程 配套资源 链接 视频教程 https://www.bilibili.com/video/BV1hE411t7RN/ 文字教程 https://blog.csdn.net/xiaotudui…...

[LeetCode]day17 349.两个数组的交集
https://leetcode.cn/problems/intersection-of-two-arrays/description/ 题目描述 给定两个数组 nums1 和 nums2 ,返回它们的交集。 输出结果中的每个元素一定是唯一的。 我们可以不考虑输出结果的顺序 。 示例 1: 输入:nums1 [1,2,2,1…...

axios 发起 post请求 json 需要传入数据格式
• 1. axios 发起 post请求 json 传入数据格式 • 2. axios get请求 1. axios 发起 post请求 json 传入数据格式 使用 axios 发起 POST 请求并以 JSON 格式传递数据是前端开发中常见的操作。 下面是一个简单的示例,展示如何使用 axios 向服务器发送包含 JSON 数…...

linux交叉编译paho-mqtt-c
下载源代码: https://github.com/eclipse-paho/paho.mqtt.c.git 编译: 如果mqtt不需要SSL安全认证,可以直接执行(注意把编译工具链路径改成自己的) cd paho.mqtt.c-1.3.13/ mkdir install # 创建安装目录 mkdir…...

feign Api接口中注解问题:not annotated with HTTP method type (ex. GET, POST)
Bug Description 在调用Feign api时,出现如下异常: java.lang.IllegalStateException: Method PayFeignSentinelApi#getPayByOrderNo(String) not annotated with HTTPReproduciton Steps 1.启动nacos-pay-provider服务,并启动nacos-pay-c…...

安装指定版本的pnpm
要安装指定版本的 pnpm,可以使用以下方法: 方法 1: 使用 pnpm 安装指定版本 你可以通过 pnpm 的 add 命令来安装指定版本: pnpm add -g pnpm<版本号>例如,安装 pnpm 的 7.0.0 版本: pnpm add -g pnpm7.0.0方法…...

【系统设计】Spring、SpringMVC 与 Spring Boot 技术选型指南:人群、场景与实战建议
在 Java 开发领域,Spring 生态的技术选型直接影响项目的开发效率、维护成本和长期扩展性。然而,面对 Spring、SpringMVC 和 Spring Boot 这三个紧密关联的框架,开发者常常陷入纠结:该从何入手?如何根据团队能力和业务需…...

常用数据结构之String字符串
字符串 在Java编程语言中,字符可以使用基本数据类型char来保存,在 Java 中字符串属于对象,Java 提供了 String 类来创建和操作字符串。 操作字符串常用的有三种类:String、StringBuilder、StringBuffer 接下来看看这三类常见用…...

深入Linux系列之进程地址空间
深入Linux系列之进程地址空间 1.引入 那么在之前的学习中,我们知道我们创建一个子进程的话,我们可以在代码层面调用fork函数来创建我们的子进程,那么fork函数的返回值根据我们当前所处进程的上下文是返回不同的值,它在父进程中返…...

HAL库外设宝典:基于CubeMX的STM32开发手册(持续更新)
目录 前言 GPIO(通用输入输出引脚) 推挽输出模式 浮空输入和上拉输入模式 GPIO其他模式以及内部电路原理 输出驱动器 输入驱动器 中断 外部中断(EXTI) 深入中断(内部机制及原理) 外部中断/事件控…...

网络安全-HSTS
什么是HSTS? HTTP严格传输安全协议(HTTP Strict Transport Security,简称:HSTS) 是互联网安全策略机制。网站可以选择使用HSTS策略,来让浏览器强制使用HTTPS与网站进行通信,以减少会话劫持风险。…...

全程Kali linux---CTFshow misc入门(38-50)
第三十八题: ctfshow{48b722b570c603ef58cc0b83bbf7680d} 第三十九题: 37换成1,36换成0,就得到长度为287的二进制字符串,因为不能被8整除所以,考虑每7位转换一个字符,得到flag。 ctfshow{5281…...

HarmonyOS:时间日期国际化
一、使用场景 在不同的国家和文化中,时间和日期格式的表示方法有所不同,使用惯例的不同点包括:日期中年月日的顺序、时间中时分秒的分隔符等。若应用中需展示时间日期,要确保界面以合适的方式显示,以便用户能够理解。 …...

使用miniforge代替miniconda
conda作为Python数据科学领域的常用软件,是对Python环境及相关依赖进行管理的经典工具,通常集成在anaconda或miniconda等产品中供用户日常使用。 但长久以来,conda在很多场景下运行缓慢卡顿、库解析速度过慢等问题也一直被用户所诟病…...

LIMO:少即是多的推理
25年2月来自上海交大、SII 和 GAIR 的论文“LIMO: Less is More for Reasoning”。 一个挑战是在大语言模型(LLM)中的复杂推理。虽然传统观点认为复杂的推理任务需要大量的训练数据(通常超过 100,000 个示例),但本文展…...

【玩转 Postman 接口测试与开发2_018】第14章:利用 Postman 初探 API 安全测试
《API Testing and Development with Postman》最新第二版封面 文章目录 第十四章 API 安全测试1 OWASP API 安全清单1.1 相关背景1.2 OWASP API 安全清单1.3 认证与授权1.4 破防的对象级授权(Broken object-level authorization)1.5 破防的属性级授权&a…...

如何编写测试用例
代码质量管理是软件开发过程中的关键组成部分,比如我们常说的代码规范、代码可读性、单元测试和测试覆盖率等,对于研发人员来说单元测试和测试覆盖率是保障自己所编写代码的质量的重要手段;好的用例可以帮助研发人员确保代码质量和稳定性、减…...

复原IP地址(力扣93)
有了上一道题分割字符串的基础,这道题理解起来就会容易很多。相同的思想我就不再赘述,在这里我就说明一下此题额外需要注意的点。首先是终止条件如何确定,上一题我们递归到超过字符串长度时,则说明字符串已经分割完毕,…...

zzcms接口index.php id参数存在SQL注入漏洞
zzcms接口index.php id参数存在SQL注入漏洞 漏洞描述 ZZCMS 2023中发现了一个严重漏洞。该漏洞影响了文件/index.php中的某些未知功能,操纵参数id会导致SQL注入,攻击可能是远程发起的,该漏洞已被公开披露并可被利用。攻击者可通过sql盲注等手段,获取数据库信息。 威胁等级:…...

Redis03 - 高可用
Redis高可用 文章目录 Redis高可用一:主从复制 & 读写分离1:主从复制的作用2:主从复制原理2.1:全量复制2.2:增量复制(环形缓冲区) 3:主从复制实际演示3.1:基本流程准…...

系统URL整合系列视频四(需求介绍补充)
视频 系统URL整合系列视频四(需求补充说明) 视频介绍 (全国)大型分布式系统Web资源URL整合需求(补充)讲解。当今社会各行各业对软件系统的web资源访问权限控制越来越严格,控制粒度也越来越细。…...