C语言-详解指针


目录

一.内存

        1.内存的定义

        2.内存的结构图

二.地址

        1.什么是地址

        2.什么是变量的地址

三.什么是指针

        1.指针的定义

四.如何获取数据存储空间的地址

        1.&运算符

五.指针变量

        1.什么是指针变量(一级指针变量)

        2.指针变量的定义                

       3.指针变量的大小

六.指针变量的大小

七.使用指针变量

        1.*运算符

          2.为什么需要使用地址                

八.指针的运算

        1.指针 +- 整数

        2.指针-指针

        

        3.指针的关系运算                

九.野指针

        1.什么是野指针

        2.野指针的成因

        3.如何避免野指针

十.指针和数组

十一.二级指针

        1.什么是二级指针

        2.二级指针变量的声明

十二.指针数组

        1.什么是指针数组

        2.指针数组的定义

          3.指针数组的使用                

十三.字符指针

        1.什么是字符指针

        2.字符指针的使用

十四.数组指针

        1.什么是数组指针

        2.什么是整个数组的地址

        3.如何保存数组的地址

        4.数组指针变量的定义

        5.数组指针的使用

        6.区别数组,指针数组,数组指针,数组指针数组

        7.指针数组和数组指针数组的使用

十五.数组传参和指针传参

        1.数组传参

        2.指针传参

 十六.函数指针

        1.什么是函数指针

        2.函数指针变量                

        3.函数指针变量的使用

十七.函数指针数组

        1.函数指针数组的定义

        2.函数指针数组的使用

十八.指向函数指针数组的指针

        1.定义                

十九.回调函数

        1.定义

        2.回调函数的使用

二十.指针笔试题


一.内存

        1.内存的定义

                内存(Memory)是计算机的重要部件,也称内存储器和主存储器,它用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器交换的数据。它是外存与CPU进行沟通的桥梁,计算机中所有程序的运行都在内存中进行,内存性能的强弱影响计算机整体发挥的水平。只要计算机开始运行,操作系统就会把需要运算的数据从内存调到CPU中进行运算,当运算完成,CPU将结果传送出来。

                计算机中常用的内存的大小是 4g/8g/16g

                程序在运行前会先加载到内存中,也会使用内存。

        2.内存的结构图

                C++-内存的结构图-CSDN博客

                一个字节是8个bit位。 

二.地址

        1.什么是地址

                地址是指内存中一个最小单元的编号。    

      

        2.什么是变量的地址

                变量的存储空间的首字节的地址就是整个变量的地址。

                 一个例子:以int类型的变量为例子

                

三.什么是指针

        1.指针的定义

                指针指的是内存中一个最小单元的编号。

                所以我们在提到指针的概念的时候可以认为指针就是地址。

  

四.如何获取数据存储空间的地址

        1.&运算符

                &地址运算符又称取地址运算符,&运算符的运算对象是变量,将变量数据的存储空间的地址叫做表达式的派生值。

                在C语言中我们用%p来作为地址的转换说明。

                那么此时我们获取到的相应类型的地址数据应该保存到什么类型的变量中呢?

五.指针变量

        1.什么是指针变量(一级指针变量)

                指针变量是一个变量,变量中的内容保存的是存储相应类型的存储空间的首字节地址。

                 我们可以通过&(取地址操作符)取出变量的内存其实地址,把地址可以存放到一个变量中,这个变量就是指针变量。

        2.指针变量的定义                

#include <stdio.h>

int main(void)
{
	int number = 10;

	int* ptr_number = &number;

	printf("number的地址:%p\n", &number);
	printf("ptr_number中保存的数据:%p\n", ptr_number);

	return  0;
}

             

                *ptr_number表明ptr_number这个变量是一个指针变量,该变量中保存的数据是保存int类型数据的存储空间的编号,也就是地址。

                此时就会有疑问,为什么我们通过变量名number也可以得到我们想要的数据,为什么还需要通过地址来访问存储空间,从而得到我们想要的数据。

        

       3.指针变量的大小

        在32位操作系统下                         在64位操作系统下        

        为什么在不同位的操作系统下,同样的代码同样的指针变量却有不同的结果呢?

六.指针变量的大小

        上面我们说到指针变量中保存的是存储空间的地址,那么指针变量在不同的平台下所占的字节数不同,也就说明了在不同的平台下我们的地址这个数据的大小不同。 

        对于32位平台下:

                对于32位的机器,假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电平(低电压)就是(1或者0);

                那么32根地址线产生的地址就会是:
                        0000 0000 0000 0000 0000 0000 0000 0000
                        0000 0000 0000 0000 0000 0000 0000 0001
                        ...
                        1111  1111  1111  1111 1111  1111  1111  1111

                所以我们要保存32位bit位的地址数据,那么我们就需要用4个字节来保存。

                所以在32位平台下指针变量的大小都是4字节。无论保存什么样类型的数据。 

        对于64位平台下同理。

七.使用指针变量

        1.*运算符

                *运算符又称解引用运算符(间接运算符),*运算符的运算对象是指针变量或地址,

通过它得到的表达式的派生值是地址中保存的相应类型的数据。

#include <stdio.h>

int main(void)
{
	int number = 10;

	int* ptr_number = &number;

	printf("number=%d\n", number);
	printf("*ptr_number=%d\n", *ptr_number);

	return  0;
}

                       

          2.为什么需要使用地址                

#include <stdio.h>

void Swap(int number_a, int number_b)
{
	int number_tmp = 0;
	number_tmp = number_a; 
	number_a = number_b;
	number_b = number_tmp;
}

int main(void)
{
	int number_a = 10;
	int number_b = 20;

	printf("两数交换前分别为number_a = %d number_b = %d\n", number_a, number_b);

	Swap(number_a, number_b);

	printf("两数交换后分别为number_a = %d number_b = %d\n", number_a, number_b);
	return 0;
}

                 此时我们运行代码发现两数并没有交换:


                        原因就是此时我们传入函数的就是一个值而已,在我们主调函数中的值并没有改变。

        解决办法:

                上面我们提到了地址是存储空间的编号,那么我们将变量的地址传入到函数中,不就可以直接对存储空间中的数据进行更改了。

#include <stdio.h>

void Swap(int* ptr_number_a, int* ptr_number_b)
{
	int number_tmp = 0;
	number_tmp = *ptr_number_a; 
	*ptr_number_a = *ptr_number_b;
	*ptr_number_b = number_tmp;
}

int main(void)
{
	int number_a = 10;
	int number_b = 20;

	printf("两数交换前分别为number_a = %d number_b = %d\n", number_a, number_b);

	Swap(&number_a, &number_b);

	printf("两数交换后分别为number_a = %d number_b = %d\n", number_a, number_b);
	return 0;
}

八.指针的运算

        1.指针 +- 整数

int main(void)
{
	int a = 10;
	int* ptr_a = &a;

	printf("a变量的地址是:%p\n", &a);
	printf("ptr_a:%p\n", ptr_a);
	printf("ptr_a + 1:%p", ptr_a + 1);
	return 0;
}

           

        从上图我们可以看出,指针+-整数并不是单纯的数值上面的累加,而是跳过整数倍个该类型所占的字节数。

        int* ptr:

                *ptr表明ptr变量是指针变量,所以这个变脸中保存的数据是一个地址,该地址所标识的存储空间中的数据是一个int类型的数据。

                所以我们在声明一个变量是指针变量的时候,*表明这个变量是一个指针变量,而指明数据类型,是为了保证我们在处理指针变量的时候,结果的正确。 

        2.指针-指针

                指针-指针的前提条件是两个指针变量指向同一段连续的存储空间上。不同的存储空间上计算出来的结果没有意义。

                指针-指针的结果是两个地址之间的元素个数。                

int main(void)
{
	int numbers[10] = { 0 };

	int* ptr_numbers_start = numbers;
	int* ptr_numbers_end = numbers + 10;

	printf("%d\n", ptr_numbers_end - ptr_numbers_start);
	return 0;
}

               

        

        3.指针的关系运算                

int main(void)
{
	int numbers[3] = { 1,2,3 };

	int* ptr_numbers_start = numbers;
	int* ptr_numbers_end = numbers + 3;

	while (ptr_numbers_start < ptr_numbers_end)
	{
		printf("%d ", *ptr_numbers_start);
		ptr_numbers_start++;
	}
	printf("\n");
	return 0;
}

         注意:

                C语言中只保证了给数组分配空间时,指向数组后面的第一个位置的指针仍然是有效指针。不允许与指向数组第一个元素的前一个位置的指针进行比较。

九.野指针

        1.什么是野指针

                概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)。

        

        2.野指针的成因

                  没有对指针变量进行初始化

#include <stdio.h>
int main()
{ 
 int *p;//局部变量指针未初始化,默认为随机值
    *p = 20;
 return 0;
}

                 指针越界访问

#include <stdio.h>
int main()
{
    int arr[10] = {0};
    int *p = arr;
    int i = 0;
    for(i=0; i<=11; i++)
   {
        //当指针指向的范围超出数组arr的范围时,p就是野指针
        *(p++) = i;
   }
    return 0;
}

                对空指针进行解引用

int main(void)
{
	int* ptr = NULL;

	*ptr = 11;
	return 0;
}

        3.如何避免野指针

                a. 指针初始化
                b. 小心指针越界
                c. 指针指向空间释放,及时置NULL
                d. 避免返回局部变量的地址
                e. 指针使用之前检查有效性     
   
#include <stdio.h>
int main()
{
    int *p = NULL;
    //....
    int a = 10;
    p = &a;
    if(p != NULL)
   {
        *p = 20;
   }
    return 0;
}

十.指针和数组

        先看一个例子:                

#include <stdio.h>
int main()
{
 int arr[10] = {1,2,3,4,5,6,7,8,9,0};
    printf("%p\n", arr);
    printf("%p\n", &arr[0]);
    return 0;
}

        通过观察上图我们可以得出结论:

                数组名是数组首元素的地址。

十一.二级指针

        1.什么是二级指针

                二级指针是指一级指针变量的地址。

        2.二级指针变量的声明

                int ** pptr;

                        *pptr表明pptr这个变量是指针变量,这个变脸中保存的数据是一个地址数据,这个地址指向的存储空间中保存的数据是一个int*类型的数据。 

十二.指针数组

        1.什么是指针数组

                顾名思义就是一个数组中的每个元素都是指针类型的。

        2.指针数组的定义

                int * ptrs[10];

                ptr[10]表明此处是声明一个数组,该数组有10个元素,int*表明这个10个元素每一个都是int*的指针变量。

        

          3.指针数组的使用                

int* arr1[10]; //整形指针的数组
char *arr2[4]; //一级字符指针的数组
char **arr3[5];//二级字符指针的数组

十三.字符指针

        1.什么是字符指针

               保存char类型数据的存储空间的地址。

        

        2.字符指针的使用

int main()
{
    char ch = 'w';
    char *pc = &ch;
    *pc = 'w';
    return 0;
}
int main()
{
    const char* pstr = "hello bit.";//这里是把一个字符串放到pstr指针变量里了吗?
    printf("%s\n", pstr);
    return 0;
}

                对于代码 const char* pstr = "hello bit.";的解释:

                        ”hello bit“是字符串字面量,这里”hello bit“表示的其实是字符串首元素的地址。这里是将这个字符串首元素的地址放到了pstr中。

        一道笔试题:            

#include <stdio.h>
int main()
{
    char str1[] = "hello bit.";
    char str2[] = "hello bit.";
    const char *str3 = "hello bit.";
    const char *str4 = "hello bit.";
    if(str1 ==str2)
 printf("str1 and str2 are same\n");
    else
 printf("str1 and str2 are not same\n");
       
    if(str3 ==str4)
 printf("str3 and str4 are same\n");
    else
 printf("str3 and str4 are not same\n");
       
    return 0;
}

        这里首先函数声明了str1和str2两个字符数组,然后将字符串“hello bit.”拷贝到数组空间中,数组名表示数组首元素的地址,同时str1和str2又是两个不同的数组,所以str1不等于str2。但是对于str3和str4这两个指针数组来说,因为字符串字面量是保存在内存的常量区的空间是不会改变的,所以str3和str4所获取的地址是相同的。

十四.数组指针

        1.什么是数组指针

                首先数组指针是一个指针,这个指针是整个数组的地址。

       

        2.什么是整个数组的地址

                数组名表示的是数组首元素的地址,那么此时对数组名取地址,得到的就是整个数组的地址。

        3.如何保存数组的地址

                前面我们提到过指针也就是地址,要保存在指针变量中,那么数组指针也不例外,也因该保存在数组指针变量中。

                

        4.数组指针变量的定义

#include <stdio.h>
int main()
{
	int numbers[10] = { 0 };

	int(*ptr_numbers)[10] = &numbers;

	return 0;
}

        首先*ptr_numbers表明ptr_numbers这个变量一个指针变量,该指针变量的类型是一个有10个int元素组成的数组该指针变量中保存的数据是一个10个元素数组的地址

        5.数组指针的使用

#include <stdio.h>

void Print(int (*ptr_numbers)[4], int r, int c)
{
	int i_i = 0;
	int i_j = 0;
	for (i_i = 0; i_i < r; i_i++)
	{
		for (i_j = 0; i_j < c; i_j++)
		{
			printf("%d ", *(*(ptr_numbers + i_i) + i_j));
		}
		printf("\n");
	}
}

int main(void)
{
	int numbers[3][4] = { {1, 2, 3, 4}, {4, 5, 6, 7} ,{7, 8, 9, 10} };

	Print(numbers, 3, 4);
	return 0;
}

        6.区别数组,指针数组,数组指针,数组指针数组

int arr[5];
int *parr1[10];
int (*parr2)[10];
int (*parr3[10])[5];

        7.指针数组和数组指针数组的使用

#include <stdio.h>

int main(void)
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr3[10] = { 1,2,3,4,5,6,7,8,9,10 };

	//整型指针数组
	int* ptr[3] = { arr1, arr2, arr3 };

	//数组指针数组
	int(*ptrs[3])[10] = { &arr1, &arr2, &arr3 };

	//遍历数据
	//整型指针数组的遍历
	int i_i = 0;
	int i_j = 0;
	for (i_i = 0; i_i < 3; i_i++)
	{
		for (i_j = 0; i_j < 10; i_j++)
		{
			printf("%d ", ptr[i_i][i_j]);
		}
		printf("\n");
	}
	printf("\n");
	//数组指针数组的遍历
	int i_z = 0;
	for (i_i = 0; i_i < 3; i_i++)
	{
		for (i_j = 0; i_j < 10; i_j++)
		{
			printf("%d ", (*(ptrs[i_i]))[i_j] );
		}
		printf("\n");
	}
	printf("\n");
	return 0;
}

十五.数组传参和指针传参

        1.数组传参

                一维数组:          

#include <stdio.h>

void test1(int arr[10])
{}
void test1(int arr [])
{}
void test1(int* arr)
{}

void test2(int *arr[20])
{}
void test2(int* arr[])
{}
void test2(int **arr)
{}

int main(void)
{
	int arr1[10] = { 0 };

	int* arr2[20] = { 0 };

	test1(arr1);
	test2(arr2);

	return 0;
}

                二维数组:

#include <stdio.h>

void test(int arr[3][5])
{}
void test(int arr[][5])
{}
void test(int (*arr)[5])
{}


int main(void)
{
	int arr[3][5] = { 0 };

	test(arr);

	return 0;
}

       

        2.指针传参

                一级指针传参:

#include <stdio.h>
void print(int *p, int sz)
{
 int i = 0;
 for(i=0; i<sz; i++)
 {
 printf("%d\n", *(p+i));
 }
}
int main()
{
 int arr[10] = {1,2,3,4,5,6,7,8,9};
 int *p = arr;
 int sz = sizeof(arr)/sizeof(arr[0]);
 //一级指针p,传给函数
 print(p, sz);
 return 0;
}

                       当一个函数的形数是一个一级指针的时候可以收什么样的实参呢?

                        数组名,变量的地址,一级指针变量。

                二级指针传参:

#include <stdio.h>
void test(int** ptr)
{
 printf("num = %d\n", **ptr); 
}
int main()
{
 int n = 10;
 int*p = &n;
 int **pp = &p;
 test(pp);
 test(&p);
 return 0;
}

                        当一个函数的形数是一个二级指针的时候可以收什么样的实参呢?

                                二级指针变量,一级指针变量的地址,一级指针数组的数组名。

 十六.函数指针

        1.什么是函数指针

#include <stdio.h>
void test()
{
 printf("hehe\n");
}
int main()
{
 printf("%p\n", test);
 printf("%p\n", &test);
 return 0;
}

               

        输出的是两个地址,这两个地址是 test 函数的地址。
        那我们的函数的地址要想保存起来,怎么保存?

        2.函数指针变量                

void test()
{
 printf("hehe\n");
}
//下面pfun1和pfun2哪个有能力存放test函数的地址?
void (*pfun1)();

        分析一下两段代码:

//代码1
(*(void (*)())0)();
//代码2
void (*signal(int , void(*)(int)))(int);

                代码1:

                        (void (*)())0是将0强转类型转换为函数指针,(*0)() 是调用函数。

                代码2:

                        首先(*signal(int , void(*)(int)))是一个函数,该函数的返回值类型是void(int)。

                代码2太复杂,如何简化:

typedef void(*pfun_t)(int);
pfun_t signal(int, pfun_t);

       

        3.函数指针变量的使用

#include <stdio.h>
void test()
{
	printf("hehe\n");
}
int main()
{
	void (*ptr_test)() = test;

	ptr_test();
	return 0;
}

十七.函数指针数组

        1.函数指针数组的定义

int (*parr1[10])();

        2.函数指针数组的使用

                函数指针数组的用途:转移表

#include <stdio.h>
int add(int a, int b)
{
           return a + b;
}
int sub(int a, int b)
{
           return a - b;
}
int mul(int a, int b)
{
           return a*b;
}
int div(int a, int b)
{
           return a / b;
}
int main()
{
 int x, y;
     int input = 1;
     int ret = 0;
     int(*p[5])(int x, int y) = { 0, add, sub, mul, div }; //转移表
     while (input)
     {
          printf( "*************************\n" );
          printf( " 1:add           2:sub \n" );
          printf( " 3:mul           4:div \n" );
          printf( "*************************\n" );
          printf( "请选择:" );
      scanf( "%d", &input);
          if ((input <= 4 && input >= 1))
         {
          printf( "输入操作数:" );
              scanf( "%d %d", &x, &y);
              ret = (*p[input])(x, y);
         }
          else
               printf( "输入有误\n" );
          printf( "ret = %d\n", ret);
     }
      return 0;
}

十八.指向函数指针数组的指针

        1.定义                

                指向函数指针数组的指针是一个 指针
                指针指向一个 数组 ,数组的元素都是 函数指针 ;
void test(const char* str)
{
 printf("%s\n", str);
}
int main()
{
 //函数指针pfun
 void (*pfun)(const char*) = test;
 //函数指针的数组pfunArr
 void (*pfunArr[5])(const char* str);
 pfunArr[0] = test;
 //指向函数指针数组pfunArr的指针ppfunArr
 void (*(*ppfunArr)[5])(const char*) = &pfunArr;
 return 0;
}

十九.回调函数

        1.定义

                回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

        2.回调函数的使用

二十.指针笔试题

                C语言-指针笔试题详解-CSDN博客

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LLM之Agent(四)| AgentGPT:一个在浏览器运行的Agent

AgentGPT是一个自主人工智能Agent平台&#xff0c;用户只需要为Agent指定一个名称和目标&#xff0c;就可以在浏览器中链接大型语言模型&#xff08;如GPT-4&#xff09;来创建和部署Agent平台。 PS&#xff1a;目前agentGPT仅支持chatgpt模型&#xff0c;暂时不支持本地llm模…

数字串最大乘积切分(动态规划)

不得不说&#xff0c;动态规划是真的骚 题解已经在图片里面了 代码如下&#xff1a; #include<stdio.h> long long gethnum(long long n);int main(void) {//定义变量并输入int N, M;long long dp[19][7] {0}, num[20][20] {0};scanf("%d%d", &N, &am…

2023年【A特种设备相关管理(锅炉压力容器压力管道)】考试内容及A特种设备相关管理(锅炉压力容器压力管道)复审考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 A特种设备相关管理&#xff08;锅炉压力容器压力管道&#xff09;考试内容根据新A特种设备相关管理&#xff08;锅炉压力容器压力管道&#xff09;考试大纲要求&#xff0c;安全生产模拟考试一点通将A特种设备相关管理…

【数据中台】开源项目(5)-Amoro

介绍 Amoro is a Lakehouse management system built on open data lake formats. Working with compute engines including Flink, Spark, and Trino, Amoro brings pluggable and self-managed features for Lakehouse to provide out-of-the-box data warehouse experience,…

Salesforce认证考试,这5招让你轻松过关!

认证是很多求职者获得第一份Salesforce工作的敲门砖。认证不仅是个人能力的体现&#xff0c;而且在学习备考的过程中&#xff0c;可以更系统地梳理知识&#xff0c;了解最新的产品和功能&#xff0c;对Salesforce有更全面和深入的认识。 大多数Salesforce从业者都至少持有一项…

Maxwell学习笔记

1 概述 Maxwell 是由美国 Zendesk 开源&#xff0c;用 Java 编写的 MySQL 实时抓取软件。 实时读取MySQL 二进制日志 Binlog&#xff0c;并生成 JSON 格式的消息&#xff0c;作为生产者发送给 Kafka&#xff0c;Kinesis、RabbitMQ、Redis、Google Cloud Pub/Sub、文件或其它平台…

多线程--11--ConcurrentHashMap

ConcurrentHashMap与HashMap等的区别 HashMap线程不安全 我们知道HashMap是线程不安全的&#xff0c;在多线程环境下&#xff0c;使用Hashmap进行put操作会引起死循环&#xff0c;导致CPU利用率接近100%&#xff0c;所以在并发情况下不能使用HashMap。 ConcurrentHashMap 主…

UVM实现component之间transaction级别的通信

my_model是从i_agt中得到my_transaction&#xff0c;并把 my_transaction传递给my_scoreboard。在UVM中&#xff0c;通常使用TLM&#xff08;Transaction Level Modeling&#xff09;实现component之间transaction级别 的通信。 在UVM的transaction级别的通信 中&#xff0c;数…

【已验证】SqlBulkCopy 执行批量插入的时候报超时问题-解决办法

把datatable里面的数据插入到数据库&#xff0c;但是数据量大的情况下批量插入会提示超时&#xff0c;所以把datatable的数据分批写入数据库的 using (SqlConnection connection new SqlConnection(ConnectionString)){connection.Open();int pageSize 100000;//SqlBulkCopy大…

Linux各目录结构说明

文章目录 目录说明源码放哪里&#xff1f;拓展&#xff1a;Linux里面安装软件是装在home目录还是opt目录还是/usr/local好&#xff1f; bin boot dev etc home lib lib64 lostfound media mnt opt proc root run sbin srv sys tmp usr var 目录说明 bin 存放二进制可执行文件&…

C语言每日一题(46)整数转罗马数字

力扣网12 整数转罗马数字 题目描述 罗马数字包含以下七种字符&#xff1a; I&#xff0c; V&#xff0c; X&#xff0c; L&#xff0c;C&#xff0c;D 和 M。 字符 数值 I 1 V 5 X 10 L 50 C 100 D …

手机如何设置防骚扰电话?

很多人都曾接到过烦人的推销电话&#xff0c;这些电话不仅让人感到烦恼&#xff0c;而且有时候还会接二连三地打来&#xff0c;让人不胜其烦。我们的手机号码似乎已经被泄露&#xff0c;很难避免这些骚扰。 有时&#xff0c;我们因无法忍受骚扰电话而选择立即将其拉黑&#xff…

ROW_NUMBER()函数——(分组后取每组最新的两条数据)

ROW_NUMBER() 功能&#xff1a;简单的说row_number()从1开始&#xff0c;为每一条分组记录返回一个数字。 用法一&#xff1a; ROW_NUMBER() OVER (ORDER BY col DESC) 说明&#xff1a;先把col列降序&#xff0c;再为降序后的每条col记录返回一个序号 用法二&#xf…

Linux系统---图书管理中的同步问题

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C/C》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、问题描述 &#xff08;1&#xff09;图书馆阅览室最多能够容纳N&#xff08;N5&#xff09;名学生&#xff0c;若有更多学生想…

玩转大数据7:数据湖与数据仓库的比较与选择

1. 引言 在当今数字化的世界中&#xff0c;数据被视为一种宝贵的资源&#xff0c;而数据湖和数据仓库则是两种重要的数据处理工具。本文将详细介绍这两种工具的概念、作用以及它们之间的区别和联系。 1.1. 数据湖的概念和作用 数据湖是一个集中式存储和处理大量数据的平台&a…

【FreeRTOS】消息队列——简介、常用API函数、注意事项、项目实现

在嵌入式系统开发中&#xff0c;任务间的通信是非常常见的需求。FreeRTOS提供了多种任务间通信的机制&#xff0c;其中之一就是消息队列。消息队列是一种非常灵活和高效的方式&#xff0c;用于在不同的任务之间传递数据。通过消息队列&#xff0c;任务可以异步地发送和接收消息…

优化您的Mac体验——System Dashboard Pro for Mac(系统仪表板)

作为Mac用户&#xff0c;我们都希望能够拥有一个高效、流畅的电脑体验。然而&#xff0c;在长时间使用后&#xff0c;我们的Mac可能会变得越来越慢&#xff0c;导致我们的工作效率下降。这时候&#xff0c;System Dashboard Pro for Mac(系统仪表板)就可以派上用场了。它是一款…

vivado时序方法检查2

TIMING-4 &#xff1a; 时钟树上的基准时钟重新定义无效 时钟树上的时钟重新定义无效。基准时钟 <clock_name> 是在时钟 <clock_name> 下游定义的 &#xff0c; 并覆盖其插入延迟和/ 或波形定义。 描述 基准时钟必须在时钟树的源时钟上定义。例如 &#xff0…

mongdb配置ssl

mongodb5.0.9 centos7.6 x86 1、正常启动mongod -f mongodb.conf 【前言】 ssl配置流程步骤&#xff0c;按照以下顺序处理即可。 1.生成证书&#xff0c;根证书&#xff0c;服务端证书&#xff0c;客户端证书 2.配置服务端ssl配置&#xff0c;测试she…

Arrays类 - Java

Arrays类 Arrays类1、常用方法案例 Arrays类 1、常用方法 Arrays 里面包含了一系列静态方法&#xff0c;用于管理或操作数组(比如排序和搜索)。 toString 返回数组的字符串形式 Arrays.toString(arr)【案例1】 sort 排序(自然排序和定制排序) Integer arr[]{1, -1, 7, 0, 8…