五大板块(2)—— 指针

2023-10-27

参考:五大板块(2)—— 指针
作者:丶PURSUING
发布时间: 2021-03-18 16:01:22
网址:https://blog.csdn.net/weixin_44742824/article/details/114981482

本文为学习笔记,整合课程内容及文章如下:

为什么要使用指针 板块:
参考:原文链接
作者:Cloudkip

指针,你说他难吧,其实都是在学校学的时候给劝退了,其实很简单,而且学会了之后老是想用,也很好用,以后看到指针就不会有心理障碍啦。

一、地址的引入

概念

地址是一个十六进制表示的整数,用来映射一块空间,是系统用来查找数据位置的依据。地址标识了存储单元空间,而字节就是最小的存储单位。

按字节的编址方式:每一个字节都有一个唯一的地址。例如:一个int型的变量是4个字节,就会对应4个地址,我们只需要取到这个变量的首地址就能得到完整的int型数据。

地址长啥样?

用一个例子感受变量存放的地址:

#include <stdio.h>

int main()
{
        int a=10;
        int b=11;
        int* p=&a;
        int* p2=&b;

        printf("a的地址是:%p\n",p);
        printf("b的地址是:%p\n",p2);

        return 0;
}

结果:可以发现两者地址相差4个字节,说明int型变量用4个字节的空间存放

a的地址是:0x7ea5d1dc
b的地址是:0x7ea5d1d8

大概可以表示为:

在这里插入图片描述

二、指针变量的引入

什么是指针?从根本上看,指针是一个值为内存地址的变量。

正如char型变量存放字符,int型变量存放整型数一样,指针变量存放的是地址,没有什么难理解的。

给指针赋值就是让其指向一个地址。

三、指针分类型与指针偏移量

用sizeof发现linux下所有指针类型的大小均为8字节。

平台:树莓派

首先明白:指针所占用的空间与指针指向的内容和内容的大小无关。
其次明白:在不同的操作系统及编译环境下,指针类型所占用的字节数是不同的
例如:
编译生成16位的代码时,指针占2个字节
编译生成32位的代码时,指针占4个字节
编译生成64位的代码时,指针占8个字节

整型指针,字符指针

#include <stdio.h>

int main()
{
        int a = 5;
        char b = 'A';

        int *pa = &a;//存放整型数的指针叫整型指针
        char *pb = &b;//而这叫字符型指针

        //printf("int型指针 pa 的地址是%p,指针偏移(++pa)的地址是:%p\n",pa,++pa);
        //printf("char型指针 pb 的地址是%p,指针偏移(++pb)的地址是:%p\n",pb,++pb);

        printf("int 型指针pa的地址是%p\n",pa);
        printf("int 型指针偏移(++pa)后的地址是:%p\n\n",++pa);

        printf("char 型指针pb的地址是%p\n",pb);
        printf("char 型指针偏移(++pb)后的地址是:%p\n",++pb);

        return 0;

}

结果:可以看到指针类型不同,其每次偏移的地址量也不同。

pi@raspberrypi:~/Desktop $ ./a.out  
int 型指针pa的地址是0x7ead81ec
int 型指针偏移(++pa)后的地址是:0x7ead81f0

char 型指针pb的地址是0x7ead81eb
char 型指针偏移(++pb)后的地址是:0x7ead81ec

不知道你会不会思考,为什么我不使用代码中被注释的两条语句,简短明了,而要使用4条printf。
你尽管试试,打印出来的pa和++pa是一样的,好似是地址没有偏移,这其实关系到了printf的出栈入栈问题,放在六、其他小知识点:printf 里的 a++,++a,真的有鬼!! 中详细展开。

函数指针(重点)

顾名思义,指向函数地址的指针。

无参无返的函数指针

这是函数指针最简单的一种形式

#include <stdio.h>

void print()//要被指向的函数
{
        printf("hello world\n");
}

int main()
{
        void (*pprint)() = NULL;//定义函数指针
        pprint = print;         //函数指针赋值:指向函数的首地址(就是函数名)
                                              //如同数组的首地址,是数组名
        pprint();        //调用方法1
        (*pprint)();     //调用方法2
        
        printf("函数指针pprint的地址是%p\n",pprint);
        printf("函数指针偏移(++pprint)后的地址是:%p\n",++pprint);

        return 0;
}

结果:

hello world
hello world
函数指针pprint的地址是0x1046c
函数指针偏移(++pprint)后的地址是:0x1046d

有参有返的函数指针

稍微上升点难度

#include <stdio.h>

int sum(int a,int b)//要被指向的函数
{
        int c = 0;
        c = a+b;
        return c;
}

int main()
{
        int total1;
        int total2;

        int (*psum)(int a,int b) = NULL;//定义函数指针

        psum = sum;           //函数指针赋值,指向函数的首地址(就是函数名)
                                            //如同数组的首地址,是数组名
        total1 = psum(5,6);   //调用方法1
        total2 = (*psum)(6,9);//调用方法2

        printf("total1:%d\ntotal2:%d\n",total1,total2);
		printf("%p\n",psum);
		printf("%p\n",++psum);
        return 0;
}

结果:

total1:11
total2:15
0x10440
0x10441

结构体中的函数指针

比较常见的还是和结构体的结合,这个容易看花眼。

#include <stdio.h>
#include <string.h>

struct student
{
        int english;
        int japanese;
        int math;
        int chinese;
        char name[128];
        int (*pLanguage)(int english,int japanese);//顺便复习函数指针怎么使用

};

int Language(int eng,int jap)//函数指针所指向的函数
{
        int total;
        total = eng + jap;
        return total;
}

int main()
{
        int lanSum;
        struct student stu1 = {
                .japanese = 90,
                .english = 100,
                .math = 90,
                .name = "华天朱",
                .pLanguage = Language,
        };

        lanSum = stu1.pLanguage(stu1.english,stu1.japanese);

        printf("stu1的名字是%s,他的语言综合分数是%d\n",stu1.name,lanSum);
		
		printf("%p\n",stu1.pLanguage);
		printf("%p\n",++stu1.pLanguage);
        return 0;
}

结果:

stu1的名字是华天朱,他的语言综合分数是190
0x10470
0x10471

规律总结

函数指针无非就三步走:

定义
类型 (*指针名)();

void (*pprint)() = NULL;

两个括号很好记

赋值
指针名 = 函数名

pprint = print;

调用
如有参数则调用时传

pprint();        //调用方法1
(*pprint)();     //调用方法2

数组指针(少用)

顾名思义,就是指向数组地址的指针。

目前还没碰到数组指针的使用,涉及即更新

#include <stdio.h>

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

        int (*p)[3] = NULL;
        p = a;
        
        printf("%p\n",p);
        printf("%p\n",++p);

        return 0;
}

结果:偏移了整个数组的大小12字节

0x7ede61e8
0x7ede61f4

指针数组(少用)

存放一系列指针的数组,本质是数组。

#include <stdio.h>

int main()
{
        int a=1;
        int b=2;
        int c=3;

        int *parray[3] = {&a,&b,&c};
        int i;

        printf("指针数组的第一个元素是:%p,地址的内容是:%d\n",parray[0],*parray[0]);
        
        return 0;
}

结果:

指针数组的第一个元素是:0x7ed501f4,地址的内容是:1

结构体指针(重点)

定义赋值调用与指针偏移

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

struct STU
{
        int score;
        char name[128];
};

int main()
{
        struct STU stu1 = {
                .score = 99,
                .name = "果粒臣",
        };

        //malloc为结构体指针开辟一块空间
        struct STU *pstu = (struct STU *)malloc(sizeof(struct STU));
        //结构体指针的赋值1:直接赋值,在此之前要开辟空间
        pstu->score = 100;
        strcpy(pstu->name,"华天朱");
        
        printf("%s:%d\n",pstu->name,pstu->score);
        free(pstu);//释放指针,重新指向一段地址
        
        //结构体指针的赋值2:指向结构体变量的地址
        pstu = &stu1;
        printf("%s:%d\n",pstu->name,pstu->score);

        //指针偏移
        printf("%p\n",pstu);
        printf("%p\n",++pstu);

        return 0;
}

结果:结构体偏移了4+128个字节

华天朱:100
果粒臣:99
0x7e905170
0x7e9051f4

实际应用例子

用一个结构体指针做一个最简单的学生成绩管理。

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

struct stud
{
        char* name;
        int score;
};

int main()
{
        int num;
        int i;
        printf("需要录入几个学生的成绩?\n");
        scanf("%d",&num);

        //这里开辟了num个结构体所需要的空间,动态分配内存
        struct stud *pstu = (struct stud *)malloc(sizeof(struct stud)*num); // 指针占用地址空间大小恒定,指向的内容需要提前分配好堆空间大小
        																	// char[5]是自动分配的栈空间																			


        for(i=0;i<num;i++){
                pstu->name = (char* )malloc(sizeof(char)*16);				// 结构体成员也是指针,指针占用地址空间大小恒定,指向的内容需要提前分配好堆空间大小
                memset(pstu->name,0,sizeof(char)*16);

                printf("请输入第%d个学生的名字\n",i+1);
                scanf("%s",pstu->name);
                printf("请输入第%d个学生的成绩\n",i+1);
                scanf("%d",&pstu->score);
                pstu++;
        }
        pstu -= num;//指针回头

        for(i=0;i<num;i++){
                printf("%s:%d\n",pstu->name,pstu->score);
                pstu++;
        }

        return 0;
}     

结果:

美羊羊:45
废羊羊:100
喜羊羊:60
灰太狼:76

野指针

是什么

野指针指向的地址是随机(又称为:"垃圾"内存)的,无法得知他的地址,操作系统自动对其进行初始化。

野指针是怎样生成的?

(1)创建指针时没有对指针进行初始化
(2)使用free释放指针后没有将其指向NULL

有什么危害

当一个指针成为野指针,指向是随机的,当你使用它时,危害程度也是随机而不可预测的。一般会造成内存泄漏也很容易遭到黑客攻击,只要将病毒程序放入这块内存中,当使用到这个指针时就开始执行。

如何避免

  • 定义指针时进行初始化

如果没有确定指向,就让它指向NULL

NULL在宏定义中是#define NULL (void **) 0,代表的是零地址,零地址不能进行任何读写操作

  • 要给指针指向的空间赋值时,先给指针分配空间,并且初始化空间

简单示例:

//char型指针
char *p = (char *)malloc(sizeof(char));
memset(p,0,sizeof(char));

//int型指针
//指针(指向地址)游标卡尺   开辟空间大小
int *p     =     (int *)malloc(sizeof(int));
memset(p,0,sizeof(int));

//结构体指针
struct stu *p = (struct stu *)malloc(sizeof(struct stu));
memset(p,0,sizeof(struct stu));

malloc动态内存分配,用于申请一块连续的指定大小的内存块区域以void*类型返回分配的内存区域地址。void *malloc(unsigned int size),因为返回值时void*,所以要进行强制转换。

memset将某一块内存中的内容全部设置为指定的值, 这个函数通常为新申请的内存做初始化工作,是对较大的结构体或数组进行清零操作的一种最快方法。void *memset(void *s, int ch, size_t n);

  • 释放指针同时记得指向NULL
free(p);
p = NULL;

malloc与内存泄漏

情景:
程序刚跑起来的时候没问题,时间久了程序崩溃,大多为内存泄漏。

最常见的情况是在无限的循环中一直申请空间。用malloc申请的空间,程序不会主动释放,只有当程序结束后,系统才回收空间。

避免在循环中一直申请空间,即使合理释放(free,指向NULL)

指针类型小测试

搞几个容易混淆的

int *p[4];
int (*p)[4];
int *p();
int(*p)();
指针数组,数组中存放的是一系列的地址
数组指针,指向一个数组
只是一个普通的函数,其返回值是int* 的指针
函数指针,指向一个函数

四、指针也可以作为数组传入的形式参数

数组作为子函数的形式参数小节中,子函数的形式参数我们用 int array[ ]来定义。

学了指针之后,我们也可以用 int *array来定义.这是因为前者的本质上传入的是数组的首地址,而指针也一样,需要传入数组的首地址。

如下:

#include <stdio.h>

int arraySum(int *array,int num)//数组形参,仅仅传递数组的首地址,代表不了个数。
{
        int sum;
        int i;
        for(i=0;i<num;i++){
                sum+=array[i];
        }
        return sum;

}

int main()
{
        int sum;
        int array[5]={0,1,2,3,4};

//      sum=arraySum(array,sizeof(array)/sizeof(array[0]));    //传递数组名
        sum=arraySum(&array[0],sizeof(array)/sizeof(array[0]));//或者传递首元素的地址(&)
                                //sizeof里面只能传入数组名                                                  
                    
        printf("sum=%d\n",sum);

        return 0;
}

五、为什么要使用指针?

(1)节省内存

指针的使用使得不同区域的代码可以轻易的共享内存数据,当然也可以通过数据的复制达到相同的效果,但是这样往往效率不太好。

指针节省内存主要体现在参数传递上,比如传递一个结构体指针变量和传递一个结构体变量,结构体占用内存越大,传递指针变量越节省内存,也就是可以减少不必要的数据复制。


在实际做项目的过程中,遇到了结构体多级嵌套导致mcu崩溃的情况(mcu ram吃紧)。

结构体变量和结构体指针变量作为函数参数传递问题

C基础-结构体-4-结构体,结构体指针作为函数传递的参数

#include <stdio.h>
#include <string.h>

struct Student {
        int age;
        char sex;
        char name[100];
};

void InputStudent(struct Student * pstu) {   //pstu只占四个字节
        (*pstu).age = 10;
        strcpy(pstu->name, "张三");
        pstu->sex = 'F';
}
void OutStudent(struct Student ss) {
        printf("%d  %c  %s\n", ss.age, ss.sex, ss.name);
}

int main(void) {
        struct Student st;
        InputStudent(&st);
        printf("%d  %c  %s\n",st.age,st.sex,st.name);
        OutStudent(st);
        return 0;
}

在这里插入图片描述

代码分析;

void OutStudent(struct Student ss) {
	printf("%d  %c  %s", ss.age, ss.sex, ss.name);
}

此处传递的是一个变量,此变量占的字节空间大,我们可以利用指针,指针只占四个字节空间,而且只存变量st的第一个字节地址,然而指针指向的是整个变量。因为指针前面的类型是struct Student代表的是整个变量。

修改为指针后速度变快,占的内存空间也减小

#include <stdio.h>
#include <string.h>
 
struct Student {
	int age;
	char sex;
	char name[100];
};
 
void InputStudent(struct Student * pstu) {   //pstu只占四个字节
	(*pstu).age = 10;
	strcpy(pstu->name, "张三");
	pstu->sex = 'F';
}
void OutStudent(struct Student * stu) {
	printf("%d  %c  %s\n", stu->age, stu->sex, stu->name);
}
 
int main(void) {
	struct Student st;
	InputStudent(&st);
	printf("%d  %c  %s\n",st.age,st.sex,st.name);
	OutStudent(&st);
	return 0;
}

在这里插入图片描述

当然眼睛是看不出来的,但是理论和事实就是这样的。

(2)在子函数中修改被传递过来的对象

C语言中的 一切函数调用中,值传递都是“按值传递” 的。如果要在函数中修改被传递过来的对象,就必须通过这个对象的指针来完成。

太抽象了不懂?举个栗子:

#include <stdio.h>

void add(int a)
{
        a = a+1;
        printf("add:a的值为%d\n",a);
}

int main()
{
        int a = 10;
        add(a);
        printf("main:a的值为%d\n",a);
        return 0;
}

结果:可以发现main函数中a的值并没有真正发生改变。

add:a的值为11
main:a的值为10

为什么没有改变呢?
函数add调用时,才申请了一个内存空间(虽然名字一样都是a,但对应不同的存储空间),才有了这个形参变量a,同时把实际参数(main中的a)的值拷贝一份给形式参数(add中的a),函数执行结束后释放空间,这个子函数中的变量自然也被释放了。

其中这个a就是传递入子函数add的对象,如果想要在这个子函数中修改a的值,就要使用指针。

#include <stdio.h>

void add(int *a)
{
        *a = *a+1;
        printf("add:a的值为%d\n",*a);
}

int main()
{
        int a = 10;

        add(&a);

        printf("main:a的值为%d\n",a);
        return 0;
}

结果:

add:a的值为11
main:a的值为11

传入了main中a的地址,再在子函数中修改这个地址中的内容,当然能够修改成功。

(3)动态分配内存

常常可以看到,程序使用的内存在一开始就进行分配(静态内存分配)。这对于节省计算机内存是有帮助的,因为计算机可以提前为需要的变量分配内存。

但是大多应用场合中,可能一开始程序运行时不清楚到底需要多少内存,这时候可以使用指针,让程序在运行时获得新的内存空间(动态内存分配),并让指针指向这一内存更为方便。

结构体指针实际应用举例中有涉及:

int num;

printf("需要录入几个学生的成绩?\n");
scanf("%d",&num);

//这里开辟了num个结构体所需要的空间,动态分配内存
struct stud *pstu = (struct stud *)malloc(sizeof(struct stud)*num);

(4)在指定地址写入数据(目前少用)

了解就行,JAVA等其他编程语言实现不了这种操作。

#include <stdio.h>

int main()
{
        volatile int *p = (volatile int *)0x7ead81eb;//强制转化成整型地址
        *p = 10;                                     //ARM架构 裸机编程 ARM驱动会使用
        printf("在地址%p中存放的数据是%d\n",p,*p);

        return 0;
}

结果:

在地址0x7ead81eb中存放的数据是10

注意哈,这个操作运行很有可能

Segmentation fault

这也正常,毕竟可能这地址放有东西或者不允许这样操作。

volatile和编译器的优化有关:

在这里插入图片描述

编译器的优化

在本次线程内,当读取一个变量时,为了提高读取速度,编译器进行优化时有时会先把变量读取到一个寄存器中(寄存器比内存要快!);以后再读取变量值时,就直接从寄存器中读取;当变量值在本线程里改变时,会同时把变量的新值copy到该寄存器中,以保持一致。

当变量因别的线程值发生改变,上面寄存器的值不会相应改变,从而造成应用程序读取的值和实际的变量值不一致。
当寄存器因别的线程改变了值,原变量的值也不会改变,也会造成应用程序读取的值和实际的变量值不一致。

volatile防止优化,每次都要从内存取数据,这样效率会慢于寄存器,但是提高准确度

(5)函数多个返回值

有时候我们总是希望一个功能子函数的返回值可以有很多个,但奈何用return只能返回一个。

碰到实际用上的例子再补充,不硬找例子。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

五大板块(2)—— 指针 的相关文章

  • Pentaho Report Designer 入门教程(二)

    Pentaho Report Designer 入门教程 二 采用Pentaho Report Designer5 1版本 也是最新的版本 一 安装和介绍 介绍部分内容略 首先安装jdk 并配置java相关环境变量 下载pentaho re
  • stm32学习总结:2、搭建基于CLion的stm32开发环境

    stm32学习总结 2 搭建基于CLion的stm32开发环境 文章目录 stm32学习总结 2 搭建基于CLion的stm32开发环境 1 前言 2 相关工具和环境准备 2 1 STM32CubeMX 前置工程创建工具 2 2 CLion
  • 敏捷:什么是用户故事(User Story)

    摘要 一件用户通过系统完成他一个有价值的目标 买一罐饮料 的事 这样的过程就叫 用户案例 user case 或者 用户故事 user story 本文描述了敏捷开发的技巧 如何以用户故事管理项目 什么是用户故事 user story 假定
  • 内网渗透-frp 用于内网穿透的基本配置和使用

    frp 用于内网穿透的基本配置和使用 文章目录 frp 用于内网穿透的基本配置和使用 前言 frps frpc 后记 参考 前言 frp 是一个专注于内网穿透的高性能的反向代理应用 支持 TCP UDP HTTP HTTPS 等多种协议 可
  • 【开源介绍】命令行的艺术( the-art-of-command-line )

    1 概述 转载 命令行的艺术 the art of command line
  • Blob数据类型、数据库事务

    1 Bolb是二进制长对象的意思 通常用于存储大文件 通过二进制数据保存到数据库里 并可以从数据库里恢复指定文件 2 如果需要将图片插入数据库 不能通过普通的SQL语句完成 Bolb常量无法表示 所以将Bolb数据插入数据库需要使用Prep

随机推荐

  • 合成孔径SAR卫星影像专业术语

    转载自 http www kosmos image com index php m content c index a show catid 73 id 4132 目录 Across track Active Remote Sensing
  • 初学机器学习:直观解读KL散度的数学概念

    选自thushv com 作者 Thushan Ganegedara 机器之心编译 机器学习是当前最重要的技术发展方向之一 近日 悉尼大学博士生 Thushan Ganegedara 开始撰写一个系列博客文章 旨在为机器学习初学者介绍一些基
  • 深度学习(Deep Learning)读书思考六:循环神经网络一(RNN)

    概述 循环神经网络 RNN Recurrent Neural Network 是神经网络家族中的一员 擅长于解决序列化相关问题 包括不限于序列化标注问题 NER POS 语音识别等 RNN内容比较多 分成三个小节进行介绍 内容包括RNN基础
  • QT窗体间传值总结之Signal&Slot

    在写程序时 难免会碰到多窗体之间进行传值的问题 依照自己的理解 我把多窗体传值的可以使用的方法归纳如下 1 使用QT中的Signal Slot机制进行传值 2 使用全局变量 3 使用public形式的函数接口 4 使用QT中的Event机制
  • 独立进程使用django模型(django.setup()使用)

    文章目录 独立进程使用django模型 独立进程使用django模型 步骤 django setup RuntimeError populate isn t reentrant 独立进程使用django模型报错 Apps aren t lo
  • 提升Postern代理性能的五个小技巧

    在使用Postern代理时 如何提高其性能是许多用户关注的问题 本文将分享一些针对Postern代理进行优化的技巧和建议 帮助更好地利用该工具并获得更出色的网络体验 Postern是一个功能强大且灵活易用的Android应用程序 可实现全局
  • 智能指针auto_prt的使用(c++学习笔记)

    c 中如果要申请资源一般用到new 最后释放资源delete 如果我们在delete之前就退出了函数呢 看下面的代码 cpp view plain copy include
  • 2 指定目录编译

    1 目录结构 指定目录编译 go build o bin calc1 exe day01 package example main 转载于 https www cnblogs com jec1999 p 9822834 html
  • TCP数据的传输过程

    TCP数据的传输过程 TCP Transmission Control Protocol 传输控制协议 是一种面向连接的 可靠的 基于字节流的通信协议 数据在传输前要建立连接 传输完毕后还要断开连接 客户端在收发数据前要使用 connect
  • Spark集群运行问题

    spark输出太多warning messages WARN Executor 2 block locks were not released by TID Lock release errors occur frequently in e
  • 阿里云对象存储oss费用明细

    https www aliyun com price product spm a311a 7996332 0 0 137630803P2qTh oss detail 最终决定 阿里云割韭菜 弃用选择业界其他便宜的 第二年阿里云只给你个续费
  • java操作svn--部分方法

    package com svnutil import java io File import java text DateFormat import java util ArrayList import java util Collecti
  • Fedora12 编译s3c2416 U-Boot1.3.4的Makefile和头文件

    复制Makefile到 和smdk2416 h到include configs 执行 make distclean make smdk2416 config make C Copyright 2007 2008 Jong pill Lee
  • matlab练习程序(Canny边缘检测)

    我可没直接调用系统函数 要是那样就太水了 其实我的matlab代码很容易就能翻译成c c 的 canny边缘检测一共四个部分 1 对原图像高斯平滑 2 对高斯平滑后的图像进行sobel边缘检测 这里需要求横的和竖的还有联合的 所以一共三个需
  • C语言链表——增删改查

    目录 一 链表的概念 1 1 什么是链表 二 链表和数组的区别 2 1 链表和数组的优缺点 2 1 1 数组的优缺点 2 1 2 链表的优缺点 三 链表的静态添加和动态遍历 四 统计链表节点个数及链表查找 五 链表插入 5 1 链表从指定节
  • 【程序设计训练】2-12 绩点计算

    问题描述 学校对本科生的成绩施行绩点制 GPA 将学生的实际考分根据不同学科的不同学分按一定的公式进行计算 规定如下 实际成绩 绩点 90 100 4 0 85 89 3 7 82 84 3 3 78 81 3 0 75 77 2 7 72
  • MIT教授Tegmark:GPT-4敲响警钟,百年后人类何去何从丨智源大会嘉宾风采

    导读 一封呼吁暂停大模型研究6个月的公开信让一家名为未来生命研究所 Future of Life Institute 简称 FLI 站上了风口浪尖 这家研究所的联合创始人Max Tegmark是来自麻省理工学院的物理学家和人工智能研究员 生
  • 对象存储OSS-iOS

    文章目录 对象存储OSS iOS 一 基础解读 1 相关名词 2 OSS的上传和下载 3 基于SDK快速开始 4 基于OSS的移动开发 4 1 整体流程 4 1 1 客户端申请STS凭证 4 1 2 AppServer请求AssumeRol
  • 2022华数杯B题论文思路分析+完整代码(水下机器人组装计划)(一二问答案接出来和标准答案一样)(问题三四逼近正确答案)(完整论文,代码可直接跑)

    写在前面 学校最近搞数学建模竞赛培训 以2022华数杯B题作为训练题目 在查资料过程中发现网上没有哪一篇论文解出了正确答案 而我们组利用Lingo软件准确的解出了正确答案 但是在第三问时 由于决策的变量激增 基于Lingo的模型已经无法解出
  • 五大板块(2)—— 指针

    参考 五大板块 2 指针 作者 丶PURSUING 发布时间 2021 03 18 16 01 22 网址 https blog csdn net weixin 44742824 article details 114981482 本文为学