Java老兵 转C语言,需要学习的点(最易懂的解释)

news2024/11/16 15:59:43

一、static

1.1 修饰函数内的局部变量:

void sayHi(void)
{              
  static int index = 5;
  index++;
}

多次调用sayHi函数,index = 5 只有在第一次调用的时候初始化一次,后面的多次调用,此句话就不执行了。

1.2 修饰全局变量或函数:

#include <stdio.h>
 
static int count = 10; // 全局变量
static void write_eeprom(const U8* xdr); // 全局函数

当 static 修饰全局变量或函数时,会使之的作用域限制在声明它的文件内。
只有此文件内可以调用,外部文件不可访问。

二、extern

直译 外面的

extern int num;  // 声明了一个整型变量num,它是在外面的、其他的文件中定义的。

执行此句代码时,不会为 num 分配任何存储空间,只是指示编译器 num 是在其他文件中定义的。
extern也可以用来修饰函数。

extern void write();

三、局部变量、全局变量

全局变量保存在内存的全局存储区中,占用静态的存储单元;
局部变量保存在栈中,只有在所在函数被调用时才动态地为变量分配存储单元。

默认值:
当局部变量被定义时,系统不会对其初始化,它的默认值有可能是一个垃圾值。
定义全局变量时,系统会自动对其初始化:

数据类型初始化默认值
int0
char‘\0’
float0
double0
pointerNULL

最佳实践是,无论是局部变量还是全局变量,定义的时候最好给显式地赋值一个默认值。

四、数组名

int heightArray[] = {1, 3, 4, 9}

heightArray既是数组名,也是指向数组第一个元素地址(也是数组的地址)的指针。

int* ptr = &heightArray[0];
也可以这么写
int* ptr = heightArray;

下面是我写的一个小程序,它本身没什么意义,单纯为了使大家更好的理解,数组名是个指针是什么意思:

int sumPreTwo(int* ptr);

int main() {
    int heightArray[] = {1, 3, 4, 9};

    int ret = sumPreTwo(heightArray);
    printf("sum pre two, the result is %d", ret);

    return 0;
}

int sumPreTwo(int* ptr)
{
	int first = *ptr;
	int* secondPtr = ptr + 1; // line2
	int second = *secondPtr; // line3
	return first + second;
}

输出:sum pre two, the result is 4

当然 line2和line3可以合并为一句

int second = *(ptr + 1)

由此,引发出求和的另一种写法:

#include <stdio.h>

int sum(int* ptr, int size);

int main() {
    int heightArray[] = {1, 3, 4, 9};

    int ret = sum(heightArray, 4);
    printf("sum all, the result is %d", ret);

    return 0;
}

int sum(int* array, int size)
{
    int sum = 0;
    for(int i=0; i<size; i++)
    {
        sum += *(array+i);
    }
    return sum;
}
/
输出: sum all, the result is 17

它本身也没什么意义,也是为了帮助大家更好地理解,为什么说:数组名是一个指向数组首元素的指针

五、定义一个函数,返回值是一个数组

C 语言不允许返回一个完整的数组,只能返回一个指向数组的指针。

#include <stdio.h>

int[] genArray(int size);

int main() {
    int heightArray[] = genArray(3);
    for(int j=0; j<3; j++){
        printf("%d element is: %d", j, heightArray[j]);
    }
    return 0;
}

int[] genArray(int size)
{
    int arr[size];
    for(int i=0; i<size; i++)
    {
        arr[i] = i;
    }
    return arr;
}

像上面这样的代码,不好意思,C不支持,编译就报错:
在这里插入图片描述

#include <stdio.h>

int* genArray();

int main() {
    int* heightArrayPtr = genArray();
    for(int j=0; j<3; j++)
    {
        printf("%d element is: %d \n", j, *(heightArrayPtr+j));
    }
    return 0;
}

int* genArray()
{
    static int arr[3];
    for(int i=0; i<3; i++)
    {
        arr[i] = i;
    }
    return arr;
}

六、静态数组

int staticArray[5]; // 静态数组声明
int staticArray[] = {1, 2, 3, 4, 5}; // 静态数组声明并初始化

获取数组长度:

int array[] = {1, 2, 3, 4, 5};
int length = sizeof(array) / sizeof(array[0]);

整个数组占用空间大小 / 一个元素占用空间大小 = 20字节 / 4字节 = 5个元素

七、动态数组(手动分配内存)

int size = 5;
int *dynamicArray = (int *)malloc(size * sizeof(int)); // 动态数组内存分配
// 使用动态数组
free(dynamicArray); // 动态数组内存释放

自己写了个例子:

#include <stdio.h>
#include <stdlib.h>

int* genArray(int size);

int main() {
    int size = 5;
    int* heightArrayPtr = genArray(size);
    for(int j=0; j<size; j++)
    {
        printf("%d element is: %d \n", j, *(heightArrayPtr+j));
    }
    free(heightArrayPtr); // ※一定别忘了内存释放
    return 0;
}

int* genArray(int size)
{
    int* array = (int*)malloc(size * sizeof(int));

    for(int i=0; i<size; i++)
    {
        array[i] = i;
    }
    return array;
}
//
0 element is: 0
1 element is: 1
2 element is: 2
3 element is: 3
4 element is: 4

malloc 的参数是字节数,此函数在 stdlib.h 中声明。
分配内存的函数,还有calloc,它们的区别是:

  • malloc 只分配内存,并不初始化,默认值可能是一个垃圾值;
  • calloc 分配内存,并初始化值为0;
  • calloc 的参数是两个,元素数与每个元素占用的空间;
  • 而malloc只有一个占用空间字节数参数;

它们在 stdlib.h中的声明如下:

  void *__cdecl calloc(size_t _NumOfElements,size_t _SizeOfElements);
  void __cdecl free(void *_Memory);
  void *__cdecl malloc(size_t _Size);

八、枚举

enum DAY
{
      MON=1, TUE, WED, THU, FRI, SAT, SUN
};
// 值 1 2 3 4 5 6 7
enum season {spring, summer=3, autumn, winter};
// 值 0 3 4 5

enum(枚举)类型的值只能是整数类型,包括int、short、char等。你不能直接在enum中指定浮点数(如float或double)作为其值。
如果想创建浮点型枚举,可以参考以下实现:

float floatValues[3] = {0.1, 0.2, 0.3};  
enum {  
    FLOAT_VALUE_1,  
    FLOAT_VALUE_2,  
    FLOAT_VALUE_3  
};

8.1 整数转换为枚举

#include <stdio.h>

enum day
{
    saturday,
    sunday,
    monday
} workday;

int main()
{
    int day1value = 1;
    enum day weekend;
    weekend = (enum day) day1value;  //类型转换
    // weekend = day1value; // 两种类型,不能直接赋值
    printf("weekend: %d", weekend);
    return 0;
}

九、空指针

int  *ptr = NULL; 

NULL 指向0x0系统保留的地址,应用程序不能访问。在程序中表达的意思是,此指针没有指向有效值(“没有初始化”)。

十、函数指针类型与变量

声明一个函数指针类型:

typedef int (*AddNum)(int);

typedef 表示我要定义一个类型。AddNum表示这个类型的名字。* 表示这是个函数指针类型。

int xxx(int)

这个范式,表达了定义的这个函数是什么样的函数,第一个int是返回值,第二个int是参数列表。xxx函数名是任意名,不是重点。
简单理解可以把它当成一个函数的模板,就是说我定义的这个函数指针类型,它指向的函数是一个怎样的函数:它的返回值是什么类型,它的参数列表是怎样的。
它定义了某种函数的模板,它代表了一堆这样的函数。

回顾一般指针的使用:

int a = 3;
int* ptr = &a;

要想定义一个指向整型的指针变量,首先要有整型这个类型(即 int),由于int 是C语言帮我们封装好了,所以可以直接用。
但是当要定义一个指向函数的指针变量时,并没有这个函数类型,所以才需要我们自己先声明一种函数类型。int xxx(int)这个范式就描述了这种函数类型。

写了个例子,便于加深理解:

#include <stdio.h>

int addNum(int);
int ori = 0;
typedef int (*AddNum)(int); // 定义函数指针类型
void sayhello(AddNum);

int main() {
    AddNum an = &addNum; // 创建一个函数指针变量,它指向了addNum函数
    printf("hello!! %d \n", an(10)); // 调用函数指针

    for(int i=0; i<3; i++)
    {
        sayhello(an);
    }
    return 0;
}

int addNum(int add)
{
    ori += add;
    return ori;
}

void sayhello(AddNum addNum)
{
    printf("hello!! %d \n", addNum(1));
}

十一、共用体

union Data
{
   int i;
   float f;
   char  str[20];
};

Data中所有变量,共用一块内存地址。
i 占4字节,f 占4字节,str占20字节,所以Data变量占用空间为20字节(等于所有成员变量中占用空间最大的)。

int main( )
{
   union Data data;        
 
   data.i = 10;
   data.f = 220.5;
   strcpy( data.str, "C Programming");
 
   printf( "data.i : %d\n", data.i);
   printf( "data.f : %f\n", data.f);
   printf( "data.str : %s\n", data.str);
 
   return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:

data.i : 1917853763
data.f : 4122360580327794860452759994368.000000
data.str : C Programming

可以看到,共用体的 i 和 f 成员的值有损坏。
因为共用内存地址,当写 str 值的时候,20个字节全重写了一遍,所以i、f 的值被覆盖掉了。

十二、typedef vs #define

它们有以下几点不同:

typedef 仅限于为类型定义符号名称,#define 不仅可以为类型定义别名,也能为数值定义别名,比如您可以定义 1 为 ONE。
typedef 是由编译器执行解释的,#define 语句是由预编译器进行处理的。

#define

在C语言中,#define是一个预处理指令,用于在编译之前进行文本替换。预处理器会在编译之前处理源代码,根据#define指令来替换代码中的文本。

例如,以下代码:

#define PI 3.14159

在编译之前,在代码中的任何地方出现的PI,它都会被预处理器替换为3.14159

除了简单的文本替换,#define还可以用于定义常量、宏函数等。例如:

#define SQUARE(x) ((x) * (x))

上述宏定义了一个名为SQUare的宏函数,该函数接受一个参数x并返回其平方。当你在代码中使用SQUare(5)时,它会被预处理器替换为((5) * (5))

typedef

在C语言中,typedef是一个关键字,它本身并不创建新的数据类型,只是为已有的数据类型创建了一个同义词或别名。

编译器在编译时解析typedef声明,并在符号表中记录这个新的类型名称与其对应的基础类型。这样,在后续的代码中,每当编译器遇到这个新的类型名称时,它都会用基础类型来替换它。

例如,考虑以下typedef声明:

typedef int Integer;
typedef struct {
    int x;
    int y;
} Point;

对于第一个typedef,编译器会记住Integerint的一个别名。在后续的代码中,任何使用Integer的地方都会被当作int来处理。

对于第二个typedef,编译器会创建一个结构体类型,并为它分配一个别名Point。这样,在代码中就可以使用Point来声明该结构体的变量,而不需要每次都写出完整的结构体定义。

需要注意的是,typedef的作用域是局部的,它遵循C语言的作用域规则。如果在一个函数内部使用typedef定义了一个类型别名,那么这个别名只在该函数内部有效。在函数外部,编译器将不认识这个别名,除非在外部也有相应的typedef声明。

十三、输入&输出

C 语言把所有的设备都当作文件
scanf() 函数用于从标准输入(键盘)读取并格式化, printf() 函数发送格式化输出到标准输出(屏幕)

#include <stdio.h>      // 标准io库
int main()
{
    printf("hello");
    return 0;
}

stdio.h 是一个头文件 (标准输入输出头文件) and #include 是一个预处理命令,用来引入头文件。 当编译器遇到 printf() 函数时,如果没有找到 stdio.h 头文件,会发生编译错误。

printf() %d 匹配整型,%f 匹配float,%p 匹配指针,%s匹配字符串,%c匹配字符

getchar() & putchar() 函数

getchar()读取下一个可用的字符,并把它返回为一个整数。这个函数在同一个时间内只会读取一个单一的字符。
int putchar(int c) 函数把字符输出到屏幕上,并返回相同的字符。这个函数在同一个时间内只会输出一个单一的字符

gets() & puts() 函数

char *gets(char *s) 函数从 stdin 读取一行到 s 所指向的缓冲区,直到一个终止符或 EOF。
int puts(const char *s) 函数把字符串 s 和一个尾随的换行符写入到 stdout。

scanf() 和 printf() 函数

带格式的输入输出

#include <stdio.h>
int main( ) {
 
   char str[100];
   int i;
 
   printf( "Enter a value :");
   scanf("%s %d", str, &i);
 
   printf( "\nYou entered: %s %d ", str, i);
   printf("\n");
   return 0;
}

十四、文件读写

#include<stdio.h>

int main()
{
    FILE *f = NULL;
    f = fopen("D:/2-Language/C/C-project1/tmp/test.txt", "w+");
    fprintf(f, "Hello World! \n");
    fputs("this is test for fputs...\n", f);
    fclose(f);
}
int fputc( int c, FILE *fp );  // 写一个字符
int fputs( const char *s, FILE *fp ); // 写一个字符串
int fprintf(FILE *fp,const char *format, ...)  // 把一个格式化字符串写入到文件中

int fgetc( FILE * fp ); // 读单个字符
char *fgets( char *buf, int n, FILE *fp ); // 读n-1个字符到buf,直到换行或文件结尾
int fscanf(FILE *fp, const char *format, ...) // 读到第一个空格或换行为止

十五、预处理器

C 预处理器不是编译器的组成部分,但是它是编译过程中一个单独的步骤。简言之,C 预处理器只不过是一个文本替换工具而已,它们会指示编译器在实际编译之前完成所需的预处理。我们将把 C 预处理器(C Preprocessor)简写为 CPP。

所有的预处理器命令都是以井号(#)开头。

#define 定义宏
#include 包含一个源代码文件

15.1 预定义宏

ANSI C 定义了许多宏。在编程中您可以使用这些宏,但是不能直接修改这些预定义的宏。

描述
__DATE__当前日期,一个以 “MMM DD YYYY” 格式表示的字符常量。
__TIME__当前时间,一个以 “HH:MM:SS” 格式表示的字符常量。
__FILE__这会包含当前文件名,一个字符串常量。
__LINE__这会包含当前行号,一个十进制常量。

15.2 预处理器运算符

宏延续运算符(\)
字符串常量化运算符(#)

十六、头文件

A simple practice in C 或 C++ 程序中,建议把所有的
常量、宏、系统全局变量和函数原型
写在头文件中,在需要的时候随时引用这些头文件。

引用头文件相当于复制头文件的内容
引用头文件会在预编译阶段,进行处理。

16.1 只引用一次头文件

如果一个头文件被引用两次,编译器会处理两次头文件的内容,这将产生错误。为了防止这种情况,标准的做法是把文件的整个内容放在条件编译语句中,如下:

#ifndef HEADER_FILE
#define HEADER_FILE

the entire header file file

#endif

这种结构就是通常所说的包装器 #ifndef。当再次引用头文件时,条件为假,因为 HEADER_FILE 已定义。此时,预处理器会跳过文件的整个内容,编译器会忽略它。

十七、错误处理

C 语言不提供对错误处理的直接支持,但是作为一种系统编程语言,它以返回值的形式允许您访问底层数据。在发生错误时,大多数的 C 或 UNIX 函数调用返回 1 或 NULL,同时会设置一个错误代码 errno,该错误代码是全局变量,表示在函数调用期间发生了错误。您可以在 errno.h 头文件中找到各种各样的错误代码。

所以,C 程序员可以通过检查返回值,然后根据返回值决定采取哪种适当的动作。

  • perror() 函数显示您传给它的字符串,后跟一个冒号、一个空格和当前 errno 值的文本表示形式。
  • strerror() 函数,返回一个指针,指针指向当前 errno 值的文本表示形式。
#include <stdio.h>
#include <errno.h>
#include <string.h>
 
extern int errno ;
 
int main ()
{
   FILE * pf;
   int errnum;
   pf = fopen ("unexist.txt", "rb");
   if (pf == NULL)
   {
      errnum = errno;
      fprintf(stderr, "错误号: %d\n", errno);
      perror("通过 perror 输出错误");
      fprintf(stderr, "打开文件错误: %s\n", strerror( errnum ));
   }
   else
   {
      fclose (pf);
   }
   return 0;
}
///
错误号: 2
通过 perror 输出错误: No such file or directory
打开文件错误: No such file or directory

17.1 程序退出状态

exit(EXIT_SUCCESS);
exit(EXIT_FAILURE);

<stdlib.h>
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1

十八、可变参数(不常用,了解下就行)

int func_name(int arg1, ...);
#include <stdio.h>  
#include <stdarg.h>  
  
// 定义一个可变参数函数  
void print_numbers(int count, ...) {  
    va_list args; // 定义一个va_list类型的变量  
    va_start(args, count); // 初始化args,使其指向第一个可变参数  
  
    for (int i = 0; i < count; i++) {  
        int value = va_arg(args, int); // 获取下一个整数参数  
        printf("%d ", value);  
    }  
  
    va_end(args); // 清理va_list变量  
}  
  
int main() {  
    print_numbers(3, 1, 2, 3); // 输出: 1 2 3  
    print_numbers(5, 4, 5, 6, 7, 8); // 输出: 4 5 6 7 8  
    return 0;  
}

使用va_list、va_start、va_arg和va_end宏来处理可变参数。这三个宏,在<stdarg.h>中定义。

十九、内存分配

序号函数描述
1void *calloc(int num, int size);在内存中动态地分配 num 个长度为 size 的连续空间,并将每一个字节都初始化为 0。所以它的结果是分配了 num*size 个字节长度的内存空间,并且每个字节的值都是 0。
2void free(void *address);该函数释放 address 所指向的内存块,释放的是动态分配的内存空间。
3void *malloc(int num);在堆区分配一块指定大小的内存空间,用来存放数据。这块内存空间在函数执行完成后不会被初始化,它们的值是未知的。
4void *realloc(void *address, int newsize);该函数重新分配内存,把内存扩展到 newsize。

void * 类型表示未确定类型的指针。C、C++ 规定 void * 类型可以通过类型转换强制转换为任何其它类型的指针。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int main()
{
   char name[100];
   char *description;
 
   strcpy(name, "Zara Ali");
 
   /* 动态分配内存 */
   description = (char *)malloc( 30 * sizeof(char) );
   if( description == NULL )
   {
      fprintf(stderr, "Error - unable to allocate required memory\n");
   }
   else
   {
      strcpy( description, "Zara ali a DPS student.");
   }
   /* 假设您想要存储更大的描述信息 */
   description = (char *) realloc( description, 100 * sizeof(char) );
   if( description == NULL )
   {
      fprintf(stderr, "Error - unable to allocate required memory\n");
   }
   else
   {
      strcat( description, "She is in class 10th");
   }
   
   printf("Name = %s\n", name );
   printf("Description: %s\n", description );
 
   /* 使用 free() 函数释放内存 */
   free(description);
}
 输出:
Name = Zara Ali
Description: Zara ali a DPS student in class 10th
strcpy( description, "Zara ali a DPS student."); // copy
strcat( description, "She is in class 10th"); // 拼接

C 语言中常用的内存管理函数和运算符
malloc() 函数:用于动态分配内存。它接受一个参数,即需要分配的内存大小(以字节为单位),并返回一个指向分配内存的指针。

free() 函数:用于释放先前分配的内存。它接受一个指向要释放内存的指针作为参数,并将该内存标记为未使用状态。

calloc() 函数:用于动态分配内存,并将其初始化为零。它接受两个参数,即需要分配的内存块数和每个内存块的大小(以字节为单位),并返回一个指向分配内存的指针。

realloc() 函数:用于重新分配内存。它接受两个参数,即一个先前分配的指针和一个新的内存大小,然后尝试重新调整先前分配的内存块的大小。如果调整成功,它将返回一个指向重新分配内存的指针,否则返回一个空指针。

sizeof 运算符:用于获取数据类型或变量的大小(以字节为单位)。

指针运算符:用于获取指针所指向的内存地址或变量的值。

& 运算符:用于获取变量的内存地址。

  • 运算符:用于获取指针所指向的变量的值。

-> 运算符:用于指针访问结构体成员,语法为 pointer->member,等价于 (*pointer).member。

memcpy() 函数:用于从源内存区域复制数据到目标内存区域。它接受三个参数,即目标内存区域的指针、源内存区域的指针和要复制的数据大小(以字节为单位)。

memmove() 函数:类似于 memcpy() 函数,但它可以处理重叠的内存区域。它接受三个参数,即目标内存区域的指针、源内存区域的指针和要复制的数据大小(以字节为单位)。

本文完。


觉得有用的话,动动你发财的小手手,点个赞,^(∩_∩)^ 谢谢~

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2024年第一篇博客

这是2024年的第一篇博客&#xff0c;2023年笔者经历了一连串的生活、工作、学习上的转折和调整&#xff0c;跌跌撞撞时光飞逝&#xff0c;转眼间就踏着元旦的钟声步入了2024年&#xff0c;前思后想、辗转反侧、犹豫再三不知道从哪里开始博客新的篇章&#xff0c;这个问题坦诚说…

解决Python xlwings报错AttributeError ‘NoneType‘ object has no attribute apps

一、问题背景 今天&#xff0c;遇到了一个问题&#xff1a;以前调试好的python使用xlwings操作wps表格的脚本突然不能运行了&#xff0c;遇到了很多莫名问题&#xff0c;下面记录分享下&#xff1a; 开始报错如下&#xff1a; D:\PycharmProjects\tiku\venv\Scripts\python.e…

C语言之字符逆序(牛客网)

个人主页&#xff08;找往期文章包括但不限于本期文章中不懂的知识点&#xff09;&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 字符逆序__牛客网 题目&#xff1a; 思路&#xff1a;既然有空格就不能用scanf函数来接收字符了。因为scanf函数遇到空格会停止读取。我们可以用get…

QtAV学习:(一)Windows下编译QtAV

QtAV 主页&#xff1a; QtAV by wang-bin 作者的编译构建说明文档&#xff1a; Build QtAV wang-bin/QtAV Wiki GitHub 我的编译环境&#xff1a; 编译环境&#xff1a;win10/msvc2015/Qt5.6.3 第一步&#xff1a;GitHub拉取代码,执行子模块初始化 地址&#xff1a; …

风控安全产品系统设计

风控业务架构 我把风控业务架构的分层分为6层,分别是组件层、业务层、决策层、能力层、计算层、可视层。 以下基建为基础安全产品的简称。 组件层 组件层的职责是:数据收集与行为反制。 从接口、设备、行为三个维度进行数据收集,接收决策层的指令进行行为反制。为了保证…

2.6c语言 判断素数

试除法(2--a-1) 判断一个数是否是素数,素数是只能被1或者他本身整除的数(1不是素数),可以通过循环遍历从2--a-1所有数,看有没有数能够被他整除,从而去判断他是不是素数. 代码部分 #include<stdio.h> int main() {int arr[10]{2,3,4,5,66,77,567,2553,3456,4436};int f…

Vue安装与配置

写入借鉴网址&#xff1a;好细的Vue安装与配置_vue配置-CSDN博客 下载Vue安装地址&#xff1a; Node.js — Download 查看是否安装成功&#xff1a; node -v npm -v 配置全局模式及缓存 结果通过&#xff1a; C:\Windows\system32>npm install vue -g added 20 packages …

ElasticSearch查询语句用法

查询用法包括&#xff1a;match、match_phrase、multi_match、query_string、term 1.match 1.1 不同字段权重 如果需要为不同字段设置不同权重&#xff0c;可以考虑使用bool查询的should子句来组合多个match查询&#xff0c;并为每个match查询设置不同的权重 {"query&…

C++类和对象入门(三)

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 前言 在c中&#xff0c;类型分为两类&#xff0c;一类是内置类型&#xff0c;另一类是自定义类型。 1.内置类型&#xf…

最适合入门的100个深度学习项目

&#x1f6a8;注意&#x1f6a8;&#xff1a;最近经粉丝反馈&#xff0c;发现有些订阅者将此专栏内容进行二次售卖&#xff0c;特在此声明&#xff0c;本专栏内容仅供学习&#xff0c;不得以任何方式进行售卖&#xff0c;未经作者许可不得对本专栏内容行使发表权、署名权、修改…

亲测解决vscode的debug用不了、点了没反应

这个问题在小虎登录vscode同步了设置后出现,原因是launch文件被修改或删除。解决方法是重新添加launch。 坏境配置 win11 + vscode 解决方法 Ctrl + shift + P,搜索debug添加配置: 选择python debugger。 结果生成了一个文件在当前路径: launch内容: {// Use Int…

MySQL篇----第十篇

系列文章目录 文章目录 系列文章目录前言一、MyISAM Static 和 MyISAM Dynamic 有什么区别?二、如果一个表有一列定义为 TIMESTAMP,将发生什么?三、你怎么看到为表格定义的所有索引?四、LIKE 声明中的%和_是什么意思?五、列对比运算符是什么?前言 前些天发现了一个巨牛…

zabbix配置邮箱告警

1.监控nginx服务状态 2.创建触发器 触发器条件&#xff1a;当服务状态的值为0时&#xff0c;进行邮箱告警 3.配置邮件告警 本次使用qq邮箱进行告警 点击右边的测试&#xff0c;进入到qq邮箱查看消息。 4.为用户添加报警媒介 5.创建动作 6.现在尝试关闭nginx服务&#xff0c;…

【办公自动化】Python执行Windows命令

第一部分&#xff1a;引言 在Python中&#xff0c;我们可以使用os模块来执行Windows命令。os模块提供了许多与操作系统交互的函数&#xff0c;包括执行系统命令。以下是一个简单的示例&#xff0c;展示了如何使用Python执行Windows命令。 第二部分&#xff1a;导入os模块 首…

探索PostgreSQL:从基础到实践(简单实例)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 下载前言一、PostgreSQL是什么&#xff1f;二、使用步骤1.引入库2.读入数据 总结 下载 点击下载提取码888999 前言 在当今的大数据时代&#xff0c;数据库作为信…

06 MP之自动填充+SQL执行的语句和速度分析

1. 自动填充 在项目中有一些属性&#xff0c;比如常见的创建时间和更新时间可以设置为自动填充。 1.1 实例 需求: 将创建时间和更新时间设置为自动填充, 这样每次插入数据时可以不用理会这两个字段 1.1.1 在数据库增加字段 默认开启驼峰映射 createTime --> create_time…

10英寸安卓车载平板电脑丨ONERugged车载工业平板:解决农业工作效率

农业是人类社会的基石之一&#xff0c;而农业工作效率的提升一直是农民和农业专业人士关注的重要议题。随着技术的不断进步&#xff0c;车载工业平板成为了解决农业工作效率的创新解决方案。本文将探讨车载工业平板如何为农业带来巨大的改变&#xff0c;提高农民的工作效率和农…

IntelliJ 跨数据源导入数据迁移

有这么一个需求&#xff0c;我们需要把服务器上一个测试表中的输入导入到本地的数据库中。 IntelliJ 已经设置了 2 个数据源。 我们可以通过 IntelliJ 的数据迁移工具在 2 个数据源中进行迁移。 找到需要导出的表 首先我们需要找到需要导出的表&#xff0c;然后从表中选中导…

Unix五种I/O模型(阻塞、非阻塞、多路复用、信号驱动、异步)

文章目录 概要一、I/O基础二、阻塞式I/O三、非阻塞式I/O三、I/O多路复用四、信号驱动I/O五、异步I/O六、小结 概要 在工作中&#xff0c;经常使用Nginx、Redis等开源组件&#xff0c;常提到其高性能的原因是网络I/O的实现是基于epoll&#xff08;多路复用&#xff09;。这次呢…

第1节、电路连接【51单片机+L298N步进电机系列】

↑↑↑点击上方【目录】&#xff0c;查看本系列全部文章 摘要&#xff1a;本节介绍如何搭建一个51单片机L298N步进电机控制电路&#xff0c;所用材料均为常见的模块&#xff0c;简单高效的方式搭建起硬件环境。 一、硬件清单 ①51单片机模块 ②恒流模块 ③开关电源 ④L298N模…