C语言——指针进阶

news2024/10/6 12:34:26

目录

前言

一. 字符指针

二. 指针数组

三. 数组指针

3.1 何为数组指针?

3.2 &数组名与数组名

四. 数组参数、指针参数

4.1 一维数组传参

4.2 二维数组传参

4.3 一级指针传参

4.4 二级指针传参

五. 函数指针

六. 函数指针数组

七. 指向函数指针数组的指针

八. 回调函数

九. 指针与数组的笔试题

十. 指针笔试题


前言

各位小伙伴,大家好久不见,想来大家都是刚刚开学,祝大家新学期新气象,咱们的编程技术更上一层楼,咱们话不多说,直接步入今天的正题,指针进阶。

在之前的指针初阶之中我们已经大概的对于指针有了些许了解,例如:

1. 指针也是一种变量

2. 指针变量的大小根据不同的环境为4/8个字节(32位平台/68位平台)

3. 指针变量大小一样,但是拥有不同的类型,解引用时可操作的权限

4. 指针的运算

那今天,我们就需要更加深入的了解指针。

一. 字符指针

我们经常会看到对于一个字符串或者字符数组的传址输入,那我们就先来介绍字符指针(char*),一般我们对于字符指针的使用都是如下:

int main()
{
	char s = 'w';
	char* ps = &s;
	//此时*pc='w'
	return 0;
}

又或者

int main()
{
	char* str = "hello world";
	printf("%s\n",str);
	return 0;
}

当我们运行第二个代码的时候,我们会发现我们打印出来的并不是一个字符“h”而是整个字符串“hello world”,很多小伙伴就会非常的疑惑?难道我们在str这个地址存入了一整句话吗?

但实际上我们并不能存入如此多的字符进去,我们实际上只是将首元素的地址存入str当中,如下图

 而根据这个知识点就很有可能出一道面试题:

#include <stdio.h>
int main()
{
	char arr1[] = "hello world";
	char arr2[] = "hello world";
	const char* arr3 = "hello world";
	const char* arr4 = "hello world";
	if (arr1 == arr2)
	{
		printf("arr1 and arr2 are same.\n");
	}
	else
	{
		printf("arr1 and arr2 are not same.\n");
	}
	if (arr3 == arr4)
	{
		printf("arr3 and arr4 are same.\n");
	}
	else
	{
		printf("arr3 and arr4 are not same.\n");
	}
	return 0;
}

很多小伙伴一看这个题目便会一头雾水,这上面四个不是一模一样吗?肯定会打印两个same,但是结果并不是这样

我们发现arr1和arr2并不是我们预料之中的结果,为什么呢?arr1和arr2是两个不同的字符串,开辟的空间并不相同,可能一个的地址在0x11223344,而另一个可能就在0x55667788,if语句中的arr1和arrr2是两个首元素地址,那他们两个肯定不会相等,但是arr3和arr4两者是去出hello world这个字符串的地址,他们并不会开辟一个新的空间,所以arr3与arr4的地址就是同一个hello world的首元素地址。

二. 指针数组

数组我们在之前早就已经学过,而数组指针顾名思义自然就是存放指针的数组,就例如

int *arr1[10];//存放10个整型指针的数组
char *arr2[5];//存放5个字符型指针的数组
char **arr3[3];//存放3个二级指针的数组

三. 数组指针

3.1 何为数组指针?

数组指针就是指向数组的指针吗?指向整个数组吗?答案是数组指针也是指针,下面根据一个例子来学习分辨什么是数组指针?

int main()
{
	int* arr[10];//这是指针数组
	int(*arr)[10];//那这个加上一个括号是要干嘛?
	return 0;
}

第一个正是我们学习的指针数组,那第二个加个括号岂不是多此一举,并非如此,数学当中加减乘除我们是不是有不同的优先级,那在我们计算机当中也是有不同的优先级,

根据优先级来看,我们发现[]操作符的优先级远高于*操作符,那arr就一定会先与[]结合,我们为了避免他们先结合,我们可以将*和arr用()括起来这样arr就会先与*结合,说明arr是一个指针变量,指向的是一个大小为10个整型的数组,所以arr是一个数组指针。

3.2 &数组名与数组名

数组的名字到底代表的是什么意思呢?

int main()
{
	int arr[10];
	printf("%p\n", arr);
	printf("%p\n", &arr);
	return 0;
}

 打印结果:

我们发现数组名与取地址数组打印出来的结果是一样的,难道这意味着数组名和取地址数组名一样吗?再看下面的这段代码:

#include <stdio.h>

int main()
{
	int arr[10] = { 0 };
	printf("arr =%p\n", arr);
	printf("&arr=%p\n", &arr);

	printf("arr+1 =%p\n", arr + 1);
	printf("&arr+1=%p\n", &arr + 1);
	return 0;
}

 我们发现arr与&arr的地址一样,但是当分别加一的时候一个加了4位而另一个却加了40位,由此我们发现其实&arrarr,虽然值是一样的,但是意义应该不一样的。 实际上: &arr 表示的是数组的地址,而不是数组首元素的地址。上面&arr 的类型是: int(*)[10] ,是一种数组指针类型 数组的地址+1,跳过整个数组的大小,所以 &arr+1 相对于 &arr 的差值是40

四. 数组参数、指针参数

当我们编写一个自定义函数的时候,我们一定会传入参数,当我们需要传入数组参数或者指针参数时我们又应该如何解决呢?

4.1 一维数组传参

#include <stdio.h>
void test(int arr[])//ok?
{}
void test(int arr[10])//ok?
{}
void test(int *arr)//ok?
{}
void test(int **arr)//ok?
{}
int main()
{
    int arr[10] = {0};
    test(arr);
    return 0;
}

上述四种方式都是可以数组传参的,第一个与第二个直接传入数组,第三个传入数组地址,第四个则是将数组名看作为一个一级指针地址,数组的每个元素都是一个int*类型,传入参数是一个数组名,那么我们就可以使用一个二级指针来接收,即是int **arr。

4.2 二维数组传参

void test(int arr[3][5])//ok?
{}
void test(int arr[][])//ok?
{}
void test(int arr[][5])//ok?
{}
//总结:二维数组传参,函数形参的设计只能省略第一个[]的数字。
//因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。
//这样才方便运算。
void test(int *arr)//ok?
{}
void test(int* arr[5])//ok?
{}
void test(int (*arr)[5])//ok?
{}
void test(int **arr)//ok?
{}
int main()
{
 int arr[3][5] = {0};
 test(arr);
}

其实无论是几维数组我们都可以将第一维省略,所以第二种并不可以这样传参,下面第一种和最后一种与一维数组其实道理相差不大,但是第二种与第三种就涉及了上面刚刚讲到的,我们传入的是数组指针并不是指针数组。

4.3 一级指针传参

我们先运用指针传参写出一个printf函数:

#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;
}

当我们将函数参数设置为一级指针的时候,这个函数可以接受什么样的参数呢?

例如:数组首元素地址,数组名,字符串首元素地址很多很多参数都可以传入一级指针。

4.4 二级指针传参

#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;
}

二级指针我们可以对于一级指针取地址得到二级指针。

五. 函数指针

我们来看一下这段代码:

#include <stdio.h>

void print(int a)
{
	printf("%d\n", a);
}
int main()
{
	int a = 10;
	print(a);
	printf("%p\n", print);
	printf("%p\n", &print);
	return 0;
}

 我们发现函数也是有自己的指针的(即地址),那当我们想要保存函数的地址有应当如何去实现呢?

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

答案是pfun1是可以存放的,pfun1与*优先结合,意味着是一个指针,指向的是一个函数,无参数,返回类型是void类型。在C陷阱与缺陷中有两段非常有意思的代码:

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

代码1咱们一步一步进行解读:

1.void (*)()--函数指针类型;


2.(void (*)())0--对0进行强制类型转换,被解释为一个函数地 址;


3.(*(void (*)())0)--对0地址进行了解引用操作;


4.(*(void (*)())0)()--调用0地址处的函数

代码2我们看上去十分的复杂但是我们只要稍加修改这个代码就会变得一目了然

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

用typedef重新定义一个返回类型为void,参数类型是整型的函数指针,而代码二中就是一个函数指针中的一个参数也是一个函数指针,是不是十分的有趣。

六. 函数指针数组

上面我们讲了指针数组就是存放指针的数组,那函数指针数组莫不是就是存放函数指针的数组吗?但是又有一个问题那就是函数指针数组又该如何定义呢?下面我们一起来看看。

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

正确的是parr1,parr1与[]操作符优先结合就是数组,那数组类型是什么?int (*) ()就是这个数组的元素,一个函数指针。

可能有小伙伴就要问了,这个函数指针数组都要把我绕昏了,这玩意有什么用处呢?

函数指针数组的用途:转移表,下面我们就来用计算器来举例:

       #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;
    do
   {
        printf( "*************************\n" );
        printf( " 1:add           2:sub \n" );
        printf( " 3:mul           4:div \n" );
        printf( "*************************\n" );
        printf( "请选择:" );
        scanf( "%d", &input);
        switch (input)
       {
比特就业课-专注IT大学生就业的精品课程 比特主页:https://m.cctalk.com/inst/
        case 1:
              printf( "输入操作数:" );
              scanf( "%d %d", &x, &y);
              ret = add(x, y);
              printf( "ret = %d\n", ret);
              break;
        case 2:
              printf( "输入操作数:" );
              scanf( "%d %d", &x, &y);
              ret = sub(x, y);
              printf( "ret = %d\n", ret);
              break;
        case 3:
              printf( "输入操作数:" );
              scanf( "%d %d", &x, &y);
              ret = mul(x, y);
              printf( "ret = %d\n", ret);
              break;
        case 4:
              printf( "输入操作数:" );
              scanf( "%d %d", &x, &y);
              ret = div(x, y);
              printf( "ret = %d\n", ret);
              break;
        case 0:
                printf("退出程序\n");
 breark;
        default:
              printf( "选择错误\n" );
              break;
       }
 } while (input);
    
    return 0;
}

这是没有采用函数指针数组的方法,下面就是采用函数指针数组的方法:

#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;
}

我们可以发现使用了函数指针数组使得代码看起来并没有那么冗杂。

七. 指向函数指针数组的指针

有的小伙伴看到这个地方就不禁非常的疑惑,最开始一个指针数组,后来来一个函数指针数组,现在又来一个函数指针数组指针,这在俄罗斯套娃呢?

指向函数指针数组的指针是一个 指针 指针指向一个 数组 ,数组的元素都是 函数指针
下面我们来看看如何定义这个指针。
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;
}

八. 回调函数

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

最后一个参数也就是一个函数,下面展示一下qsort函数的使用,并模拟实现qsort快排。

qsort函数的使用:

#include <stdio.h>
//qosrt函数的使用者得实现一个比较函数
int int_cmp(const void * p1, const void * p2)
{
  return (*( int *)p1 - *(int *) p2);
}
int main()
{
    int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
    int i = 0;
    
    qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp);
    for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++)
   {
       printf( "%d ", arr[i]);
   }
    printf("\n");
    return 0;
}

   使用qsort的方式自定义一个冒泡排序:

 

#include <stdio.h>
int int_cmp(const void * p1, const void * p2)
{
  return (*( int *)p1 - *(int *) p2);
}
void _swap(void *p1, void * p2, int size)
{
    int i = 0;
    for (i = 0; i< size; i++)
   {
        char tmp = *((char *)p1 + i);
       *(( char *)p1 + i) = *((char *) p2 + i);
       *(( char *)p2 + i) = tmp;
   }
}
void bubble(void *base, int count , int size, int(*cmp )(void *, void *))
{
    int i = 0;
    int j = 0;
    for (i = 0; i< count - 1; i++)
   {
       for (j = 0; j<count-i-1; j++)
       {
            if (cmp ((char *) base + j*size , (char *)base + (j + 1)*size) > 0)
           {
               _swap(( char *)base + j*size, (char *)base + (j + 1)*size, size);
           }
       }
   }
}
int main()
{
    int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
    //char *arr[] = {"aaaa","dddd","cccc","bbbb"};
    int i = 0;
    bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp);
    for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++)
   {
       printf( "%d ", arr[i]);
   }
    printf("\n");
    return 0;
}

注意:里面有一个void*类型,它并不是跟void一样的意义,它的含义是传入参数不知道是什么类型,可能是整型也有可能是字符型,因此这里才使用void*类型。

九. 指针与数组的笔试题

//一维数组
int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a+0));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(a[1]));
printf("%d\n",sizeof(&a));
printf("%d\n",sizeof(*&a));
printf("%d\n",sizeof(&a+1));
printf("%d\n",sizeof(&a[0]));
printf("%d\n",sizeof(&a[0]+1));
//字符数组
char arr[] = {'a','b','c','d','e','f'};
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));
char arr[] = "abcdef";
printf("%d\n", sizeof(arr));
printf("%d\n", sizeof(arr+0));
printf("%d\n", sizeof(*arr));
printf("%d\n", sizeof(arr[1]));
printf("%d\n", sizeof(&arr));
printf("%d\n", sizeof(&arr+1));
printf("%d\n", sizeof(&arr[0]+1));
printf("%d\n", strlen(arr));
printf("%d\n", strlen(arr+0));
printf("%d\n", strlen(*arr));
printf("%d\n", strlen(arr[1]));
printf("%d\n", strlen(&arr));
printf("%d\n", strlen(&arr+1));
printf("%d\n", strlen(&arr[0]+1));
char *p = "abcdef";
printf("%d\n", sizeof(p));
printf("%d\n", sizeof(p+1));
printf("%d\n", sizeof(*p));
printf("%d\n", sizeof(p[0]));
printf("%d\n", sizeof(&p));
printf("%d\n", sizeof(&p+1));
printf("%d\n", sizeof(&p[0]+1));
printf("%d\n", strlen(p));
printf("%d\n", strlen(p+1));
printf("%d\n", strlen(*p));
printf("%d\n", strlen(p[0]));
printf("%d\n", strlen(&p));
printf("%d\n", strlen(&p+1));
printf("%d\n", strlen(&p[0]+1));
//二维数组
int a[3][4] = {0};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a[0][0]));
printf("%d\n",sizeof(a[0]));
printf("%d\n",sizeof(a[0]+1));
printf("%d\n",sizeof(*(a[0]+1)));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(*(a+1)));
printf("%d\n",sizeof(&a[0]+1));
printf("%d\n",sizeof(*(&a[0]+1)));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a[3]));

 大家可以自己自己琢磨琢磨,我们会发现数组名的意义:

1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。
3. 除此之外所有的数组名都表示首元素的地址。

十. 指针笔试题

最后还有几道指针的笔试题,帮助我们巩固一下对于指针进阶的了解。

试题一:

int main()
{
    int a[5] = { 1, 2, 3, 4, 5 };
    int *ptr = (int *)(&a + 1);
    printf( "%d,%d", *(a + 1), *(ptr - 1));
    return 0;
}
//程序的结果是什么?

答案是2,5,因为一个*a就是1的地址,加上1就是a[1]的地址,指向的对象就是2,第二个ptr将&arr+1这个时候就指向a数组结尾的位置也就是a[4]的元素也就是5后面的一个元素,但是是未知的,减一,那指向的也就是5。

试题二:

int main()
{
    int a[5][5];
    int(*p)[4];
    p = a;
    printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
    return 0;
}

答案是:FFFFFFFFFFFFFFFC,-4,

试题三:

int main()
{
 char *c[] = {"ENTER","NEW","POINT","FIRST"};
 char**cp[] = {c+3,c+2,c+1,c};
 char***cpp = cp;
 printf("%s\n", **++cpp);
 printf("%s\n", *--*++cpp+3);
 printf("%s\n", *cpp[-2]+3);
 printf("%s\n", cpp[-1][-1]+1);
 return 0;
}

答案是:POINT
ER
ST
EW

这就是所有内容,如果有不明白的地方,欢迎在评论区留言,咱们下次再见。

 

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

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

相关文章

Java 继承中构造函数的问题

继承中构造函数的问题 父类构造函数和子类构造函数的关系 new一个之类对象时默认调用了父类的无参构造函数 ,创建了父类对象 父类的成员变量和成员方法才能创建出来 子类才能继承下来使用 首先创建一个父类&#xff0c;动物类 接下来创建一个子类&#xff0c;狗类&#xff…

基于OSG的虚拟校园系统的设计与实现

基于open scene graph的虚拟校园系统的设计与实现 摘要 •引言 • OSG基本原理 •OSG操作与动画 •视点的定位和切换 •自由漫游 •路径漫游 • 路径动画 • 点选和文字 • 粒子系统 • 3DMAX • 无线通信与数据库设计 • 实现步骤 • 结论 摘要 随着科技的不断发展,人工智能&a…

2023年,8种必备Selenium编写自动化用例的技巧

在开始自动化时&#xff0c;您可能会遇到各种可能包含在自动化代码中的方法&#xff0c;技术&#xff0c;框架和工具。有时&#xff0c;与提供更好的灵活性或解决问题的更好方法相比&#xff0c;这种多功能性导致代码更加复杂。在编写自动化代码时&#xff0c;重要的是我们能够…

2023年网络安全十大发展趋势

近日&#xff0c;中国计算机学会&#xff08;CCF&#xff09;计算机安全专委会中来自国家网络安全主管部门、高校、科研院所、大型央企、民营企业的委员投票评选出2023年网络安全十大发展趋势。 趋势一 数据安全治理成为数字经济的基石 我国《数据安全法》提出“建立健全数据…

spring的启动过程(一) :IOC容器的启动过程

一、web容器的加载 首先我们要先知道一个web项目的启动过程。 将Web项目部署到Tomcat中的方法之一&#xff0c;是部署没有封装到WAR文件中的Web项目。要使用这一方法部署未打包的webapp目录&#xff0c;只要把我们的项目&#xff08;编译好的发布项目&#xff0c;非开发项目&am…

掌握MySQL分库分表(五)SpringBoot2+MybatisPlus整合Sharding-Jdbc水平分表实现

文章目录创建Java-Maven项目创建数据库、表创建Java实体类配置启动类水平分表配置文件配置测试分库分表实现分析控制台SQL逻辑SQL真实SQL主键重复问题创建Java-Maven项目 添加依赖 <properties><java.version>11</java.version><maven.compiler.source&…

PMP考试有没有什么技巧可以介绍一下么?

一、试题形式 ——中英文对照 即每道题都是一遍英文&#xff0c;一遍翻译的中文&#xff0c;在审题的时候有一些小的技巧需要注意。首先如果你的英文水平足够好&#xff0c;建议直接阅读原文。PMP试题毕竟是美国人出的&#xff0c;语言的组织、思想的表达&#xff0c;肯定更符…

python居然能语音控制电脑壁纸切换,只需60行代码

前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 家在日常的电脑使用中&#xff0c;都会有自己喜爱类型的桌面 单纯的桌面有时候会让人觉得单调 今天&#xff0c;就由我带领大家只用60行代码打造一款语音壁纸切换器程序&#xff0c; 让大家能够通过语音的方式来控制电脑去…

c++模板的简单认识

文章目录 前言一.泛型编程 函数模板 模板参数的匹配原则 类模板总结前言 ADD函数很好写&#xff0c;但是如果我们要有int类型的&#xff0c;double类型的&#xff0c;char类型的等等各种类型&#xff0c;难道要写这么多不同的ADD函数吗&#xff0c;这么写简直太麻…

Linux:基于bufferevent epoll tcp服务器代码

基于bufferevent epoll tcp服务器代码: #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> #include <event2/event.h> #include <event2/buffer…

Excel/Word的一些快捷操作整理

Excel/Word的一些快捷操作整理 1. 给Word文件导入目录 前提&#xff1a;大致内容已经定稿&#xff0c;文章中各标题分级明确&#xff0c;最好各级标题字体大小设置不一样。 步骤&#xff1a;在头部导航栏&#xff0c;选择**“引用”–“目录”**&#xff0c;根据自己需求选择其…

KDJB1200六相继电保护测试仪

一、概述 KDJB1200继电保护测试仪是在参照电力部颁发的《微机型继电保护试验装置技术条件(讨论稿)》的基础上&#xff0c;广泛听取用户意见&#xff0c;总结目前国内同类产品优缺点&#xff0c;充分使用现代新的的微电子技术和器件实现的一种新型小型化微机继电保护测试仪。可…

DataWhale 大数据处理技术组队学习task3

四、分布式数据库HBase 1. 产生背景 1.1 Hadoop的局限性 优点&#xff1a;存储结构化、半结构甚至非结构化的数据&#xff0c;是传统数据库的补充&#xff0c;是海量数据存储的最佳方法。缺陷&#xff1a; 只能进行批处理&#xff0c;并且只能以顺序的方式访问数据。&#x…

【C++】-- 异常

目录 C语言传统的处理错误的方式 C异常概念 异常的使用 异常的抛出和捕获 自定义异常体系 异常的重新抛出 异常安全 异常规范&#xff08;C期望&#xff09; C标准库的异常体系 异常的优缺点 C异常的优点 C异常的缺点 总结 C语言传统的处理错误的方式 传统的错误…

zookeeper单机部署

一.下载zookeeper压缩包 二.上传解压安装包到/data/zookeeper目录&#xff0c;并解压 tar -zxvf apache-zookeeper-3.5.8-bin.tar.gz 三.修改配置文件 cd apache-zookeeper-3.5.10-bin/conf mv zoo_sample.cfg zoo.cfg vi zoo.cfg 修改为如下&#xff1a; dataDir/data/zooke…

【研究空间复用及函数调用问题】

本篇总结函数调用过程会存在的一些奇怪现象&#xff0c;空间复用问题&#xff0c;其实本质上涉及函数调用的底层原理&#xff0c;理解函数栈帧的创建和销毁这样的问题直接迎刃而解。1.空间复用问题案例1案例22.函数调用过程不清晰问题案例33.总结1.空间复用问题 案例1 我们先…

程职场人必备微软出品的实用小工具

系统增强工具PowerToys 下载地址&#xff1a;https://github.com/microsoft/PowerToys 什么是 Windows 系统中&#xff0c;最好的辅助工具&#xff1f; PowerToys 一定可以获得提名。PowerToys 是一款来自微软的系统增强工具&#xff0c;就像是一个神奇的系统外挂&#xff0c;…

精确控制 AI 图像生成的破冰方案,ControlNet 和 T2I-Adapter

ControlNet 和 T2I-Adapter 的突破性在哪里&#xff1f;有什么区别&#xff1f;其它为 T2I 扩散模型施加条件引导的相关研究ControlNet 和 T2I-Adapter 的实际应用效果如何&#xff1f;使用体验上&#xff0c;跟 SD原生支持的 img2img 有什么区别&#xff1f;ControlNet 在插画…

电商数据采集——2022年中国手机行业数据浅析

据国家统计局数据显示&#xff0c;2022年12月&#xff0c;国内手机产量当期值为14310.3万台&#xff0c;同比下降18.4%&#xff1b;累计值为156080万台&#xff0c;同比下降6.2%。 据中国信通院数据显示&#xff0c;2022年12月&#xff0c;国内市场手机出货量2786.0万部&#x…

F.pad() 函数

F.pad() 对tensor 进行扩充的函数。 torch.nn.functional.pad (input, pad, mode‘constant’, value0) input&#xff1a;需要扩充的 tensor&#xff0c;可以是图像数据&#xff0c;亦或是特征矩阵数据&#xff1b;pad&#xff1a;扩充维度&#xff0c;预先定义某维度上的扩充…