学习中科院杨力祥c++

第一天
1.sizeof 一个对象,求得的数据部分的尺寸,而不求代码(也就是函数)的尺寸。
一个对象数据和函数是分开存储的,有数据段,代码段等。涉及到C++对象模型的知识。
这样的设计即多份数据共用一份代码(函数)只适用于单cpu执行的情况。一个CPU一次只能执行一条指令,所以每个对象都有自己的函数代码
所生成的指令是没用的,因为cpu每次只能执行一条指令,也就是只能访问一个对象的指令。但是这样的对象模型如果是并行计算则会出现问题。
例如对象A在CPU1里面跑,对象B在CPU2里面跑,那么编译器只生成一份函数指令则会出现问题,因为两个对象要同时执行这个指令,即两个CPU
的程序指针同时指向该函数指令所在的内存。设计到并行机的知识。


第二天
1.一个类声明和实现分别写到头文件和源文件中,这样成员函数是非inline的。声明时用inline修饰就可以使该成员函数成为inline的。
如果一个类声明和实现写在一起,也就是在类里面直接写实现,这样成员函数是inline的。

2.C语言函数是禁止嵌套定义,必须嵌套调用。


第三天
1.静态先于main函数的执行而存在。

2.所有计算机理论在杨力祥看来不外乎两个词:序和可识别。

3.数据结构的那些设计就是由于硬件的设计所导致的,物质基础决定上层建筑。

4.鉴赏力:例如拿一本书翻几页,知道它要实现个什么东西,然后合上书,自己去思考,
去设计。自己设计完之后,再打开书和别人的去对比,这样就能发现大师设计的想法是多么优秀。
可以看到自己跟大师的差距。学东西最怕的就是学了十几二十年看不到自己和别人差在哪里。
一个人有没有水平就体现在鉴赏力上面,能不能看出它好在哪里。

5.用体系性思维去思考问题,把一个东西放到体系里面去思考。

6.C语言调用函数时将局部变量压栈出栈,那么如果将所有的局部变量都定义为静态可以吗?
不难发现静态全局的访问速度更快,而压栈还需要不断的进栈出栈。栈是动态使用内存,
静态变量是静态使用内存,也就是编译器已经算好它的大小及数量等。如果将局部变量定义为静态,
所有的情况都可以解决,但是有一个问题解决不了,就是自己调用自己,或者说递归。
说明C语言在设计时,递归在整个体系结构中占了很重要的地位。

7.指针是地址吗?如果指针是地址为什么还要起这么个名字,直接叫地址不就好了。
在计算机里指针主要分为两大类,一个是指令指针,也就是程序指针,另一个就是数据指针,
数据指针往往用寄存器来代替。指针就是一个指向数据的地址吗?在计算机中每个字节就是一个地址,
但是一个数据不一定只占有一个地址。指针指向的是一个数据的首地址,且指针是有类型的。当拿到一个指针的时候,
也就是拿到了一个数据的首地址,拿到首地址后应该向下数几个字节来拼成这个数据,就由指针的类型确定,
拼成这个数据之后,编译器如何解析这个数据,例如4个字节,该解析为int还是float,这个也由指针的类型来确定。
 
8.指针的三个优点。第一,以小搏大。即就地解决,山不过来,我过去的思想。用于函数传参时传址。
传参时不把所有数据都带过去,复制一遍,而是将所有数据的内存地址传过去。
第二,切换。指令的切换,函数指针,也就是指令指针,例如动态链接库,用指针在动态链接库里来回切换函数,
调用里面的各种函数。数据的切换,数组不是一个类型,只是一个组数据的打包。数据的切换例如数组中的行指针列指针的应用。
第三,就是挂接,最常用的挂接就是链表。用指针把一组数据连接起来。

9.指令指针寄存器IP(X86型CPU)相当于ARM型CPU中的程序计数器PC。

10.IP在main函数指令执行中遇到调用函数,也就是跳转指令,跳转到另一个函数的指令位置,然后开始
执行,执行完该函数的指令之后,IP又跳回到原来main函数指令的位置。CPU中有一大堆寄存器用来计算等。
当调用函数IP还没跳转时,CPU中的寄存器存储的是现在正在计算的那些数据,也就是跳转前的状态。但是
IP跳转之后,CPU开始做新的是事情,也就是CPU中的寄存器开始处理新的计算,而跳转前正在处理数据寄存器
的值就会丢失。当该函数调用完之后,IP返回原来的位置,CPU的寄存器也应该会返回到跳转之前的状态,继续
干原来的事情,但是调用函数的时候,CPU的寄存器已经处于调用函数时的状态了。该怎么解决这个问题?
将寄存器的数据进行压栈和出栈,即保护现场和恢复现场。 内存的栈区,其实就是纯粹的数据。
返回值为基本类型的直接走寄存器,而返回值为自定义类型的往栈里走。

11.调用一个函数栈里面存放的东西依次是(由编译器决定):CPU原来的状态(现场保护),返回值,形参,然后是一些局部变量的数据。
例如在调用函数时,执行char a = 'a';时,实际就是将'a'这个值进行压栈,将这个数据放到栈的内存里面来进行使用。
压栈出栈其实就是一个栈指针的来回走动。调用函数传参,其实就是向栈里面的形参的那块内存直接写一个值,

12.程序是如何运行的?点击一个exe,实在操作系统上运行一个程序,操作系统将exe的一些有效文件从磁盘装载到内存中,
对于C来说装载两类数据,一类是代码,另一类是静态数据。静态数据又分全局变量和静态局部变量。
然后指令指针IP指向main函数入口点的对应位置。然后开始执行。可以发现静态数据是先于main函数的执行而存在,
这也是静态数据的一个巨大的作用,一般而言函数都是在main函数执行之后才能执行,
但是一个全局对象的构造函数是先于main函数的执行而执行的。IP指向main函数入口之后,程序开始执行,也就是IP开始自动往下走,
IP走的方式有两种(有硬件决定),一种是顺序执行(沿着指令的顺序自动往下走,CPU的功能,不需要人为干预),
另一种是跳转(由程序员控制,例如循环(向上跳)和条件判断执行(向下跳))。

13.静态数据在被加载到内存而不是在硬盘上的证明:
int a[N];
int main(){}
build如上程序,将N设置为10000,而1,比较两个程序的可执行文件exe的大小,发现两个文件一样大,也就是说这个静态数据
并不在硬盘上,而是操作系统加载时,开辟到内存的。


第四天
1.c/c++中有一个先声明后使用的原则。
声明(声明变量和函数)是给编译器看的。定义变量时才会开辟内存,声明不会开辟,声明是个编译器看的,如果声明了一个变量,
且后面没有使用,则编译器会将其优化,视为不存在,不会开辟内存。

2.写一个函数的顺序是先声明,再定义,最后调用。但是声明和定义可以合起来写。例如下面的写法:
void Swap(int, int);
void main() {
    Swap(a ,b);
}
void Swap(int x, int y)  {
    int temp = x;
    ...
}
首先声明函数Swap是为了给编译器看,知道了其返回值类型和参数类型几个数,只是为了计算其在
栈中占用空间,方便栈指针跳转等(不得而知),所以不用写参数名字,有了其类型就够了。
而定义的时候,是必须要知道参数的名字的,第一因为函数中要用到这个参数。但是问题来了,如果
不写参数名字,调用函数时形参在从左到右一个一个的进栈时,由此每个参数在栈中的内存地址
我都知道了,函数中的使用不就可以直接访问那个地址了吗?这也就导致了第二个原因,函数参数
进栈的顺序是不一定的,所以必须为其加上名字,后面才能准确拿到参数。

3.编译是以*.c或*.cpp文件为单位编译的。一个程序里面有几个cpp编译几次,一个cpp只编译一次。
#include "a.h"是将该文件a.h的内容嵌入到当前位置。例如下面某个文件的代码。
#include "Circle.h"
int main() {
  Circle circle(1, 2);
}
由c/c++先声明后使用的原则,只要在该cpp文件中声明了Circle这个类,就可以使用。所以写上了
#include "Circle.h"这句话,将Circle的声明代码嵌入到当前这个文件。

4.地址重定位:例如在main.c中调用了a.h中的函数,a.h中的函数只声明而不定义,所以
在main.obj中,也就是在main.c编译之后的机器码中,IP跳转到该函数的地址是不知道的,因为该函数的
.obj还没有链接到一起,所以这些调用函数地方指针都空出来了,当所有obj都拼到一起之后,编译器算出
该函数地址的值赋值给原来指针的地方,也就是地址重定位。

5.一个.cpp文件编译之后一般来说生成一个.obj文件(目标文件,机器码,可执行,但不是立即可执行)。
然后将多个编译生成的.obj文件以及标准库等其他的.obj文件拼在一起后,然后进行地址重定位,将
其之间的关系全部联系起来。最后加入一些头等打包成exe。

6.所谓lib库等,就是将一大堆的.obj文件合起来,然后加入一些引导头之类的。

7.上述讲的这些链接,都是静态链接,链接之后还是在硬盘中,执行的时候加载到内存中。
例如printf这个函数的代码,在运行之前已经存在于exe,这就是静态链接。
相对的就是动态链接dll。

8.链接printf的时候,不是讲"stdio.h"这个库连接进去,而是将printf链接进去,以最简化原则,
需要谁连接谁。

9.静态链接中,例如连续调用多次printf函数,实际上就链接了一次,只产生一份代码,只是传的参数不同。
但是站在操作系统的角度来看,系统中有多个程序在执行,每个程序都调用了printf,也就是每个程序都
链接了一次printf。站在程序的角度看,自己已经很节约了只链接了一次,但是站在操作系统的角度看,
链接了多次,产生了浪费,其实只要搞出一份代码就可以,自己的程序访问别人程序的代码,
但是这样就导致了跨进程的问题,十分不安全。而动态链接库就解决了这个问题。动态链接库没有将代码
放到某个程序中,而是放到操作系统中,当某个程序使用其的时候,应用loadLibrary这个技术,加载该库。
如果要用printf函数,就从dll中找到该函数的地址。原来是静态的算好printf函数的地址,现在变成了动态
获取printf函数的地址。

10.作用域,生存周期。
例如static局部变量,全局的生存周期,局部的作用域。

11.资料:
http://blog.chinaunix.net/uid-23069658-id-3981406.html  深入理解C语言的函数调用过程
http://blog.csdn.net/wu5215080/article/details/38899259  C语言之内存四区模型和函数调用模型
http://blog.csdn.net/wu5215080/article/details/38899259  C语言之内存四区模型和函数调用模型
http://blog.chinaunix.net/uid-25667116-id-3064937.html  栈的一点理解
http://blog.csdn.net/pi9nc/article/details/12419819 程序的链接与装入(动、静态重定位)



第五天
1.讨论:对象定义时,为什么要对象自动调用构造函数,而不是外部调用?
思想猜测:面向对象是尽量将一个类进行物化,它自己就是一个物,产生之后就是一个完整的物体,而不需要别人调用构造函数
来进行物体的组装,初始化等。面向对象,一切皆对象,里面是物与物之间的交互,模拟人类社会,如果一个物产生之后还需要
别的物来调用它的函数将它初始化,这是非常诡异的。所以一个对象应该在它被使用之前就初始化好了,它不应该由对象的使用
者来初始化。

2.为什么要设计构造函数,析构函数?
a.更好的体现“物化”思想(自动性)。
b.更好的封装性,避免从外部初始化。很显然外部初始化对象的成员变量破坏了对象的封装性。
c.更有效地使类架构设计与程序架构设计分开。
d.促进更清晰地面向接口编程(所谓的接口都是public的函数),更有效地复用。

3.例如一个类里面维护了一个数组,然后写了一大堆public函数,来操作这个数组。既然可以直接操作
数组,为什么要将其封装提供接口呢?好处就是提供接口,面向接口编程,松耦合,更容易复用。并且
将其物化后,提供接口跟别人交互,更像是一个人用语言去跟别人交流。并且将数据封装,更好的保护
了数据,不将其暴露出来。

4.new和delete是操作符,不是函数。malloc函数只是分配出一块内存,而不管分配出什么类型的。需要什么类型
自己去强转。而new操作符不但分配了内存,并且赋予了其类型,引发其构造函数的调用。


第六天
1.程序一开始写的时候最难,无法下手。当程序写了一大堆时,思路打开后,却不难了。

2在当解决问题时,会遇到问题难度大于自己能力的情况。此时人们采取的方法有两种,一种是提升自己的能力,
快速学习相关知识等。但是能力并不是短时间能够提升的。能力的提升是金字塔状的,一层一层铺上去的。
真正的大师站在金字塔的顶端的时候,底下是铺了一大层的。第二种就是将问题的难度往下缩。缩小的办法
之一就是去掉问题包装层,留下问题最主要的东西,是它的最小完备集。

3.看传记,最好是看大师本人写的,不要去看其他阿猫阿狗写的,他们怎么可能理解大师所想的。

4.书读了十几年,是时候去动脑思考问题了。遇到一个问题有没有能力去解决,就看你有没有能力去将问题解剖,
然后用已学过的知识去分析。世界的本原是相通的,所以所有的知识都是相通的,那么就可以用自己学过的知识
去解决其他陌生领域的问题。通过这个思想,那么你是否可以通过十五天的时间去成为某个其他领域的专家?
因为知识是相同的,思想是相通的,世界的本原是相通的。

5.函数重载时,为什么函数参数和参数个数是可识别的,但是函数的返回值是不可识别的?
因为调用这个函数时,调用语法是没有返回值信息的,由此导致调用时不可识别。
从定义函数的表面上可以通过返回值识别,eg:
int Fun();
float Fun();
从定义语法上,以上两个函数可以识别。但是在调用语法上面是不可识别的。eg:
void main() {
  Fun();
}
从语法上如何识别调用的是哪个Fun函数呢?不能识别。
如果语规定说调用的时候,前面必须写返回值类型,那么这可以识别。
从这个问题可以分析到,一个语法中,哪个行为可以这样做,哪个行为不能这样做,
是在整个语法体系中相互制约的,所以可以从整个语法体系去分析某个行为为什么
是这样的,一定是有原因的,是有其他行为与其相互作用,相互制约,相生相克。

6.void在当返回值类型时,表示不返回,并不是返回无类型,不返回任何值,不去建栈。

7.构造函数可以显示调用,匿名对象。

8.构造函数没有返回值,是编译器造出来自动调用用来初始化对象的,它不需要返回值,返回给谁呢?


第七天
1.析构函数不能重载,不能显示调用。

2.C++的发明者喜欢用一个词代表多个意思。例如static有多种用法,const也有好多种用法。

3.静态局部对象。静态变量的产生早于main函数的调用,但是构造函数的调用不会早于main函数。
可能是在main函数一开始的时候,也可能第一次使用的时候,例如静态局部。
分析:代码如下,
A a;  // 构造函数输出a。
int main() {
  cout << "b" << endl;
}
输出为 a, b
先输出a,后输出b,那么是不是就是首先调用A的构造函数,然后调用main函数?
如果是这样,那么是不是和C语言是一个悖论,C规定函数必须嵌套使用,但是不能
嵌套定义。但在这种情况下A的构造函数不是在main函数中调用使用!并且如果A的构造
函数可以在main之前调用,那么是不是可以把所有的事都放到构造函数中去做,main函数
其实就没什么用了?
事实证明这种想法是错误的,通过查看编译生成的机器码可以看到,全局A的构造函数
是在刚进入main函数的时候,就调用的A的构造函数。
由此也可以看出C++是一个不纯粹的面向对象的语言,因为它要进入main函数,在里面先做这个,
后做那个,很面向过程的一种风格。如果更纯粹点的话,就把main函数去掉,也就是把main函数做成一个
类,由该类来带领队伍去做各种事,也就是将其对象化,而不是面向过程的,在main这个函数中进行动作。
在现实中的面向对象都是纯粹的面向对象,因为不论做什么事,都是有人,有角色去带领,去做。

4.面向过程,把一个问题的解决方案步骤后,过程化,先做这个,然后做那个,最后再做什么什么。
而面向对象是将问题进行角色划分,进行物化,进行专业化分工。

5.问题分析:代码如下,
int a = 5;
cout << &5 << endl;
5是常量吗,为什么不能对其取地址?
5是一个常量,不能对其进行赋值。5是int a = 5;这条指令中的立即数,这个5是这条指令中的一部分,
是不能将其取出来的。指针虽然有指令指针,但是指令指针是指向某条指令的,
而不能将某条指令拆分开来,取到其中的某一部分。
在C++中常数即常量, 如:int a = 5;
常量5,不在数据中,而在指令中,没有指针,不能赋值。

6.const常量,具有常量性质的数据(编译器“把门”)。常量必须初始化。
const int a = 10;
a = 12;  // 错误,这个赋值错误是因为编译器把门,不让它通过,而不是因为其他的原因。

7.const推测:
const int a = 10;
cout << a << endl;
int b = a;
推测一:如果代码中没有对常量a取地址的行为,那么,编译器就直接将其视为宏的作用。也就是
在编译初期,直接将a替换成10。
const int a = 10;
cout << &a << endl;
推测二:如果代码中有对常量a进行取地址的行为,那么const的作用之一就是将a进行内存分配,
将其变成一个普通局部变量。const的作用之二就是提示编译器进行把门,不要让程序员对其
进行赋值。

8.const    成员函数:约束成员函数的只读性。const很巧妙地解决了野指针的问题。

9.引用,是一个变量的别名,引用本身并不是没有存储空间的。引用不会为值去开辟一个
地址空间,但是其本身要占用空间。引用确实占用了栈空间,也确实是存储了目标变量的
地址。

10.初始化非const引用必须用左值,const引用则不必。
eg:
int& a = 5;  // 错误
const int& a = 5;  // 正确
引用在内部存放的是一个变量的地址,它是变量的别名。对于不可寻址的值,编译器为了实现引用,
必须生成一个临时对象,引用必须指向该对象,但是用户不能访问它.
一种不准确的解释为:编译器产生的临时产生的中间变量都是const的,即其为常量,
所以必须用const的引用。
eg:
const int a;
const int& b = a;  // 因为a是const的,所以其引用也必须是const。
这种解释是有悖论的,如果其为const,那么其应该在指令区,是不能做左值的。
但在《Thinking in C++》中说到编译器产生的临时的中间变量是可以做左值的。
例如const int& a = 5;编译器会为5这个常量产生一个临时的中间变量,且这个临时
中间变量是可以作为左值得。

比较正确的解释为:临时中间变量是程序员是不能对其进行操作的,而且其在使用完之后
就会释放,所以我们修改一个其是没有意义的。所以编译器就为其加入了不能作为非const
引用的这个语义限制,防止用户错误使用。也就是说临时中间变量有const的性质,但不是const
变量,所以编译器加入了这个语义限制。


第八天
1.C++体系性的思考特别多。体系性思考特别重要。


第九天
1.世界上最难做好的就是最简单的道理。人有一个毛病,越是聪明的人越有的一个毛病,
追求复杂很难理解的道理。

2.在拷贝构造函数中为什么可以访问引用对象的私有变量?
一种解释:因为C++的封装层次达到类的层次,而不是对象。所以对于C++来说访问权限是针对“类”
来说的。也就是说private的访问权限是其他类不能访问的,而不是这个类的不同对象之间不能访问。

3.成员函数和非成员函数之间最大的区别就是,成员函数的参数里面有一个你看不见的参数,
这个参数传的是this指针。

4.this指向当前对象的指针。


第十天
1.学习,学会规则只能达到解决温饱的问题,真正要达到衣食无忧,靠的是悟性。
悟性对一个事物的思考,把握。学过一个东西,然后能掌握它,抓住它的主要矛盾,这是只是一个基本的本事,
真正的本事是没有学过一个东西,能够抓住它的主要矛盾。

2.其实很多高考新课标的修改就是一种思路。新课标的题目被称为很开放,开放并不是乱七八糟的无厘头,而是
一种思想的开放。通过已有已学过的知识,去分析一个问题,然后设计解决方案。这就是新课标的设计类题目。
这也就是其被称为开放的原因。学习,去思考,去推理,达到设计的境界。

3.对事物要有一种“敏”,也就是对事物有一种敏感,快速感知其思路,其设计的伟大之处,以及要达到的目的。

4.生物的继承进化,基因既有自己的基因,又有继承前人的基因(加机制),但是并没有完全加入了前人的基因
(减机制),一些前人的基因可能没有继承。但是在C++中,虽然有priave,但是还是完全继承了前人的基因。
也就是C++只有加机制,没有减机制。
eg:
class Base {
private:
  int a;
  int b;
};

class Derived : public Base {
private:
  int c;
};

int main() {
  cout << sizeof(Base) << endl;  // 输出8
  cout << sizeof(Derived) << endl;  // 输出12

  return 0;
}
生物不断地进化,可能进化出新的物种。如果C++就像生物一样,既能继承一些基因,
也能丧失一些基因,那么通过不断地继承之后,可能出现一个新的类,一个功能完全不同于最初
基类的类。

5.程序能不能实现自己编程呢,程序一定要人去写吗?如果程序模仿生物,不断地进行继承,进行
进化,自我繁衍出新的类,那么是否可以实现程序的自我编程呢?未来的程序是不是可以这样写,
大致写出一个框架,然后让它自己去跑,程序在那里自适应,自己创造新的东西。

6.思考:用人类繁衍的思想,想出一个语言的设计方案。
人类两性繁殖,减数分裂,然后父母双方各一半基因的随机融合等等,这些思想是否可以做出
一个语言,可以达到这个效果。

7.上述的思考只是一个想法而已,人要有许多此类的想法,对基本的事物要敏感,要有想法,
并且对其进行一些思考,与其他发展已经很成熟的事物进行类比,万事万物都是相通的。
就像拿面向对象语言的设计去和生物进行类比,因为面向对象语言人类设计了几十年,发展其实
并不是很成熟,而生物的发展已经有几亿年,是一个很成熟的事物,所以可以将这两个事物
进行类比。


第十一天
1.真正要干成点什么事,想象力和创造力显得尤为重要。
传统教育对技术细节重视最大,在最基础的时候,技术细节确实很重要,但是达到一定高度之后,
想象力,创造力,体系性显得特别重要,是真正的突破口。

2.想象力,创造力,其实可以这样做,想到一个想法,然后就去做,去实现,然后搞出个水落石出!
不要一想而过!

3.设计类架构的方法,如果从上往下设计,也就是从基类开始思考,思考下面要派生什么类,这样的
思考方法其实是有一定问题的,很难想到下面该派生什么类。但是可以反向思考,从小往上思考。想
好最下层的类,然后不断从中抽取基类。
类是抽象出来的,不是从上往下拍脑袋想出来的。

4.一个人都优秀是他思考问题的方法优秀,有和他人不同的思考角度。一个人要快速的调转自己的思考方式,
也就是随机应变的能力强。而不是十分固执,死磕于自己的一种角度,人改变自己的思想方法很难。《柳丁思考的帽子》

5.人类一切美好高雅的东西都应该去尝试,因为这些都是艺术,是人类伟大智慧的结晶,给人带来美好感受。


第十二天
1.程序中,小问题要及时解决,不要试图去绕过去,程序越来越庞大,小问题越滚越多,最终达到毁灭性灾难。
小问题不要积累,不要去妥协,一定要及时解决。

2.读书也要有敏感性,对其里面的内容要敏感,快速抓住其思考,精髓,核心等等。




































下面是网上对杨力祥老师的评价: 有感于杨力祥老师和中科院的牛人们,进而有感于中科院和北京的学生 (2007-03-23 09:47:45) 转载▼ 还是再说一个高级Windows程序设计的杨力祥老师,周三上完课后还在回味呢,在他滔滔不绝,口若悬河的精彩讲演中深知计算机这东东的快乐是在巨大的痛若经历和深厚功底下的,当然了激情是支撑这一路下去的唯一东东。对编程的感觉就像艺术般地发挥。像那个五分钟搞出汇编把软件驱修好的牛人,与IBM的角力,小编程的演示,无不透出其出的深厚内涵 ,不禁想到自已是否可以几年以后如此这般萧洒。(总不明白为何身边有那夸夸其谈不干实事的人,不可能是物以类聚吧?呵自认是绝对勤快的人啊)。 再说中科院和北京的大学生,有他们是有那么好的机会和资源啊,不在于有多少钱有多好的硬件设施,他们可以看到的和听到的是我们所无法比的。可以请王永明,可以听INTEL的高手,见到不同的牛人,于此不会也是不可能的。呵如果这些都搬到广州就好了。为什么偏是在北京呢?如果哪天哪个领导人英明一下,大手一挥,北京只搞政治,不搞经济,别的都给我投出去,呵,这下可好了,牛人们都往南方走了。 刚才上传了CSDN把我的资源删了,不知道怎么回事。。可能是后缀名的问题 重新弄了一下。下载后把后缀名改成downlist就可以用迅雷打开了。 解压密码:abab123.gfugifyr7t565
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值