📄 m2_pointers.hlp
字号:
{cmd:*}{it:P}{cmd:[2]} is equivalent to {it:X2} and
{cmd:*}{it:Q}{cmd:[2]} is equivalent to {it:f2}().
{title:Mixed pointer arrays}
{p 4 4 2}
You may create mixed pointer arrays, such as
{it:R}{cmd: = (&}{it:X}{cmd:, &}{it:f}{cmd:())}
{p 4 4 2}
In this case,
{cmd:*}{it:R}{cmd:[2]} is equivalent to {it:f}().
{p 4 4 2}
You may not, however, create arrays of pointers mixed with real, complex,
or string elements. Mata will abort with a type-mismatch error.
{title:Definition of NULL}
{p 4 4 2}
{cmd:NULL} is the special pointer value that means "points to nothing" or
undefined. {cmd:NULL} is like 0 in many ways -- for instance, coding
{cmd:if (X)} is equivalent to coding {cmd:if (X!=NULL)}, but {cmd:NULL}
is distinct from zero in other ways. 0 is a numeric value; {cmd:NULL} is
a pointer value.
{title:Use of parentheses}
{p 4 4 2}
Use parentheses to make your meaning clear.
{p 4 4 2}
In the table below, we assume
{it:p} {cmd:= &}{it:X}
{it:P} {cmd:= (&}{it:X11}{cmd:, &}{it:X12}{cmd: \ &}{it:X21}{cmd:, &}{it:X22}{cmd:)}
{it:q} {cmd:= &}{it:f}{cmd:()}
{it:Q} {cmd:= (&}{it:f11}{cmd:(), &}{it:f12}{cmd:() \ &}{it:f21}{cmd:(), &}{it:f22}{cmd:())}
{p 4 4 2}
where
{it:X},
{it:X11},
{it:X12},
{it:X21}, and
{it:X22}
are matrices and
{it:f}(),
{it:f11}(),
{it:f12}(),
{it:f21}(), and
{it:f22}()
are functions.
Expression meaning
{hline 64}
{cmd:*}{it:p} {it:X}
{cmd:*}{it:p}{cmd:[1,1]} {it:X}
{cmd:(*}{it:p}{cmd:)[1,1]} {it:X}{cmd:[1,1]}
{cmd:*}{it:P}{cmd:[1,2]} {it:X12}
{cmd:(*}{it:P}{cmd:[1,2])[3,4]} {it:X12}{cmd:[3,4]}
{cmd:*}{it:q}{cmd:(a,b)} execute function {it:q}{cmd:()} of {cmd:a}, {cmd:b}; dereference that
{cmd:(*}{it:q}{cmd:)(a,b)} {it:f}{cmd:(}{it:a}{cmd:,}{it:b}{cmd:)}
{cmd:(*}{it:q}{cmd:[1,1])(a,b)} {it:f}{cmd:(}{it:a}{cmd:,}{it:b}{cmd:)}
{cmd:*}{it:Q}{cmd:[1,2](a,b)} nonsense
{cmd:(*}{it:Q}{cmd:[1,2])(a,b)} {it:f12}{cmd:(}{it:a}{cmd:,}{it:b}{cmd:)}
{hline 64}
{title:Pointer arithmetic}
{p 4 4 2}
Arithmetic with pointers (which is to say, with addresses) is not allowed:
: {cmd:y = 2}
: {cmd:x = &y}
: {cmd:x+2}
{err:<stmt>: 3205 undefined operation on pointer}
{p 4 4 2}
Do not confuse the expression {cmd:x+2} with the expression {cmd:*x+2}, which
is allowed and in fact evaluates to 4.
{p 4 4 2}
You may use the equality and inequality operators {cmd:==} and {cmd:!=} with
pairs of pointer values:
{cmd}if (p1 == p2) {c -(}
...
{c )-}
if (p1 != p2) {c -(}
...
{c )-}{txt}
{p 4 4 2}
In addition, pointer values may be assigned and compared with the value
{cmd:NULL}, which is a lot like, but different from, zero: {cmd:NULL} is a 1
{it:x} 1 scalar containing an address value of 0. An unassigned pointer has
the value {cmd:NULL}, and you may assign the value {cmd:NULL} to pointers:
{cmd:p = NULL}
{p 4 4 2}
Pointer values may be compared with {cmd:NULL},
{cmd}if (p1 == NULL) {c -(}
...
{c )-}
if (p1 != NULL) {c -(}
...
{c )-}{txt}
{p 4 4 2}
but if you attempt to dereference a {cmd:NULL} pointer, you will get an error:
: {cmd:x = NULL}
: {cmd:*x + 2}
{err:<stmt>: 3120 attempt to dereference NULL pointer}
{p 4 4 2}
Concerning logical expressions, you may directly examine pointer values:
{cmd}if (p1) {c -(}
...
{c )-}{txt}
{p 4 4 2}
The above is interpreted as if {cmd:if (p1!=NULL)} were coded.
{title:Listing pointers}
{p 4 4 2}
You may list pointers:
: {cmd:y = 2}
: {cmd:x = &y}
: {cmd:x}
{cmd:0x8359e80}
{p 4 4 2}
What is shown, 0x8359e80, is the memory address of {cmd:y} during our
Stata session. If you typed the above lines, the address you would see could
differ, but that does not matter.
{p 4 4 2}
Listing the value of pointers often helps in debugging because, by comparing
addresses, you can determine where pointers are pointing and whether some
are pointing to the same thing.
{p 4 4 2}
In listings, {cmd:NULL} is presented as 0x0.
{title:Declaration of pointers}
{p 4 4 2}
Declaration of pointers, as with all declarations (see
{bf:help m2_declarations:[M-2] declarations}})
is optional. That basic syntax is
{p 8 12 2}
{cmd:pointer}[{cmd:(}{it:totype}{cmd:)}]
{it:orgtype}
[{cmd:function}]
...
{p 4 4 2}
For instance,
{cmd:pointer(real matrix) scalar} {it:p1}
{p 4 4 2}
declares that {it:p1} is a pointer scalar and that it points to a
real matrix, and
{cmd:pointer(complex colvector) rowvector} {it:p2}
{p 4 4 2}
declares that {it:p2} is a row vector of pointers and that each
individual pointer points to a complex colvector, and
{cmd:pointer(real scalar function) scalar} {it:p3}
{p 4 4 2}
declares that {it:p3} is a pointer scalar and that it points to a
function that returns a real scalar, and
{cmd:pointer(pointer(real matrix function) rowvector) colvector} {it:p4}
{p 4 4 2}
declares that {it:p4} is a column vector of pointers to pointers, the pointers
to which each element points are row vectors, and each of those elements
point to a function returning a real matrix.
{p 4 4 2}
You can omit the pieces you wish.
{cmd:pointer() scalar} {it:p5}
{p 4 4 2}
declares that {it:p5} is a pointer scalar -- to what being uncertain.
{cmd:pointer scalar} {it:p5}
{p 4 4 2}
means the same thing.
{cmd:pointer} {it:p6}
{p 4 4 2}
declares that {it:p6} is a pointer, but whether it is a matrix, vector, or
scalar, is unsaid.
{title:Use of pointers to collect objects}
{p 4 4 2}
Assume that you wish to write a function in two parts: {cmd:result_setup()} and
{cmd:repeated_result()}.
{p 4 4 2}
In the first part, {cmd:result_setup()}, you will be passed a matrix and a
function by the user, and you will make a private calculation that you will
use later, each time {cmd:repeated_result()} is called.
When {cmd:repeated_result()} is called, you will need to know the matrix,
the function, and the value of the private calculation that you previously
made.
{p 4 4 2}
One solution is to adopt the follow design. You request the user code
{cmd:resultinfo = result_setup(}{it:setup args}...{cmd:)}
{p 4 4 2}
on the first call, and
{it:value} {cmd:= repeated_result(resultinfo,} {it:other args}...{cmd:)}
{p 4 4 2}
on subsequent calls. The design is that you will pass the information between
the two functions in {cmd:resultinfo}.
In this case, {cmd:resultinfo} will need to contain three things: the
original matrix, the original function, and the private result you
calculated. The user, however, never need know the details, and you will
simply request that the user declare {cmd:resultinfo} as a pointer vector.
{p 4 4 2}
Filling in the details, you code
{cmd}pointer vector result_setup(real matrix X, pointer(function) f)
{c -(}
real matrix privmat
pointer vector info
...
privmat = ...
...
info = (&X, f, &privmat)
return(info)
{c )-}
real matrix repeated_result(pointer vector info, ...)
{c -(}
pointer(function) scalar f
pointer(matrix) scalar X
pointer(matrix) scalar privmat
f = info[2]
X = info[1]
privmat = info[3]
...
... (*f)(...) ...
... (*X) ...
... (*privmat) ...
...
{c )-}{txt}
{p 4 4 2}
In point of fact, it was not necessary to unload {cmd:info[]} into the
individual scalars. The lines using the passed values could just as well
have read
... {cmd:(*info[2])(}...{cmd:)} ...
... {cmd:(*info[1])} ...
... {cmd:(*info[3])} ...
{title:Efficiency}
{p 4 4 2}
When calling subroutines, it is better to pass the evaluation of pointer
scalar arguments rather than the pointer scaler itself, because then the
subroutine can run a little faster. For instance, say {cmd:p} points to
a real matrix. It is better to code
... {cmd:mysub(*p)} ...
{p 4 4 2}
rather than
... {cmd:mysub(p)} ...
{p 4 4 2}
and then to write {cmd:mysub()} as
{cmd:function mysub(real matrix X)}
{cmd:{c -(}}
... {cmd:X} ...
{cmd:{c )-}}
{p 4 4 2}
rather than
{cmd:function mysub(pointer(real matrix) scalar p)}
{cmd:{c -(}}
... {cmd:(*p)} ...
{cmd:{c )-}}
{p 4 4 2}
Dereferencing a pointer (obtaining {cmd:*}{it:p} from {it:p}) does not
take long, but it does take time.
Passing {cmd:*}{it:p} rather than {it:p} can be important if
{cmd:mysub()} loops and performs the evaluation of {cmd:*}{it:p}
hundreds of thousands or millions of times.
{title:Diagnostics}
{p 4 4 2}
The prefix operator {cmd:*}
(called the dereferencing operator) aborts with error if it is applied to a
nonpointer object.
{p 4 4 2}
Arithmetic may not be performed on undereferenced pointers. Arithmetic
operators abort with error.
{p 4 4 2}
The prefix operator {cmd:&} aborts with error if it is applied to a
built-in function.
{title:Also see}
{p 4 13 2}
Manual: {hi:[M-2] pointers}
{p 4 13 2}
Online: help for
{bf:{help m2_intro:[M-2] intro}}
{p_end}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -