当前位置: 首页 > news >正文

万字指针超详细总结

🏠个人主页:泡泡牛奶

🌵系列专栏:C语言从入门到入土

本期将会带大家来认识什么是指针、指针的类型有哪些、指针运算、一级指针、二级指针、指针数组、数组指针、函数指针、函数指针数组等等相关知识,真正从0开始认识指针到指针的各种操作,让你在日常刷题、准备考试也能得心应手(≧∀≦)ゞ

赶快让我们看看今天的内容吧( ̄︶ ̄)>[GO!]

99749488_p0

文章目录

  • 🚀1. 什么是指针?
    • ✨1.1 如何进行编址?
  • 🚀2. 指针和指针类型
    • ✨2.1 指针的类型
    • ✨2.2 指针类型的意义
  • 🚀3. 野指针
    • ✨3.1 野指针成因
    • ✨3.2 如何规避野指针
  • 🚀4. 指针运算
    • ✨4.1 指针 +- 整数
    • ✨4.2 指针 - 指针
    • ✨4.3 指针的关系运算
  • 🚀5. 指针和数组
  • 🚀6. 字符指针(char*)
  • 🚀7. 泛型指针(void*)
  • 🚀7. 二级指针
  • 🚀8. 指针数组
  • 🚀9.数组指针
    • - 小试牛刀
  • 🚀10. 数组参数、指针参数
    • ✨10.1 一维数组传参
    • ✨10.2 二维数组的传参
    • ✨10.3 一级指针传参
    • ✨10.4 二级指针传参
  • 🚀11. 函数指针
  • 🚀12. 函数指针数组
  • 🚀13. 指向 函数指针数组 的指针
  • 🚀14. 回调函数

🚀1. 什么是指针?

要理解指针, 我们首先要了解2个要点:

  • 指针是内存中一个最小单元的编号,也就是地址

  • 平时所说的指针,指的是指针变量,即用来存放内存地址变量

内存

image-20220831200608387

指针变量

我们可以通过& (取地址操作符) 取出变量的内存起始地址,将地址存放到一个变量之中,这个变量就是我们所称的指针变量

#include <stdio.h>

int main()
{
    int a = 10;//在内存中申请一块空间
    int* p = &a;//用 变量p 存放a的地址
    
    return 0;
}

类比:

  1. 整型的变量,叫整型变量
  2. 地址的变量,叫指针变量

注意:

一个地址占用一个字节,而指针访问的字节数量由指针的类型来决定

image-20220831215824390 image-20220831220120695

✨1.1 如何进行编址?

对于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

这里就有 2 32 2^{32} 232 个地址,按每个地址是一个字节来算
2 32 B y t e = 2 32 1024 k B = 2 32 1024 ∗ 1024 M B = 2 32 1024 ∗ 1024 ∗ 1024 G B = 4 G B 2^{32} Byte = \frac{2^{32}}{1024} kB= \frac{2^{32}}{1024*1024} MB = \frac{2^{32}}{1024*1024*1024} GB = 4GB 232Byte=1024232kB=10241024232MB=102410241024232GB=4GB
32位机器下有4G的闲置空间进行编址

同理,如果是64位的机器,就有 2 64 2^{64} 264 根地址线,到底有多大,不妨自己进行计算一下( •̀ ω •́ )✧

通过上面的介绍,我们可以明白:

  • 在32位机器就需要 32个二进制位 进行二进制排序,那么就需要用到 4B 的空间来存储,故一个32位平台下的指针就应该是4个字节。
  • 同理,在64位机器上,就有64个地址线,那么指针变量的大小就是8个字节。

总结:

  • 指针是用来存放地址的,地址是唯一一块地址空间
  • 指针在32位平台是4个字节,在64位平台是8个字节

🚀2. 指针和指针类型

✨2.1 指针的类型

我们知道,变量都是有不同类型的,例如整型、浮点型等。那指针有没有类型呢?

准确的说是有的,但是指针的类型并不会改变指针的大小。

有这样一段代码:

int num = 10;
p = &num;

如果我们想要将 &num (num的地址) 保存到 p 中,已知 p是一个指针变量,那么它的类型就应该是 int* 类型。

char* pc = NULL;//字符型
short* ps = NULL;//短整型
int* pi = NULL;//整型
long* pl = NULL;//长整型

float* pf = NULL;//单精度浮点型
double* pd = NULL;//双精度浮点型

void* pv = NULL;//泛型指针

注意:

有些人可能会有一个疑问,* 到底该靠左边写呢?还是右边写呢?

  • int* pi 可以很容易理解 piint* 类型的,但是这样写也相对会带来一个风险,当出现int* p1, p2; 这样多个命名的写法时,有些人会认为 p2 也是 int* 类型的,但这却是错的p2 实际上的类型是 int 类型。
  • int *p1, *p2 这样的写法解决了上面的风险,但却相较于*靠左边写比较难看出来类型

总之,只要能分的清楚* 在左边 和 在右边 的 优势和劣势,怎么写都行φ(゜▽゜*)♪

通过上面可以看到,指针的定义方式是: type + *

其实:

char* 类型的指针是为了存放 char 类型变量的地址

int* 类型的指针是为了存放 int 类型变量的地址

✨2.2 指针类型的意义

1. 进行解引用操作时,访问字节数量

#include <stdio.h>

int main()
{
    int n = 0x11223344;
    
    char *pc = (char*)&n;
    int *pi = &n;
    
    *pc = 0;
    *pi = 0;
    
    return 0;
}

指针1

可以看到 char 类型进行解引用操作时访问的是1个字节,而 int 类型进行解引用操作访问的是4个字节

2. 决定指针 向前向后 走一步所跨过的字节 (步长)

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

    char* pc = (char*)arr;
    int* pi = arr;

    *pi = 0x11223344;
    *pc = 0;

    *(pi + 1) = 0x11223344;
    *(pc + 1) = 0;

    return 0;
}

指针2

通过上面的例子,我们可以看到 char 类型是跳过1个字节, 而 int 类型跳过4个字节

🚀3. 野指针

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

✨3.1 野指针成因

1. 指针未初始化

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

2. 指针越界访问

#include <stdio.h>

int main()
{
    int arr[5] = {0};
    int *pi = arr;
    int i = 0;
    for (i=0; i<=5; ++i)
    {
        //当指针指向数组规定的范围时,p就是野指针
        *(pi++) = i;
    }
    return 0;
}

3. 指针所指向的空间被释放

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

int main()
{
    int* nums = (int*)malloc(sizeof(int)*5);
    if (!nums)
    {
        return -1;
    }
    
    for (int i = 0; i<5; ++i)
    {
        nums[i] = i;
    }
    
    free(nums);
    
    for (int i = 0; i<5; ++i)
    {
        nums[i] = i;
    }
    
    return 0;
}

指针3

上面可以看到,被 malloc 开辟的空间被释放后,指针nums 就变为野指针,再去访问这块空间就会被当成随机访问

✨3.2 如何规避野指针

  1. 指针初始化
  2. 注意指针越界
  3. 指针所指向的空间被释放后,使器置为NULL
  4. 避免返回局部变量的地址
  5. 指针使用之前检查其有效性

🚀4. 指针运算

✨4.1 指针 ± 整数

用于表示指针 向前 或 向后 走的步数

int arr[5];
int *pi = arr+3;

*(pi+1) = 4;
*(pi-1) = 3;

✨4.2 指针 - 指针

用于表示 前后两个指针 之间的 元素个数

int my_strlen(char* str)
{
    char* p = s;
    while (*p != '\0')
    {
        ++p;
    }
    return p-s;
}

✨4.3 指针的关系运算

C语言标准规定:

允许 指向数组元素的指针 与 指向数组 最后一个元素后面 的那个内存位置的指针比较,但是不允许与 指向第一个元素之前 的那个内存位置的指针进行比较。

image-20220902172905316

安全写法:

for (vp = &a[N]; vp > & &a[0]; )
{
    *--vp = 0;
}

危险写法:

for (vp = &a[N-1]; vp >= &a[0]; vp--)
{
    *vp = 0;
}

注意: 虽然这样的写法再绝大部分编译器上使可以顺利完成任务的,但我们还是应该尽量避免这样的写法,因为标准规定不保证它可行。

🚀5. 指针和数组

请看下面例子:

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

运行结果:

image-20220902180042784

可以看到数组名和数组首元素地址是一样的。

结论: 数组名 表示的是 数组首元素地址。

注意:以下2种情况除外

  1. sizeof(arr) 表示整个数组的(字节)大小
  2. &arr 表示整个数组,&arr + 1 跳过整个数组

那么,现在我们知道数组名可以表示数组的首元素地址,那么我们是否可以将数组首元素地址存放到一个指针中,利用指针来访问数组呢?

答案当然是可以的:

#include <stdio.h>

int main()
{
    int arr[] = { 1,1,4,5,1,4,1,9,1,9,8,1,0 };
    int* p = arr;
    int sz = sizeof(arr)/sizeof(arr[0]);
    
    for (int i = 0; i<sz; ++i)
    {
        printf("%d ", *(p+i));
    }
    
    return 0;
}

🚀6. 字符指针(char*)

一般使用:

int main()
{
    char ch = 'w';
    char* pc = &ch;
    *pc = 'w';
    return 0;
}

还有一种使用方法如下:

int main()
{
    const char* pstr = "hello world!";//常量字符串
    printf("%s\n", pstr);
    return 0;
}

指针指向字符串可以类比数组,同样是指向首元素地址。

那么,有这样一个问题:

#include <stdio.h>

int main()
{
    char str1[] = "hello world!";
    char str2[] = "hello world!";
    
    char *str3 = "hello world.";
    char *str4 = "hello world.";
    
    if (str1 == str2)
        printf("str1 和 str2 相同\n");
    else
        printf("str1 和 str2 不相同\n");
    
    if (str3 == str4)
        printf("str3 和 str4 相同\n");
    else
        printf("str3 和 str4 不相同\n");
    
    return  0;
}

最终输出结果为:

image-20220903145140406

原因: str1str2 分别是两个不同的数组,即使数组内容相同,所占用的空间依然不同;str3str4 指向的是同一个相同的常量字符串,C/C++会把相同的常量字符串存放在一个单独的空间,当存在几个指针指向同一个字符串的时候,它们实际会指向同一块内存。

对比:

#include <stdio.h>

int main()
{
    char str1[] = "hello world!";
    char str2[] = "hello world!";

    char* str3 = "hello world.";
    char* str4 = "hello world.";
    char* str5 = "hello world!";

    printf("%p\n", str1);
    printf("%p\n", str2);
    printf("%p\n", str3);
    printf("%p\n", str4);
    printf("%p\n", str5);

    return  0;
}

image-20220903145312120

str3str4 指向的常量字符串相同,所以str3 == str4,而str5 所指向的常量字符串不相同,故 str3 != str5

🚀7. 泛型指针(void*)

泛型指针,顾名思义,指针具有泛用性,什么类型的指针都可以接收,而这通常也用于函数中进行使用。

泛型指针特点:

  1. 可以 接收任何类型 的指针
  2. 泛型指针访问字节数0

注意: void* 只能接收,不能 指向数据(不能通过void*访问数据)

**思考:**那么这样的指针到底有什么用呢🤔?

  • 可以利用可以接收任何类型的特点,来实现一个可以应对各种类型的数据
  • 在使用过程中可以将泛型指针转换成其它类型

例如:

int fun(void* p, void* q)
{
    return *((int*)p) - *((int*)q);
}

如果想知道更多,请接着往下看哦( •̀ ω •́ )✧

🚀7. 二级指针

我们知道,指针变量也是变量,既然是变量就有地址,那么指针变量的地址存放在哪里?

image-20220903174810955

二级指针 可用于存放一级指针的地址

对于二级指针的运算有:

  • *pi 通过对 pi 中地址进行解引用,这样找到的是i*pi 其实访问 的就是 i

  • **ppi 先通过 *ppi 找到 pi 内存放的值, 然后再通过 *pi 找到 i 内存放的值

int i = 10;
int *pi = &i;//pa 等价于 &a
int **ppi = &pi;

**ppi = 30;
//等价于 *pa = 30;
//等价于 a = 30;

🚀8. 指针数组

**Q:**指针数组到底是 指针 还是 数组 🤔?

**A:**是 数组

类比:

  • 整型数组:int arr1[5] 用于连续存放一组整型数据
  • 字符数组:char arr2[5] 用于连续存放一组字符型数据

image-20220913202917668

那么指针数组是什么样的?

int* arr3[5];

解释:arr3首先与[]结合,说明arr3是一个数组,数组里面存放了5个元素,每个元素是int*类型

按操作符的优先级来说,arr3首先会与[]结合,再看到*

image-20220913203707711

#include <stdio.h>

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

    int* arr[3] = { arr1,arr2,arr3 };

    for (int i = 0; i < 3; ++i)
    {
        for (int j = 0; j < 5; ++j)
        {
            //写法一
            printf("%d ", *(arr[i] + j));
            //写法二
            //printf("%d ", arr[i][j]);
        }
        printf("\n");
    }

	return 0;
}

我们知道,数组名代表其元素的首元素地址,通过arr[i] 访问到具体哪个地址,再通过地址访问到数组元素

总结:

什么是指针数组🤔?

存放指针的数组,就是指针数组。

🚀9.数组指针

指针是数组是数组,那么数组指针就是指针。

通过上面类比,我们可以思考思考:

什么是 数组指针🤔?

如同上面所说,按优先级来看,如果写成int* arr[5] 又是指针数组,那么该如何表示呢?

类比:

  • 整型指针:int* pi = &a( 假设定义了 int a = 0

  • 浮点型指针:float* pf = &b ( 假设定义了 float b = 0.0f

int (*p)[10];

解析: p先与*结合,说明p是一个指针变量,然后指向一个大小为10的整型数组。所以p是一个指针,指向一个数组,脚数组指针。

使用实例:

#include <stdio.h>

int main()
{
    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
    
    int(*pa)[10] = arr;
    //error
    //arr是首元素地址,为int*类型
    
    int(*pa)[10] = &arr;
    //指向整个数组
    
    for (int i = 0; i<10; ++i)
    {
        printf("%d ",(*pa)[i] );
    }
    
    return 0;
}

小结:

  • Q:什么是 数组指针🤔?

  • A:数组指针就是一个指向 (整个)数组 的指针。

注意:

指针的类型需要与数组的类型相同,以上面为例,arr 的类型是int[10],那么(*pa)的类型也应该是int[10]

- 小试牛刀

现在我们已经对 指针数组数组指针 有了一定的了解了,那么就来试试下面几个例子吧φ(゜▽゜*)♪

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

按优先级结合顺序来说,parr1首先与[]结合,确定是数组,是什么数组?向外看,类型是int*类型,是 一个存放int*类型的 指针数组

  1. int (*parr2)[10]

parr2首先与*结合,是指针,是什么指针?向外看类型为int [10],是一个指向有10个元素的整型数组的 数组指针

  1. int (*parr3[10])[5]

``parr3首先与[]结合,说明()内部是**数组**,去除parr3[10]后剩下int (*)[5]`,可以看出这是一个数组指针,那么组合在一起就是一个数组指针数组

image-20220917233250473

🚀10. 数组参数、指针参数

在写代码的时候难免要将数组或者指针传给数组,那么函数的参数该如何设计呢?

✨10.1 一维数组传参

我们知道,数组名就是首元素的地址,而指针又是可以接收数组的存在,那么我们是否可以这样写?

void test1(int arr[])//    1
{}
void test2(int arr[10])//  2
{}
void test3(int* arr)//     3
{}
void test4(int* arr[10])// 4
{}
void test5(int** arr)//    5
{}
  1. void test1(int arr[])
  2. void test2(int arr[10])
  3. void test3(int* arr)
#include <stdio.h>

//假设定义了以上代码

int main()
{
    int arr1[20] = {0};
    test1(arr1);
    test2(arr1);
    test3(arr1);
    
    int *arr2[10];
    test4(arr2);
    test5(arr2);
    
    return 0;
}

1、2、3的调用方式都相同,虽然void test2(int arr[10])中参数为int arr[10]但是还是能访问到20个元素,因为数组在内存中是连续存放

✨10.2 二维数组的传参

void test1(int arr[3][5])//有具体数值
{}
void test2(int arr[][5])//省略行
{}

//error
//不能都省略
void test3(int arr[][])
{}

总结:

二维数组传参,函数参数的设计只能省略 第一个[]的数字。对于一个二维数组而言,可以不知道有多少行,但是必须知道一行有对少个元素,这样才能方便运算。

在数组一章中 🚀点此传送门[数组] ,我们知道二维数组在内存中存储实际上与一维数组相同,都是由低地址向高地址连续存储,那么我们是否也是可以将二维数组以一维数组的方式进行传参呢🤔?答案是可以的。

void test4(int* arr)
{}

结合指针数组,也可以写成下面这样

#include <stdio.h>
#include <assert.h>

void test5(int** arr, int row, int col)
{
    int i = 0;
    for (i = 0; i < row; ++i)
    {
        int j = 0;
        for (j = 0; j < col; ++j)
        {
            arr[i][j] = i + j;
            printf("%d ", arr[i][j]);
        }
        printf("\n");
    }
}

void test6(int* arr[5], int row, int col)
{}
    
int main()
{
    int i = 0;
    int* arr[5];
    
    //构建二维数组
    for (i=0; i<5; ++i)
    {
        int* tmp = (int*)malloc(sizeof(int)*10);
        assert(tmp);
        arr[i] = tmp;
    }
    
    //传参
    test5(arr, 5, 10);
    test6(arr, 5, 10);
    
    
    return 0;
}

运行结果:

image-20220917234342833

而这样的传参方法多可能会在OJ(例如:力扣)上遇到 ( •̀ ω •́ )✧暗示

✨10.3 一级指针传参

#incldue <stdio.h>

void test(int *p, int sz)
{
    int i = 0;
    for (i=0; i<sz; ++i)
    {
        *(p+i) = i;
        printf("%d ", *(p+i));
    }
}

int main()
{
    int arr[10] = {0};
    int *p = arr;
    int sz = sizeof(arr)/sizeof(arr[10]);
    
    //一集指针p,传给函数
    test(arr, sz);
    
    return 0;
}

思考🤔

当函数参数为一级指针时,函数可以传什么值?

  1. 传数组

主要用于对数组进行操作

  1. 传单个数值

用于修改某个数的值 (在之后的学习中,相信大家会遇到很多这样的情况☺️)

✨10.4 二级指针传参

#include <stdio.h>

void test(int **ptr)
{
    printf("%d\n", **ptr);
}

int main()
{
    int n = 10;
    int *p = &n;
    int **pp = &p;
    test(pp);
    test(&p);
    return 0;
}

二级指针接收一集指针地址,传参的时候需要参数为一级指针地址

🚀11. 函数指针

首先我们来看一下下面一段代码:

#include <stdio.h>

void test()
{
    printf("hehe\n");
}

int main()
{
    printf("%p\n", test);
    printf("%p\n", &test);
    
    return 0;
}

输出结果为:

image-20220918153731193

输出的是两个相同的地址,而这两个就是test函数的地址,那么要怎样将函数的地址存起来呢?

//假设有以下函数定义
void test(int i)
{
    printf("haha\n");
}

//那么函数指针应该为
void (*pfun)(int) = test;

pfun首先与*结合,说明pfun是指针,其指向的是一个函数,指向的函数参数为int,返回类型为void

看两段有意思的代码:

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

    对代码稍微进行简化一下

    typedef void (*type_t)();
    
    //函数指针在进行调换是要将名字放在()里
    //理解上:效果等同于
    //typedef void (*)() type_t;
    
    //简化后
    (* (type_t) 0 )()
    

    可以发现,0被强制类型转换成了函数指针类型,再进行函数调用。

  • void (* signal( int , void(*)(int) ) )(int)

    我们按照同样的方法对大妈进行简化

    typedef void(*type_t)(int);
    //简化后
    type_t signal(int, type_t);
    

    可以轻易看出:

    1. signal是一个函数声明,一个参数是int,另一个参数是函数指针参数int返回类型void
    2. signal的返回类型也是一个函数函数指针,该指针指向一个函数参数int返回类型void

🚀12. 函数指针数组

数组是一个存放相同类型数据的储存空间,类比指针数组:

int* arr[10];
//arr先与[]结合,每个元素是int*

仿照指针数组

  1. 首先名字要与[]先结合,再写出类型int (*)() parr[10]

  2. 再根据函数指针的语法规定,将数组放入()内部,于是就出现了下面这样

    int (* parr[10] )();
    

那么对于这样的函数指针数组,它的用途是什么呢?

答:转移表

可以将 函数 参数相同返回类型相同 的一类函数用一个数组存起来,最后可以通过数组的下标调用函数

而最简单的实例就是:计算器

🚀13. 指向 函数指针数组 的指针

对比指向 指针数组 的指针:

指针指向一个数组,数组每个元素都是指针(指路✨->二维数组传参)

int* arr[10];

int **p = &arr;

那么我们接下来看看指向函数指针数组的指针要怎么定义吧😎。

void test(const char* str)
{
    printf("%s\n", str);
}

int main()
{
    //函数指针
    void (*pfun)(const char*) = test;
    
    //将函数指针存入数组
    void (*pfarr[5])(const char*);
    pfarr[0] = test;
    
    //指向函数指针数组pfarr的指针ppfarr
    void (* (*ppfarr[5]) )(const char*) = &pfarr;
    
    return 0;
}

🚀14. 回调函数

回调函数就是通过函数指针调用的函数。将函数的地址作为参数传递给另一个函数, 当这个函数指针用来调用其所指向的函数时,我们就说这是回调函数。

qsort这个函数就是利用了回调函数,下面为大家简单介绍一下这个函数吧😎

image-20220918194754335

base - 需要排序的数组

num - 数组元素个数

size - 每个元素的大小

compare - 比较两个数的函数

#include <stdio.h>

//回调函数
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 sz = sizeof(arr) / sizeof(arr[0]);
	int i = 0;
    
	qsort(arr, sz, sizeof(int), cmp);
    
    //打印
	for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++)
	{
		printf( "%d ", arr[i]);
	}
	printf("\n");
    
	return 0;
}

现在我们已经基本了解 什么是回调函数 与 qsort的基本使用方法 ,那么能不能试着仿照 qsort 写一个冒泡排序呢?

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 BubbleSort(void* base, size_t num, size_t size,
            int (*cmp)(const void*,const void*))
{
    int i = 0;
    int j = 0;
    for (i=0; i<num-1; ++i)
    {
        int flag = 1;
        for (j=0; j<num-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 );
                flag = 0;
            }
        }
        if (flag)
        {
            break;
        }
    }
}

注意:

base需要强制类型转换成char*,因为void*的访问的是0字节,传入具体参数需要具体参数,至于转成char*是因为,char*每次跳过一个字节,方便访问地址

如果有其它想要了解的函数可以考虑去cplusplus官网看看,连接我就放在这里啦(≧∀≦)ゞ


好啦ヾ(*))) 本期的内容就到这里,如果觉得对你有帮助的话,还不忘三连支持一下,谢谢ο(=•ω<=)ρ⌒☆

这一次真的是爆肝了(;´д`)ゞ超长篇的大总结,如果对你有帮助的话,还不忘动动手指给予我一点点支持吧o(TヘTo)

相关文章:

  • 列表页常见 hook 封装
  • 集合_HashSet(HashMap)扩容机制源码简析
  • Spring注解@Qualifier的详细用法你知道几种「扩展点实战系列」- 第444篇
  • uni-app 微信小程序中关于 map 地图使用案例分享
  • 工业级成熟航运港口人工智能产品全球前三船公司及港口码头落地,中国上海人工智能独角兽中集飞瞳全球应用最广规模最大最先进港航AI企业
  • CSS基础篇---02选择器进阶、背景样式、显示模式
  • 【C语言】自定义类型 —— 结构体
  • 千万级用户ms级抽奖N名设计方案
  • 2022第五空间WEBMISC
  • 说几句得罪人的大实话
  • Spark 优化 (二) --------- Spark 数据倾斜
  • 第01篇:系统化学习, 搞定Spring容器管理
  • 【Android】-- Intent(显式和隐式Intent)
  • 【HashMap】HashMap的6种遍历方法
  • 网络中其他重要技术与协议(DNS系统,ICMP协议,NAT技术与代理服务器)
  • @jsonView过滤属性
  • 【跃迁之路】【733天】程序员高效学习方法论探索系列(实验阶段490-2019.2.23)...
  • canvas 高仿 Apple Watch 表盘
  • eclipse(luna)创建web工程
  • Java 23种设计模式 之单例模式 7种实现方式
  • Java超时控制的实现
  • JS函数式编程 数组部分风格 ES6版
  • JS学习笔记——闭包
  • PHP 程序员也能做的 Java 开发 30分钟使用 netty 轻松打造一个高性能 websocket 服务...
  • Phpstorm怎样批量删除空行?
  • 高度不固定时垂直居中
  • 七牛云 DV OV EV SSL 证书上线,限时折扣低至 6.75 折!
  • 吐槽Javascript系列二:数组中的splice和slice方法
  • 推荐一个React的管理后台框架
  • 小程序开发之路(一)
  • 验证码识别技术——15分钟带你突破各种复杂不定长验证码
  • 容器镜像
  • ​flutter 代码混淆
  • ​linux启动进程的方式
  • #pragam once 和 #ifndef 预编译头
  • $refs 、$nextTic、动态组件、name的使用
  • (2022 CVPR) Unbiased Teacher v2
  • (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例
  • (echarts)echarts使用时重新加载数据之前的数据存留在图上的问题
  • (ZT)薛涌:谈贫说富
  • (五)MySQL的备份及恢复
  • (小白学Java)Java简介和基本配置
  • (一)Java算法:二分查找
  • (一)pytest自动化测试框架之生成测试报告(mac系统)
  • (转)Groupon前传:从10个月的失败作品修改,1个月找到成功
  • .net core 6 redis操作类
  • .net mvc actionresult 返回字符串_.NET架构师知识普及
  • .Net 垃圾回收机制原理(二)
  • .NET 设计模式—适配器模式(Adapter Pattern)
  • .net 使用ajax控件后如何调用前端脚本
  • .NET/C# 利用 Walterlv.WeakEvents 高性能地中转一个自定义的弱事件(可让任意 CLR 事件成为弱事件)
  • .NET3.5下用Lambda简化跨线程访问窗体控件,避免繁复的delegate,Invoke(转)
  • .NET开发不可不知、不可不用的辅助类(三)(报表导出---终结版)
  • .NET命名规范和开发约定
  • .Net小白的大学四年,内含面经