① 怎么用c语言实现matlab中的功能
通过把耗时长的函数用c语言实现,并编译成mex函数可以加快执行速度。Matlab本身是不带c语言的编译器的,所以要求你的机器上已经安装有VC,BC或Watcom
C中的一种。如果你在安装Matlab时已经设置过编译器,那么现在你应该就可以使用mex命令来编译c语言的程序了。如果当时没有选,就在Matlab里键入mex
-setup,下面只要根据提示一步步设置就可以了。需要注意的是,较低版本的在设置编译器路径时,只能使用路径名称的8字符形式。比如我用的VC装在路径C:\PROGRAM
FILES\DEVSTUDIO下,那在设置路径时就要写成:“C:\PROGRA~1”这样设置完之后,mex就可以执行了。为了测试你的路径设置正确与否,把下面的程序存为hello.c。
/*hello.c*/
#include
"mex.h"
void
mexFunction(int
nlhs,
mxArray
*plhs[],
int
nrhs,
const
mxArray
*prhs[])
{
mexPrintf("hello,world!\n");
}
假设你把hello.c放在了C:\TEST\下,在Matlab里用CD
C:\TEST\
将当前目录改为C:\
TEST\(注意,仅将C:\TEST\加入搜索路径是没有用的)。现在敲:
mex
hello.c
如果一切顺利,编译应该在出现编译器提示信息后正常退出。如果你已将C:\TEST\加
入了搜索路径,现在键入hello,程序会在屏幕上打出一行:
hello,world!
看看C\TEST\目录下,你会发现多了一个文件:HELLO.DLL。这样,第一个mex函数就算完成了。分析hello.c,可以看到程序的结构是十分简单的,整个程序由一个接口子过程
mexFunction构成。
void
mexFunction(int
nlhs,
mxArray
*plhs[],
int
nrhs,
const
mxArray
*prhs[])
前面提到过,Matlab的mex函数有一定的接口规范,就是指这
nlhs:输出参数数目
plhs:指向输出参数的指针
nrhs:输入参数数目
例如,使用
[a,b]=test(c,d,e)
调用mex函数test时,传给test的这四个参数分别是
2,plhs,3,prhs
其中:
prhs[0]=c
prhs[1]=d
prhs[2]=e
当函数返回时,将会把你放在plhs[0],plhs[1]里的地址赋给a和b,达到返回数据的目的。
细心的你也许已经注意到,prhs[i]和plhs[i]都是指向类型mxArray类型数据的指针。
这个类型是在mex.h中定义的,事实上,在Matlab里大多数数据都是以这种类型存在。当然还有其他的数据类型,可以参考Apiguide.pdf里的介绍。
为了让大家能更直观地了解参数传递的过程,我们把hello.c改写一下,使它能根据输
入参数的变化给出不同的屏幕输出:
//hello.c
2.0
#include
"mex.h"
void
mexFunction(int
nlhs,
mxArray
*plhs[],
int
nrhs,
const
mxArray
*prhs[])
{
int
i;
i=mxGetScalar(prhs[0]);
if(i==1)
mexPrintf("hello,world!\n");
else
mexPrintf("大家好!\n");
}
将这个程序编译通过后,执行hello(1),屏幕上会打出:
hello,world!
而hello(0)将会得到:
大家好!
现在,程序hello已经可以根据输入参数来给出相应的屏幕输出。在这个程序里,除了用到了屏幕输出函数mexPrintf(用法跟c里的printf函数几乎完全一样)外,还用到了一个函数:mxGetScalar,调用方式如下:
i=mxGetScalar(prhs[0]);
"Scalar"就是标量的意思。在Matlab里数据都是以数组的形式存在的,mxGetScalar的作用就是把通过prhs[0]传递进来的mxArray类型的指针指向的数据(标量)赋给C程序里的变量。这个变量本来应该是double类型的,通过强制类型转换赋给了整形变量i。既然有标量,显然还应该有矢量,否则矩阵就没法传了。看下面的程序:
//hello.c
2.1
#include
"mex.h"
void
mexFunction(int
nlhs,
mxArray
*plhs[],
int
nrhs,
const
mxArray
*prhs[])
{
int
*i;
i=mxGetPr(prhs[0]);
if(i[0]==1)
mexPrintf("hello,world!\n");
else
mexPrintf("大家好!\n");
}
这样,就通过mxGetPr函数从指向mxArray类型数据的prhs[0]获得了指向double类型的指针。
但是,还有个问题,如果输入的不是单个的数据,而是向量或矩阵,那该怎么处理呢
?通过mxGetPr只能得到指向这个矩阵的指针,如果我们不知道这个矩阵的确切大小,就
没法对它进行计算。
为了解决这个问题,Matlab提供了两个函数mxGetM和mxGetN来获得传进来参数的行数
和列数。下面例程的功能很简单,就是获得输入的矩阵,把它在屏幕上显示出来:
//show.c
1.0
#include
"mex.h"
#include
"mex.h"
void
mexFunction(int
nlhs,
mxArray
*plhs[],
int
nrhs,
const
mxArray
*prhs[])
{
double
*data;
int
M,N;
int
i,j;
data=mxGetPr(prhs[0]);
//获得指向矩阵的指针
M=mxGetM(prhs[0]);
//获得矩阵的行数
N=mxGetN(prhs[0]);
//获得矩阵的列数
for(i=0;i<M;i++)
{
for(j=0;j<N;j++)
mexPrintf("%4.3f
",data[j*M+i]);
mexPrintf("\n");
}
}
编译完成后,用下面的命令测试一下:
a=1:10;
b=[a;a+1];
show(a)
show(b)
需要注意的是,在Matlab里,矩阵第一行是从1开始的,而在C语言中,第一行的序数为零,Matlab里的矩阵元素b(i,j)在传递到C中的一维数组大data后对应于data[j*M+i]
。
输入数据是在函数调用之前已经在Matlab里申请了内存的,由于mex函数与Matlab共用同一个地址空间,因而在prhs[]里传递指针就可以达到参数传递的目的。但是,输出参数却需要在mex函数内申请到内存空间,才能将指针放在plhs[]中传递出去。由于返回指针类型必须是mxArray,所以Matlab专门提供了一个函数:mxCreateDoubleMatrix来实现内存的申请,函数原型如下:
mxArray
*mxCreateDoubleMatrix(int
m,
int
n,
mxComplexity
ComplexFlag)
m:待申请矩阵的行数
n:待申请矩阵的列数
为矩阵申请内存后,得到的是mxArray类型的指针,就可以放在plhs[]里传递回去了。但是对这个新矩阵的处理,却要在函数内完成,这时就需要用到前面介绍的mxGetPr。使用
mxGetPr获得指向这个矩阵中数据区的指针(double类型)后,就可以对这个矩阵进行各种操作和运算了。下面的程序是在上面的show.c的基础上稍作改变得到的,功能是将输
//reverse.c
1.0
#include
"mex.h"
void
mexFunction(int
nlhs,
mxArray
*plhs[],
int
nrhs,
const
mxArray
*prhs[])
{
double
*inData;
double
*outData;
int
M,N;
int
i,j;
inData=mxGetPr(prhs[0]);
M=mxGetM(prhs[0]);
N=mxGetN(prhs[0]);
plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL);
outData=mxGetPr(plhs[0]);
for(i=0;i<M;i++)
for(j=0;j<N;j++)
outData[j*M+i]=inData[(N-1-j)*M+i];
}
当然,Matlab里使用到的并不是只有double类型这一种矩阵,还有字符串类型、稀疏矩阵、结构类型矩阵等等,并提供了相应的处理函数。本文用到编制mex程序中最经常遇到的一些函数,其余的详细情况清参考Apiref.pdf。
通过前面两部分的介绍,大家对参数的输入和输出方法应该有了基本的了解。具备了这些知识,就能够满足一般的编程需要了。但这些程序还有些小的缺陷,以前面介绍的re由于前面的例程中没有对输入、输出参数的数目及类型进行检查,导致程序的容错性很差,以下程序则容错性较好
#include
"mex.h"
void
mexFunction(int
nlhs,
mxArray
*plhs[],
int
nrhs,
const
mxArray
*prhs[])
{
double
*inData;
double
*outData;
int
M,N;
//异常处理
//异常处理
if(nrhs!=1)
mexErrMsgTxt("USAGE:
b=reverse(a)\n");
if(!mxIsDouble(prhs[0]))
mexErrMsgTxt("the
Input
Matrix
must
be
double!\n");
inData=mxGetPr(prhs[0]);
M=mxGetM(prhs[0]);
N=mxGetN(prhs[0]);
plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL);
outData=mxGetPr(plhs[0]);
for(i=0;i<M;i++)
for(j=0;j<N;j++)
outData[j*M+i]=inData[(N-1-j)*M+i];
}
在上面的异常处理中,使用了两个新的函数:mexErrMsgTxt和mxIsDouble。MexErrMsgTxt在给出出错提示的同时退出当前程序的运行。MxIsDouble则用于判断mxArray中的数据是否double类型。当然Matlab还提供了许多用于判断其他数据类型的函数,这里不加详述。
需要说明的是,Matlab提供的API中,函数前缀有mex-和mx-两种。带mx-前缀的大多是对mxArray数据进行操作的函数,如mxIsDouble,mxCreateDoubleMatrix等等。而带mx前缀的则大多是与Matlab环境进行交互的函数,如mexPrintf,mxErrMsgTxt等等。了解了这一点,对在Apiref.pdf中查找所需的函数很有帮助。
至此为止,使用C编写mex函数的基本过程已经介绍完了。
② matlab 从最基础开始,需要前辈高人指点!!!
matlab 是在C的基础上写的,但是比C不知道简单多少。。。所以无所谓的。。
matlab 貌似只有英文版本,至少2007之前都是英文版,你可以下一个金山词霸,不过作用不是很大,很多数学术语翻译不准确
matlab 被誉为第四代编程语言,更加傻瓜,但要全面掌握也是不可能的。。。所以借阅相关书籍,研究你要的工具箱。。。
看书比较方便一点,上淘宝或者什么上买本吧。。。
不用谢
另外给你附上一些错误说明,由于我这的pdf是我们老师还没有出版的书籍,而且只写了一半,所以不能给你全部,只给你些错误说明:
1. Assignment statements do not proce results.
赋值语句不会产生结果,通常是把==写成了=
2. Capitalized internal function xxx; Caps Lock
may be on.
拼写错误或者大写开关打开
3. Function definitions are not permitted at the
prompt or in scripts.
函数要写在m文件里,且必须有合法的开头
4. Index exceeds matrix dimensions.
下标超越矩阵维数
5. Indexed empty matrix assignment is not allowed.
不同维数矩阵赋值引发的错误
6. Input argument ’xxx’ is undefined.
输入参数没定义
7. Matrix dimensions must agree.
矩阵维数不一致
8. Matrix must be square.
必须为方阵
9. Missing operator, comma, or semicolon.
缺少运算符
10. Strings passed to EVAL cannot contain function declarations.
把function写在了命令行上
11. Subscript indices must either be real positive
integers or logicals.
下表必须是非负数,或逻辑值
12. Too many input arguments.
输入参数太多
3. Undefined function or method ’xxx’ for input
arguments of type ’xxx’.
没定义的函数或方法,一般是拼写错误导致
14. Undefined function or variable ‘xxx’.
没定义的函数名或变量名
③ 如何在matlab上运行c语言写的程序
1.准备好C语言程序,清楚C语言的入口函数
2.编写mexfunction函数。mexfunction函数为C语言与MATLAB语言的接口函数。调用实例在mylinedetect.c文件中.在MATLAB中调用mex指令编译相关文件,将C语言编译为MEX文件。
3.编译完成后,生成mylinedetect.mexw32或mylinedetect.mexw64文件,此文件即mex文件,用于MATLAB与C语言接口函数.
4.编译完成之后,编写MATLAB函数,调用MEX文件。以MEX文件的形式调用编译完成的C语言函数[o1,o2]=mylinedetect(double(X).');......
5.输出结果,上述linedetect函数完成图像中直线检测功能,带入MATLAB中调用后形成结果。
④ MATLAB中如何运行c语言程序
呵呵,看来我们有研究相同的问题吧
matlab是一种科学的计算语言,采用的是解释执行的方式,在配置比较水的机器(比如说我的),运行起来速度不敢恭维,但是他适合工程师用,快速建立起自己的运算平台,很多语法是类似c语言。你可以考察一下matlab的安装目录下extern下面lib库中的函数,可以发现,有很多的c语言代码,实际上,其内核有很多c的成分。
所以你应该可以明白了,可以运行,但是要把matlab的库函数包含在c编译库中。
你完全可以在extern中的example中,在matlab环境下面运行几个c代码试一试,当然所采用的指令是mex(把c语言用于matlab中),mcc把matalb代码转化为c代码,一些具体的参数,你可以用matlab强大的help工具获得。我们还可以一起探讨一下啊,给各邮箱之类的吧,呵呵,很乐意的
⑤ 在C语言编程中,如何调用MATLAB的绘图功能
一、调用Matlab引擎
调用Matlab引擎可以在WIN32、MFC中使用,它的原理实际上相当于打开一个精简版的Matlab然后往里面输命令。下面是调用Matlab中的加法程序add.m的例子。
先在Matlab的work目录下创建add.m文件并编写程序如下:
function s = add (a, b) s = a+b;在C程序中,首先打开精简版的Matlab
Engine *ep = engOpen (NULL);
编译运行后,会自动打开一个命令行监控窗口,输入pwd就可以看到当前的工作目录,于是需要先将工作目录转换至存放add.m的目录: engEvalString (ep, ”cd ..\\..\\work”);
engEvalString是往Matlab里输命令的函数,显然我们的目标是成功运行: engEvalString (ep, ”s=add(a,b)”);
目前Matlab中并没有a和b两个变量,因此需要在C中初始化这两个变量并转换成Matlab基本变量类型mxArray,才能将它们输入到Matlab中。
⑥ matlab编程
计算机程序就是计算机指令的集合,不同的编程语言指令与功能是不一样的.MATLAB语言是一种面向对象的高级语言,它具有编程效率高、易学易用的优点.
MATLAB与其它大部分高级语言一样,有它自己的控制流语句.控制流极其重要,因为它使过去的计算影响将来的运算。MATLAB提供如下几种控制流结构:For循环,While循环,If-Else-End结构和switch-case-end结构。由于这些结构经常包含大量的MATLAB命令,故经常出现在M文件中.MATLAB支持的控制流语句和C语言支持的控制流语句在调用格式上非常相似.
1.For 循环
For循环允许一条语句或一组语句被重复执行预先指定的次数。For循环的一般形式是:
for x =array
语句
end
在for和end语句之间的语句按数组中的每一列执行一次。在每一次迭代中,x被指定为数组的下一列,即在第n次循环中,x=array(:, n)。例如,
for n=1:10
x(n)=sin(n*pi/10);
end
x
x =
0.3090 0.5878 0.8090 0.9511 1.0000 0.9511 0.8090 0.5878 0.3090 0.0000
换句话,第一语句是说:对n等于1到10,执行所有语句,直至下一个end语句。第一次通过For循环n=1,第二次,n=2,如此继续,直至n=10。在n=10以后,For循环结束,然后执行end语句后面的任何命令.注意,该循环结束后,n=10.
For循环的其它重要方面是:
(1)For循环不能用For循环内重新赋值循环变量n来终止。
For n=1:10
x(n)=sin(n*pi/10);
n=9;
end
x
x =
0.3090 0.5878 0.8090 0.9511 1.0000 0.9511 0.8090 0.5878 0.3090 0.0000
n
n=
9
执行过程是这样的:
n=1,
x(1)=sin(pi/10),
n=9,
n=2,
x(2)=sin(2*pi/10),
n=9,
n=3,
...,
n=10,
x(10)=sin(10*pi/10),
n=9.
循环结束后,n=9.
(2)在For循环内接受任何有效的MATLAB数组。
data=[3 9 45 6; 7 16 -1 5]
data =
3 9 45 6
7 16 -1 5
for n=data
x=n(1)-n(2)
end
x =
-4
x =
-7
x =
46
x =
1
(3)For循环可按需要嵌套。
For n=1:5
for m=1:5
A(n,m)=n^2+m^2;
end
disp(n)
end
1
2
3
4
5
A
A =
2 5 10 17 26
5 8 13 20 29
10 13 18 25 34
17 20 25 32 41
26 29 34 41 50
(4)当有一个等效的数组方法来解给定的问题时,应避免用For循环。例如,上面的第一个例子可被重写为
n=1:10;
x=sin(n*pi/10)
x =
0.3090 0.5878 0.8090 0.9511 1.0000 0.9511 0.8090 0.5878 0.3090 0.0000
两种方法得出同样的结果,而后者执行更快,更直观,要求较少的输入。
(5)为了得到最大的速度,在For循环(While循环)被执行之前,应预先分配数组。例如,前面所考虑的第一种情况,在For循环内每执行一次命令,变量x的大小增加1。迫使MATLAB每通过一次循环要花费时间对x分配更多的内存。为了消去这个步骤,For循环的例子应重写为
x=zeros(1,10);
for n=1:10
x(n)=sin(n*pi/10);
end
现在,只有x(n)的值需要改变。
例1 相传古代印度国王要褒奖他的聪明能干的宰相达依尔(国际象棋发明者),问他要什么?达依尔回答:“陛下只要在国际象棋棋盘的第一个格子上放一粒麦子,第二个格子上放二粒麦子,以后每个格子的麦子数都按前一格的两倍计算。如果陛下按此法给我64格的麦子,就感激不尽,其他什么也不要了。”国王想:“这还不容易!”让人扛了一袋麦子,但很快用光了,再扛出一袋还不够,请你为国王算一下共要给达依尔多少小麦?(1 小麦约 颗)
解: 麦粒总数为
程序如下:
a=1;
s=0
for i=1:64
s=s+a;
a=2*a;
end
s=s/1.4/10^8
运行后得:
s=
1.3176e+011
例2 公元前五世纪我国古代数学家张丘建在《算经》一书中提出了“百鸡问题”:鸡翁一值钱五,鸡母一值钱三,鸡雏三值钱一。百钱买百鸡,问鸡翁、母、雏各几何?
解 设 x:鸡翁数,则x的范围:0~19
y:鸡母数,则y的范围:0~33
z:鸡雏数,则z的范围:0~100
则:
x+y+z=100
5x+3y+z/3=100
这是一个不定方程。
for x=0:19
for y=0:33
for z=0:100
if (x+y+z==100)&(5*x+3*y+z/3==100)
d=[x,y,z]
end
end
end
end
运行后得结果:
d =
0 25 75
d =
4 18 78
d =
8 11 81
d =
12 4 84
2.While 循环
与For循环以固定次数求一组命令的值相反,While 循环以不定的次数重复执行一组语句。While循环的一般形式是:
while 表达式1
语句1
end
只要表达式1里的所有元素为真,就执行while和end之间的语句1,否则,就结束循环。通常,表达式的值给出一个标量值,但数组值也同样有效。在数组情况下,当数组的所有元素为真(值不等零)时,就执行语句1,数组中有一个元素为假(值为零),就结束循环。
例3按下面的公式计算:
使误差小于给定的 .
解: 把 作为误差,程序如下:
error=input('请输入误差:');
x=1;
y=0;
n=1;
while x>error
y=y+1;
x=x/n;
n=n+1;
end
e=y
运行如下:
请输入误差:0.001
e =
2.7181
3.IF-ELSE-END 结构
很多情况下,命令的序列必须根据关系的检验有条件地执行。在编程语言里,这种逻辑由某种If-Else-End结构来提供。最简单的If-Else-End结构是:
if 表达式1
语句1
end
如果在表达式1中的所有元素为真(非零),那么就执行if和end语言之间的语句1。
假如有两个选择,If-Else-End结构是:
if 表达式1
语句1
else
语句2
end
在这里,如果表达式1为真,则执行语句1;如果表达式是假,则执行语句2。
当有三个或更多的选择时,If-Else-End结构采用形式
if 表达式1
语句1
elseif 表达式2
语句2
elseif 表达式3
语句3
elseif 表达式4
语句4
elseif ……
.
.
.
else
语句
end
如果表达式1为真,则执行语句1,结束循环;如果表达式1为假,则检验表达式2,如果表达式2为真,则执行语句2,结束循环;如果表达式2为假,则检验表达式3,如此下去,如果所有表达式都为假时,则执行最后的语句。即只执行第一个真值表达式相关的语句;接下来的表达式不检验,跳过其余的If-Else-End结构。而且,最后的else命令可有可无。
4.switch-case-end结构
如果在一个程序中,必须针对某个变量不同取值情况进行相应操作,switch语句比if else语句更方便。switch语句的一般形式为:
switch 分支条件(数值或字符串)
case 数值(或字符串)条件1
语句1
case 数值(或字符串)条件2
语句2
case 数值(或字符串)条件3
语句3
case ...
...
otherwise
语句
end
其中分支条件可以是一个函数、变量或者表达式.如果条件1与分支条件匹配就执行语句1,退出循环;否则,检验条件2,如果条件2与分支条件匹配执行语句2,退出循环;否则,检验条件3,...,当所有条件都不与分支条件匹配时就执行最后的语句。注意otherwise是可以省略的。
例4 在图形界面上放置一个弹出式菜,点击弹出式菜单可以设置曲线颜色。
解:程序如下:
x=linspace(-6,6,50);
y=sin(x);
h=plot(x,y,'linewidth',4);
h0=uicontrol('position',[600,500,100,30],...
'style','popupmenu',...
'string','红色|蓝色|黄色|黑色|青色',...
'callback',...
['v=get(h0,''value'');',...
'switch v;',...
'case 1;',...
'set(h,''color'',''r'');',...
'case 2;',...
'set(h,''color'',''b'');',...
'case 3;',...
'set(h,''color'',''y'');',...
'case 4;',...
'set(h,''color'',''k'');',...
'case 5;',...
'set(h,''color'',''c'');',...
'end;']);
⑦ 怎样把Matlab和c语言结合起来编程序
C、C++、JAVA都是完整的通用平台的语言。通俗的说,就是它们可以编写任何程序并可以在大部分硬件系统和操作系统中运行,C++、JAVA都是在C语言基础上发展起来的,在表达形式上三者很相似。区别是,C是面向过程语言,就是说,其编程核心是逻辑流程。C++和Java是面向对象语言,简单的说,是以数据为中心进行编程。这三门语言现在都有强大的生命力,从使用范围上大略可以按照Java——C——C++的顺序排列。特别的,c语言非常适合底层开发,具有独一无二的优势,而且具有基础学习的意义,可以大大地帮助两外两门语言的学习。
VB、QB都是从Basic语言发展起来的。VB是window平台的专属语言,所以适用面窄,也不适合作为入门语言,因为你学不到编程的基本知识和能力,而要花精力去学习windows特有的编程方式和习惯。QB没人用了,死掉的语言。
FOX是一种已经废弃的数据库语言,不用考虑了。
Matlab是使用最广泛的科学计算的软件,在这个软件上用于编写计算程序的语言也叫Matlab。所以它也不是通用编程语言,只适用于科学计算,而且只能用在Matlab软件。初学编程者不用考虑。
学好一门编程语言的方法就一个——大量地编程,书上题目做会之后,尽可能地参与实际的项目,这是最好的锻炼。
9月
⑧ 新手怎么学Matlab
一,MATLAB功能非常全面,也非常强大, 主要用于科学计算,它的计算基于矩阵来实现,可用于以下方面:
1,数值计算(好多问题没有解析解);
2,符号计算(呵呵,很强悍,做高数题方便了,不过在这方面MATLAB还不 是相当强,它的符号计算库借用了Maple的);
3,数据的分析,处理及可视化(数据绘图很方便);
4,图形图像处理,信号分析处理等等;
5,Simulink建模仿真,这是MATLAB非常有特色也是非常强大的功能,也使得其应用不仅仅局限于一般的科学计算。
二,MATLAB的软件应用:
MATLAB是用C语言开发的,支持编程,而且其语法跟C语言很相似,楼主想必已经学过C语言,再学习MATLAB会很轻松。
MATLAB支持与C语言,Fortran语言,Java语言的混合编程,同时支持与word,excel的混合使用,扩展性强。
三,MATLAB的学习:
学习它首先要有比较好的教材,初级阶段就用比较简单的教材,清华的,北航的,都可以。
高级阶段要用比较厚重,全面的教材,推荐一本鄙人正在使用的教材,人们邮电出版社出版,求是科技编着的《MATLAB 7.0 从入门到精通》,还有一本国内翻译的由美国人写的教材,很厚,很全(楼主自己在网上搜一下,我见同系的同学拿过,还是相当不错的)。
另外,学习MATLAB跟学习其他语言一样,要多上机,多练习,熟能生巧嘛。最后祝楼主学习愉快。
以上系个人总结,有啥不妥之处,还请见谅啊(看在我码这么多字的份上,也该奖励一下吧,呵呵)。