c语言小知识点小计
c语言小知识点小计
1、运算符的优先级
++
运算符的优先级是和指针解引用*
的优先级相同的,但在代码运行中执行顺序是从后往前
的。因此下面代码
int a[10] = {1,2,3,4};
int* arr = a;
printf("%d",*arr++);//访问的值是2
//注意:printf("%d",*a++);这种语法是错误的,因为a是个常量(指针常量),不可更改
2、 strcpy和memcpy的使用
strcpy只用于字符串数组之间的拷贝,因为strcpy是以\0
来判断结束的。使用方式如下:
char a[] = {"this is a test!"};
char b[100];
strcpy(b,a);//不像memcpy需要用户确定拷贝的大小,strcpy以'\0'为结束符判断拷贝的结束
memcpy()能够拷贝任意类型的数组,但需要手动确定拷贝的大小
int a[10] = {1,2,3,4,5};
int b[10];
strcpy(b,a,sizeof(a));//memcpy()需要手动确定拷贝数据的大小
3、数组和数组的首地址
由于数组名是一个指针常量,因此指针的指向是不能更改的,也就是说数组名的指向的地址是不能更改的。因此不能有数组名++
的操作如下图代码:
int a[10] = {1,2,3,4} ;
//a++这种写法是错误的,当需要对数组的元素进行访问时,
//可以用下标或者是重新定义一个指针来对数组进行访问。如下所示:
//方法一
for (int i = 0;i<10;i++)
{
printf("数组中的元素是%d",a[i]);
}
//方法二,虽然不能使用++但是可以使用(地址+偏移值的方式)
for (int i = 0;i<10;i++)
{
printf("数组中的元素是%d",*(a+i));
}
//方法三
int *arr = a;
for(int i = 0;i<10;i++)
{
printf("数组中的元素是%d",*arr+i)
}
4、sizeof()的使用
sizeof可以获取当前变量的大小,如下面示例所见:
如果想获取数组的的所占内存大小只能使用sizeof(数组名)
int arr[10] = {1,2,3,4};
pirnft("数组的大小是%d",sizeof(a));//获取的是10个int数据占据的空间大小
printf("数组指针的大小是%d",sizeof(&a);//获取的是指针的大小
5、指向常量和常量指针
所谓的常量指针
是指常量的值不能通过指针来修改,但指针的指向是可以修改的;
所谓的指针常量
是指指针的指向不可修改,在第一次绑定赋值后就不能在去绑定其他变量了。示例如下:
//指针常量int b1 = 10;int *const ddd = &b1; // 指针常量,指针的指向不能更改,需在初始化的时候就赋值//ddd = &c1;错误,因为指针常量的指向是不能修改的*ddd = 20;//语法正确
//常量指针const int *ccc;int c1 = 20;int d1 = 30;ccc = &c1;ccc = &d1;
// *ccc = 40;语法错误,常量指针不能用过指针来修改变量的值,当可以修改指向cout << "数组的大小是:" << *ccc << endl;
6、不同系统中变量的大小
- 在32位系统中指针的大小占
4字节:32位
- 在64位系统中指针的大小占
8字节:64位
- char———1字节
short———2字节
int————4字节
long————4字节
long long——8字节
float————4字节
double———8字节
7、c语言中局部变的内存分配
局部变量在函数执行时在栈区分配空间,并在函数执行结束后释放空间。
8、结构体的内存大小与字节对齐
- 可用手动更改对齐系数:
#pragma pack(n),n=1,2,4,8,16 来改变这一系数,其中的 n 就是你要指定的“对齐系数”
- 数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在 offset 为 0 的地方,以后每个数据成员的对齐按照 #pragma pack 指定的数值和这个数据成员自身长度中,比较小的那个进行。
- 结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。
- 结合1、2可推断:当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。
#include<stdio.h>
struct S1
{char a;int b;char c;
};//占12字节
struct S2
{int a;char b;int c;char d;
};//占16字节
int main()
{// sizeof()功能:获取了数据在内存中所占用的存储空间,以字节为单位来计数。printf("%d\n", sizeof(struct S1));printf("%d\n", sizeof(struct S2));return 0;
}
- 这里可能不好理解在此对其进行解释(
假设为32位系统,因此当有跨字节时进行4字节对齐
):下图中每个框代表一个字节,由于ch占一个字节因此将其方到第一字节处。由于int 占4字节跨字节了,因此进行4字节对齐。short占2个字节因此放到后面的地址空间。由于char占一个字节没跨字节不用字节对齐。
内存对齐的规则:
9、数组和指针的区别
- char arr1[] = “hello”;和char *arr2 = “hello”;两句代码中出现的字符串都存储在静态存储区中。
- char arr1[] 声明了一个名为 arr1 的字符数组,这个数组的大小正好能够存放字符串 “hello” 加上一个结尾的空字符 ‘\0’。编译器会为 arr1 在栈上分配足够的空间,以存储所有这些字符。
- 字符串字面量 “hello” 存储在程序的常量区。
在函数执行时,“hello” 的内容会被复制到新分配的栈空间中,也就是 arr1 数组中。
这通常是通过一个循环来完成的,每个字符(包括结尾的空字符 ‘\0’)都会从常量区复制到 arr1 的相应位置。
int main()
{
char arr1[] = "hello";
char *arr2 = "hello";
arr1[0] = 'A';//这种写法没有问题,因为arr1是存放在栈上的变量。
printf("%c\r\n",arr1[0]);
//arr2[0] = 'A';这种写法是错误的,因为arr2是指向静态存储区的一个常量指针,不能用过指针来修改值,而且“hello”存放在静态存储区,里面的值就是不能进行修改的
printf("%c\r\n",arr2[0]);
}
10、结构体简介
结构体定义的三种方式:
- 1、最标准的方式:
#include <stdio.h>
struct student //结构体类型的说明与定义分开。声明
{int age; /*年龄*/float score; /*分数*/char sex; /*性别*/
};
int main ()
{struct student a={ 20,79,'f'}; //定义printf("年龄:%d 分数:%.2f 性别:%c\n", a.age, a.score, a.sex );return 0;
}
2、不环保的方式(声明和定义一起)
#include <stdio.h>
struct student /*声明时直接定义*/
{int age; /*年龄*/float score; /*分数*/char sex; /*性别*//*这种方式不环保,只能用一次*/
} a={21,80,'n'};
int main ()
{printf("年龄:%d 分数:%.2f 性别:%c\n", a.age, a.score, a.sex );
}
3、最奈何人的方式(定义一次性的结构体变量)
#include <stdio.h>
struct //直接定义结构体变量,没有结构体类型名。这种方式最烂
{int age;float score;char sex;
} t={21,79,'f'};int main ()
{printf("年龄:%d 分数:%f 性别:%c\n", t.age, t.score, t.sex);return 0;
}
4、使用typedef定义结构体
用 typedef 定义新类型名来代替已有类型名,即给已有类型重新命名;
一般格式为;typedef 已有类型 新类型名;
typedef int Elem;
typedef struct{
int date;..........
}STUDENT;
STUDENT stu1,stu2;
//这里也可与在前面加上结构体的名称如:
typedef struct student
{
int date;..........
}STUDENT;//在定义结构体时可以直接使用:
struct student xiaoming;
//也可以直接使用:
STUDENT zhangshan;
- 对于结构体的初始化
结构体在没创建实例之前是不分配内存的
typedef struct student{
char name[20];
char sex[20];
int age;
}stu;struct student stu1 = {"xiaomin","男",11};
//或者初始化时写成
stu stu2 = {.name = "小张",.sex = "男",.age = 12}
- 结构体之间可以直接赋值(这里可以个数组之间不能直接赋值对比记忆)
typedef struct {int a;}stu1;stu1 ss1 = {10};stu1 ss2 = ss1;printf("ss2 = %d",ss2.a);
- 结构体中的位域
:
(但对成员进行读写时花费的时间可能较长)
在成员变量之后使用冒号并声明这个变量将要占用的比特位将大大节省空间。例如你需要9位的一个变量来表示一个数据,但c语言中只有uint16但使用u16将浪费7位的内存,因此可以写成
uint16 sign :9;
typedef struct stu { uint 8 flag :1; uint16 num :9; }STU;
11、c语言中的结构体
- 内存的最小索引单元是
1字节
,那么你其实可以把内存比作一个超级大的「字符型数组」。在上一节我们讲过,数组是有下标的,我们是通过数组名和下标来访问数组中的元素。那么内存也是一样,只不过我们给它起了个新名字:地址。每个地址可以存放「1字节」的数据
,所以如果我们需要定义一个整型变量,就需要占据4个内存单元
。 - 获取某个变量的地址,使用取地址运算符
&
,定义指针的时候也使用了*
,这里属于符号的「重用」,也就是说这种符号在不同的地方就有不同的用意:在定义的时候表示「定义一个指针变量」,在其他的时候则用来「获取指针变量指向的变量的值」。
char* pa = &a;
int* pb = &f;
printf("%c, %d\n", *pa, *pb);
- 使用scanf(“请输入一个数%d”,&a);这里的需要输入a的地址。可以简单的理解是你想将输入的数据放到内存中的那个地方,这个地方的地址是多少。
//如果是使用数组来接收字符串就不需要加&
char arr[100];
scanf("%s",arr);//为什么不需要加&呢?因为数组名就是地址了
- 定义指向数组的指针
char a[10];
char *p;
p = a;
p = &a[0];
//对数组的访问可以通过三中方式printf("*p = %d, *(p+1) = %d, *(p+2) = %d\n", *p, *(p + 1), *(p + 2));printf("a = %d, a+1 = %d, a+2 = %d", *a, *(a+1), *(a+2));//主要这里不能使用++运算来对地址进行改写printf("a = %d, a+1 = %d, a+2 = %d", a[0], a[1], a[2]);
- 在c语言中字符串结束标识符‘\0’占一个字节
12、指针数组和数组指针
int* p1[5];//指针数组,数组中的每一个元素都是int指针类型
int (*p2)[5];//数组指针,指向一个int类型的数组,且数组中有5个元素,格式和函数指针相似#include "stdio.h"
int main(void)
{char* p1[5] = {"人生苦短,我用Python。","PHP是世界上最好的语言!","One more thing...","一个好的程序员应该是那种过单行线都要往两边看的人。","C语言很容易让你犯错误;C++看起来好一些,但当你用它时,你会发现会死的更惨。"};int i;for (i = 0; i < 5; i++){printf("%s\n", p1[i]);//如果想访问,每个字符数组的某个元素可以使用p1[i][i]}return 0;
}
- 整形指针指向数组和数组指针的区别
#include
int main(void)
{int temp[5] = {1, 2, 3, 4, 5};int(*p2)[5] = &temp;//这里要注意,数组指针指向是数组的地址,而不是数组首元素的地址int i;for (i = 0; i < 5; i++){printf("%d\n", *(*p2 + i));//因此这里第一次解引用时获取首元素的地址,第二次解引用是获取数据}return 0;
}
13、指针和二维数组
- 二维数组在内存中也是线性存放的,例如
int arry[3][4]
其实是申请了一块连续的20字节的地址用于存放数据。 - array作为数组的名称,显然应该表示的是数组的「首地址」。由于二维数组实际上就是一维数组的「线性拓展」,因此array应该就是指的
指向包含4个元素
的数组的指针
。指向第一个数组的首地址。
int array[3][4] = {{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12}};这里注意要访问数据时要么直接通过下标进行访问,要么需要通过两次解应用才能访问数据,因为第一次解引用获取的是内存数组的地址,第二次才是获取内部数组中的数据printf("二维数组中第五个元素数 = %d\r\n", array[1][0]);printf("二维数组中第五个元素数 = %d\r\n", *(*array+4));printf("二维数组中第六个元素数 = %d\r\n", *(array[1]+1));
14、void指针
void 不能直接用来定义一个数据类型,但可以定义一个指针类型。void 类型的指针可以转换位各种类型的指针。如果void类型没有进行强制类型转换不能用于接收其他类型的指针。
void *a;a = malloc(sizeof(int) * 5);for (int i = 0; i < 5; i++){*(((int *)a) + i) = i;}for (int i = 0; i < 5; i++){printf("----->%d\r\n", *(((int *)a)++));这句代码是错误的,注意这里对a进行了强制类型转换,系统会生成一个临时变量其生存周期为当前执行语句,因此无法对其进行++操作printf("----->%d\r\n", *((int *)a+i));}
14、实现函数宏的三种方式
- {} 方式:这种方式在有if和while判断语句时仍然受判断语句控制
#define INT_SWAP(a,b)\
{ \int tmp = a; \a = b; \b = tmp; \
}
int main()
{
int var_a = 1;
int var_b = 2;INT_SWAP(var_a, var_b);
printf("var_a = %d, var_b = %d\n", var_a, var_b); // var_a = 2, var_b = 1if (1)INT_SWAP(var_a, var_b);
printf("var_a = %d, var_b = %d\n", var_a, var_b); // var_a = 1, var_b = 2
}
但当没有花括号时将导致问题,问题出现的原因是当没有花括号时判断语句后面本来是只能接一句语的。
- do{…}while(0) 方式
需要注意的是do{}while()语句必须使用分号;结尾
#define INT_SWAP(a,b) \
do{ \if (a < 0 || b < 0) \break; \int tmp = a; \a = b; \b = tmp; \
}while(0)//因此下面代码将有问题:if (1)
if (1)INT_SWAP(var_a, var_b)//按正常思维来说这里确实不应该有分号,但由于这个宏定义是do{}while()结尾,因此c语言要求必须加上冒号
else
{printf("hello world!\n");
}
- ({}) 方式
与 do{...}while(0) 相同,({}) 支持在无花括号且有分支的 if 语句中直接调用。例如:
#define INT_SWAP(a,b) \
({ \int tmp = a; \a = b; \b = tmp; \
})
C 语言规定 ({}) 中的最后一条语句的结果为该双括号体的返回值
int a = ({1,2,3});//根据运算的优先级先算后面的括号中内容,算完后返回3
15、在c++ 中指定使用c语言的方式编译
- 兼容性:C++语言支持函数重载,而C语言不支持。C++编译器在编译时会对函数名进行名称修饰(name mangling)以支持重载,而C编译器不会。使用extern "C"可以确保C++代码中声明的函数或变量在链接时使用C语言的名称修饰规则,这样C++程序就能正确地调用C库中的函数。
- 链接C库:当你想在C++程序中使用C库(例如标准C库或第三方C库)时,你需要使用extern "C"来声明这些库中的函数,这样C++编译器才知道如何正确地处理这些函数的名称
extern "C" {// 这里可以包含C头文件,或者直接声明C函数#include <c_header.h>// 或者int c_function(int arg);
}
-------------------------------------------------------------------------------------------------
// C++程序
#include <iostream>
extern "C" {#include "c_lib.h"//这个头文件中包含的有add(int,int)函数
}int main() {int result = add(5, 3); // 正确调用C库中的函数std::cout << "The sum is: " << result << std::endl;return 0;
}
16、位域
在结构体定义时,我们可以指定某个成员变量所占用的二进制位数(Bit),这就是位域。请看下面的例子:
位域定义的结构体也存在内存对齐,当前指定的位域小于当前的数据类型时(或者没有超过系统定义最小对齐字节时则紧挨着存储,否则进行字节对齐)
typedef struct bs{unsigned m;unsigned n: 4;unsigned char ch: 6;
};
C语言标准还规定,只有有限的几种数据类型可以用于位域。
在 ANSI C 中,这几种数据类型是 int、signed int 和
unsigned int(int 默认就是 signed int);到了 C99,_Bool 也被支持了。
- 如果成员之间穿插着非位域成员,那么不会进行压缩。例如对于下面的 bs:
1struct bs{
2 unsigned m: 12;
3 unsigned ch;
4 unsigned p: 4;
5};
17、#error的目的是什么?
- 可以提醒程序员定义重复定义的某些变量
#define a 10
#ifdef a
#error "请取消定义a"
#endif
18、c语言中使用的3种死循环
while(1)
{}for(;;)
{}do{}while(1);loop:...goto loop;
19、static关键字
在C语言中,关键字static有三个明显的作用:
第一、在修饰变量的时候,static修饰的静态局部变量只执行一次,而且延长了局部变量的生命周期,直到程序运行结束以后才释放。
第二、static修饰全局变量的时候,这个全局变量只能在本文件中访问,不能在其它文件中访问,即便是extern外部声明也不可以。
第三、static修饰一个函数,则这个函数的只能在本文件中调用,不能被其他文件调用。Static修饰的局部变量存放在全局数据区的静态变量区。初始化的时候自动初始化为0;
(1)不想被释放的时候,可以使用static修饰。比如修饰函数中存放在栈空间的数组。如果不想让这个数组在函数调用结束释放可以使用static修饰
(2)考虑到数据安全性(当程想要使用全局变量的时候应该先考虑使用static)
20、关键字volatile有什么含意?并给出三个不同的例子。
一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:
1:并行设备的硬件寄存器(如:状态寄存器)
2:一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
3:多线程应用中被几个任务共享的变量
21、在嵌入式系统中将a的第三位置一和清零
#define BIT3 (0x1Ul << 3)
static int a;void set_bit3(void)
{a |= BIT3;
}
void clear_bit3(void)
{a &= ~BIT3;
}
22、c语言中的__interrupt关键字
- 使用这个函数定义一个中断服务子程序(ISR)
函数存在的问题:
①函数不能有返回值
②函数不能有参数
③不要在中断服务函数中做浮点运算
④不要在中断服务函数中进行耗时的操作和不可重入函数:在C语言中,函数的重入性(reentrancy)
是指一个函数在执行过程中,可以被中断,并且在稍后重新开始执行而不会产生错误的能力。
重入函数和不可重入函数的概念主要与多线程编程和中断处理相关。
__interrupt double compute_area (double radius)
{double area = PI * radius * radius;printf("\nArea = %f", area);return area;
}
23、c语言中的自动类型转换
- 是当表达式中存在有符号类型和无符号类型时所有的操作数都自动转换为无符号类型。
void foo(void)
{unsigned int a = 6;int b = -20;(a+b > 6) ? puts("> 6") : puts("<= 6");
}//结果是大于6
24、使用typedef定义指针类型时需要注意不能让连续定义两个指针类型,否则第二个定义失败
#define dPS struct s *
typedef struct s * tPS;
dPS p1,p2;
tPS p3,p4;
第一个扩展为
struct s * p1, p2;
25、c语言中与内存相关的错误
- 间接应用坏指针:
scanf("%d", &value);//正确的写法\
scanf("%d", value);//系统会讲value里面的值当成地址,将数据写到这个地址中
- 读未初始化的内存
int *a = (int *)malloc(5*sizeof(int));
for(int i = 0;i<5;i++)
{a[i]+=i;//这句代码是不合法的因为在申请空间后并没有对空间中的数据进行初始化,因此不能将里面的数据看成0
}
- 栈缓冲区溢出
void buff()
{char buf[6];//由于当前定义的缓冲区较小,因此下面定的gets输入的字符不能大于这个值,否则会发生溢出,虽然在vs中运行没有报错但当前已经发生的栈溢出。gets(buf);return;
}
- 假设指针和它们指向的对象大小相同
int **makeArray(int n, int m)
{int i;int **A = (int **)malloc(n * sizeof(int)); /* 注意此处语句,存在问题 */for(i = 0; i < n; i++){A[j] = (int *)malloc(m * sizeof(int));}return A;
}
此程序的目的是创建一个由 n 个指针组成的数组,每个指针都指向一个包含 m 个 int 的数组。
然而,第 4 行程序代码将 sizeof(int *)写成了 sizeof(int),代码实际上创建的是一个 int 的数组。
这段代码只有在 int 和指向 int 的指针大小相同的机器上运行良好;否则,就会出现错误。
- 内存越界
代码试图访问申请空间之外的空间将导致内存越界
int **makeArray(int n, int m)
{int i;int **A = (int **)malloc(n * sizeof(int*)); /* 注意此处语句,存在问题 */for(i = 0; i <= n; i++) /* 注意循环终止条件:这里访问的空间总大小为n+1将造成空间越界 */{A[j] = (int *)malloc(m * sizeof(int));}return A;
}
*
和++ 运算符的优先级
*p++
等价于*(p++)
如果想对指针指向的值进行自增操作需要用括号进行优先级控制
(*p)++
这个相当于对指针指向的值进行自加
- 寻找数组中的特定值
int * secrch(int *p,int value)
{
while(*p && *p != value)//第一分p判断当前的值是否为空,第二个用来判断当前的值是否为目标值
{p++;
}
return p;
}
- 使用malloc等函数后没有释放空间造成内存泄
void leak(int n)
{int *x = (int *)malloc(n * sizeof(int));return;
}
26、c语言中几种分配内存的函数
- malloc(size)以直接为单位分配未初始化的空间;
- calloc(number,size)以字节为单位分配number个每个大小为size的空间,并将数据初始化为0;
- realloc(void *ptr,size)重新分配ptr的大小,如果ptr = null则相当于malloc函数,如果size = 0相当free函数
27、c语言中内存拷贝的内存重叠现象
- 使用memcpy(目的,源,大小)拷贝内存中的数据时可能由于内存重叠而造成影响
- 使用memove(目的,源,大小)不会因为内存重叠而造成数据混乱
void *Memcpy2(void *dest, const void *src, size_t count)
{ char *d; const char *s; if (((int)dest > ((int)src+count)) || (dest < src)) { d = (char*)dest; s = (char*)src; while (count--) *d++ = *s++; } else /* overlap :存在内存的重叠*/ { d = (char *)((int)dest + count - 1); /* 指针位置从末端开始,注意偏置 */ s = (char *)((int)src + count -1); while (count --) *d-- = *s--; } return dest;
}
28、内存分配函数 malloc 原理及实现
- 虚拟内存地址与物理内存地址
为了简单,现代操作系统在处理内存地址时,普遍采用虚拟内存地址技术。即在汇编程序(或机器语言)层面,当涉及内存地址时,都是使用虚拟内存地址。采用这种技术时,每个进程仿佛自己独享一片2N字节的内存,其中N是机器位数。例如在64位CPU和64位操作系统下,每个进程的虚拟地址空间为264Byte。
由于在机器语言层面都是采用虚拟地址,当实际的机器码程序涉及到内存操作时,需要根据当前进程运行的实际上下文将虚拟地址转换为物理内存地址,才能实现对真实内存数据的操作。
- 页与地址的构成
在现代操作系统中,不论是虚拟内存还是物理内存,都不是以字节为单位进行管理的,而是以页(Page)为单位。一个内存页是一段固定大小的连续内存地址的总称,具体到Linux中,典型的内存页大小为4096Byte(4K)。
由于每页的大小都是4k = 4096字节因此寻址时只需要12位就可以完成,因此每个地址用页号和偏移号来代表在内存中的位置
相关文章:

c语言小知识点小计
c语言小知识点小计 1、运算符的优先级 运算符的优先级是和指针解引用*的优先级相同的,但在代码运行中执行顺序是从后往前的。因此下面代码 int a[10] {1,2,3,4}; int* arr a; printf("%d",*arr);//访问的值是2 //注意:printf("%d&qu…...
《C#面向语言版本编程》C# 13 中的新增功能
将C#语言版本升级为预览版 C# 13 包括一些新增功能。 可以使用最新的 Visual Studio 2022 版本或 .NET 9 预览版 SDK 尝试这些功能。若想在.NET项目中尝试使用C#的最新预览版特性,可以按照以下步骤来升级你的项目语言版本: .打开项目文件: 找…...

0成本通过Hugo和GitHub Pages搭建博客
版权归作者所有,如有转发,请注明文章出处:https://cyrus-studio.github.io/blog/ 使用 Chocolatey 安装 Hugo Chocolatey 是一个 Windows 软件包管理器,使用 PowerShell 和 NuGet 作为基础。它可以自动化软件的安装、升级和卸载过…...

Ollama 可以玩 GLM4和CodeGeeX4了
最近这一两周看到不少互联网公司都已经开始秋招提前批了。 不同以往的是,当前职场环境已不再是那个双向奔赴时代了。求职者在变多,HC 在变少,岗位要求还更高了。 最近,我们又陆续整理了很多大厂的面试题,帮助一些球友…...

浅析C++指针与引用的关系
前言: 在实践中指针与引用相辅相成,功能相互叠加,但各有各的特点,互相不可替代!!!...

Python面试宝典第31题:字符串反转
题目 编写一个函数,其作用是将输入的字符串反转过来,输入字符串以字符数组s的形式给出。不要给另外的数组分配额外的空间,你必须原地修改输入数组,并使用O(1)的额外空间解决这一问题。备注:s[i]都是ASCII码表中的可打印…...

【深入理解SpringCloud微服务】深入理解微服务中的远程调用,并手写一个微服务RPC框架
【深入理解SpringCloud微服务】深入理解微服务中的远程调用,并手写一个微服务RPC框架 远程过程调用微服务中的RPC框架如何实现一个微服务中的RPC框架接口扫描生成代理对象代理对象处理逻辑 手写一个微服务RPC框架RPCClientEnableRPCClientMicroServiceRPCClientRegi…...

数据结构----二叉树
小编会一直更新数据结构相关方面的知识,使用的语言是Java,但是其中的逻辑和思路并不影响,如果感兴趣可以关注合集。 希望大家看完之后可以自己去手敲实现一遍,同时在最后我也列出一些基本和经典的题目,可以尝试做一下。…...

通过python管理mysql
打开防火墙端口: 使用 firewall-cmd 命令在防火墙的 public 区域中永久添加 TCP 端口 7500(FRP 控制台面板端口)、7000(FRP 服务端端口)以及端口范围 6000-6100(一组客户端端口)。这些端口是 FR…...
Run the OnlyOffice Java Spring demo project in local
Content 1.Download the sample project in java2.Run the project3.Test the example document 1.Download the sample project in java Link: download the sample code in official website document properties setting spring 项目所在的服务器 server. Address192.168…...

11. Rancher2.X部署多案例镜像
**部署springboot项目 : ** **部署中间件Mysql8.0 : ** 名称:service-mysql 端口 :3306:3306 镜像:mysql:8.0 环境变量: MYSQL_ROOT_PASSWORDxdclass.net168路径映射 /home/data/mysql/data /var/lib/mysql:rw /etc/localtime…...

探索Linux世界之Linux环境开发工具的使用
目录 一、yum -- Linux软件包管理器 1、什么是yum 2、yum的使用 2.1 yum一些经常见的操作 1.查看软件包 2. 安装软件包 3. 删除软件包 3、yum的周边知识 3.1 yum的软件包都是从哪里来的?是从哪里能下载到这些软件包? 3.2 yum的拓展软件源 二、…...

探索Spring Boot微服务架构的最佳实践
目录 引言 一、Spring Boot简介 二、微服务架构的关键要素 三、Spring Boot在微服务中的最佳实践 3.1 清晰的服务边界 3.2 自动化配置与依赖管理 3.3 服务注册与发现 3.4 配置管理 3.5 安全与认证 3.6 监控与日志 3.7 分布式事务 四、总结 引言 在当今快速迭代的软…...

[论文泛读]zkLLM: Zero Knowledge Proofs for Large Language models
文章目录 介绍实验数据实验数据1实验数据2实验数据3 介绍 这篇文章发在CCS2024,CCS是密码学领域的顶会。作者是来自加拿大的University of Waterloo。文章对大语言模型像GPT和LLM等大语言模型实现了零知识可验证执行,但不涉及零知识可验证训练。个人觉得…...

vscode插件中的图标怎么设置
首先在ts文件目录下和package.json同级的目录下加入一张图片,后缀是jpg、png、jpeg都可以。 然后package.json中加入该行 重新 vsce package即可 如果出现报错 The specified icon xxx/xxx/icon.jpg wasnt found in the extension. 那就是没有放正确文件夹的位…...
Study--Oracle-08-oracle数据库的闪回技术
一、闪回恢复区(Flash Recovery Area) 1、什么是闪回恢复区 闪回恢复区是Oracle数据库中的一个特殊存储区域,用于集中存放备份和恢复数据库所需的所有文件,包括归档日志和闪回日志。这个区域可以帮助数据库在遇到介质故障时进行完全恢复。通过将备份数…...

获取客户端真实IP
出于安全考虑,近期在处理一个记录用户真实IP的需求。本来以为很简单,后来发现没有本来以为的简单。这里主要备忘下,如果服务器处于端口回流(hairpin NAT),keepalived,nginx之后,如何取得客户端的…...

韩式告白土味情话-柯桥生活韩语学习零基础入门教学
你们韩国人别太会告白了! 1、너 얼굴에 뭐가 조금 묻었어! 你的脸上有点5376东西! 뭐가 조금 묻었1585757는데? 有点什么? 이쁨이 조금 묻었네. 有点漂亮。 2、돌잡이 때 뭐 잡았어요? 你抓周的时候抓了什么? 쌀 잡았…...
Linux安全与高级应用(一)深入探讨Linux安全与高级应用
文章目录 深入探讨Linux安全与高级应用引言目录一、Linux安全与应用概述1.1 Linux的应用现状1.2 Linux的安全需求 二、构建LAMP企业网站平台2.1 LAMP平台简介2.2 安装和配置Apache服务器2.2.1 安装Apache2.2.2 配置Apache 2.3 安装和管理MySQL数据库2.3.1 安装MySQL2.3.2 配置M…...
【nginx 第二篇章】各个环境安装 nginx
一、Windows环境安装 1、下载 Nginx 访问Nginx官网(http://nginx.org/en/download.html)下载稳定版本的 Nginx 压缩包,如 nginx-1.xx.x.zip。下载后解压到指定的目录,例如 D:\nginx。 2、启动 Nginx 直接双击解压目录下的 ngi…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
Mobile ALOHA全身模仿学习
一、题目 Mobile ALOHA:通过低成本全身远程操作学习双手移动操作 传统模仿学习(Imitation Learning)缺点:聚焦与桌面操作,缺乏通用任务所需的移动性和灵活性 本论文优点:(1)在ALOHA…...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...
MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用
文章目录 一、背景知识:什么是 B-Tree 和 BTree? B-Tree(平衡多路查找树) BTree(B-Tree 的变种) 二、结构对比:一张图看懂 三、为什么 MySQL InnoDB 选择 BTree? 1. 范围查询更快 2…...
安卓基础(Java 和 Gradle 版本)
1. 设置项目的 JDK 版本 方法1:通过 Project Structure File → Project Structure... (或按 CtrlAltShiftS) 左侧选择 SDK Location 在 Gradle Settings 部分,设置 Gradle JDK 方法2:通过 Settings File → Settings... (或 CtrlAltS)…...
「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案
在移动互联网营销竞争白热化的当下,推客小程序系统凭借其裂变传播、精准营销等特性,成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径,助力开发者打造具有市场竞争力的营销工具。 一、系统核心功能架构&…...
Python实现简单音频数据压缩与解压算法
Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中,压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言,提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...
【FTP】ftp文件传输会丢包吗?批量几百个文件传输,有一些文件没有传输完整,如何解决?
FTP(File Transfer Protocol)本身是一个基于 TCP 的协议,理论上不会丢包。但 FTP 文件传输过程中仍可能出现文件不完整、丢失或损坏的情况,主要原因包括: ✅ 一、FTP传输可能“丢包”或文件不完整的原因 原因描述网络…...