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…...

在Spring Boot和MyBatis-Plus项目中,常见的错误及其解决方法2.0
1. org.springframework.beans.factory.BeanCreationException: Error creating bean with name requestMappingHandlerMapping 现象 在创建bean时发生错误,通常是因为存在重复的URL映射。 解决方法 检查所有控制器方法上的URL映射注解,确保没有重复…...

招聘信息数据清洗
文章目录 前言代码示例如下 前言 相关知识 为了完成本关任务,你需要掌握: 1.Spark 清洗数据的相关方法, 2.空值列怎么删除; 3.怎么数据切分才能达到想要的数据。 Spark清洗数据相关方法 一、将含有空值的数据删除 1.将含有空值的数据删除&a…...

机器学习——支持向量机(SVM)(1)
目录 一、认识SVM 1. 基本介绍 2. 支持向量机分类器目标 二、线性SVM分类原理(求解损失) 三、重要参数 1. kernel(核函数) 2 .C(硬间隔与软间隔) 四、sklearn中的支持向量机(自查&#…...

Elastic Observability 8.15:AI 助手、OTel 和日志质量增强功能
作者:来自 Elastic Alex Fedotyev, Tom Grabowski, Vinay Chandrasekhar, Miguel Luna Elastic Observability 8.15 宣布了几个关键功能: 新的和增强的原生 OpenTelemetry 功能: OpenTelemetry Collector 的 Elastic 分发:此版本…...

Unity3D ECS架构的优缺点详解
前言 Unity3D作为一款强大的游戏开发引擎,近年来在性能优化和架构设计上不断进化,其中ECS(Entity-Component-System)架构的引入是其重要的里程碑之一。ECS架构通过重新定义游戏对象的组织和处理方式,为开发者带来了诸…...

理解Go语言中多种并发模式
Go 的同步原语使实现高效的并发程序成为可能,并且选择合适的同步原语和并发模式可以更加容易地实现并发的可能,减少错误的发生。这里谈论的并发模式是只在 Go 语言中常见的并发的“套路” ,一种可解决某一类通用场景和问题的惯用方法。 1. 并发模式概述 我们先来回顾下同步…...

C++ primer plus 第17 章 输入、输出和文件:文件输入和输出03:文件模式:二进制文件
系列文章目录 17.4.5 文件模式 程序清单17.18 append.cpp 程序清单17.19 binary.cpp 文章目录 系列文章目录17.4.5 文件模式程序清单17.18 append.cpp程序清单17.19 binary.cpp17.4.5 文件模式1.追加文件来看一个在文件尾追加数据的程序。程序清单17.18 append.cpp2.二进制文…...

网络安全之sql靶场(11-23)
sql靶场(11-23) 目录 第十一关(post注入) 第十二关 第十三关 第十四关 第十五关 第十六关 第十七关 第十八关 第十九关 第二十关 第二十一关 第二十二关 第二十三关 第十一关(post注入) 查看…...

WordPress网站被入侵,劫持收录事件分析
7.15,网站被入侵,但是直到7月17日,我才发现被入侵。 16日,17日正常更新文章,17日查询网站收录数据时,在站长资源平台【流量与关键词】查询上,我发现了比较奇怪的关键词。 乱码关键词排名 起初…...

原生js: 实现三个水平tab按钮, 默认第一个上面有class, 点击另外的实现class=‘cur‘的切换的效果
问: <ul><li class"cur">热门问题</li><li>订阅问题</li><li>使用问题</li></ul> 这是我的代码, 这是我的代码: // 遍历 helpInfoClass 数组helpInfoClass.forEach((item, index) > {var itemId item[0];var i…...