-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path2014-04-30-cpp-pointers-to-pointers.html
More file actions
341 lines (266 loc) · 16.5 KB
/
2014-04-30-cpp-pointers-to-pointers.html
File metadata and controls
341 lines (266 loc) · 16.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>柳公子</title>
<link rel="stylesheet" type="text/css" href="http://huliuqing.github.io/stylesheets/reset.css" media="screen" />
<link rel="stylesheet" type="text/css" href="http://huliuqing.github.io/stylesheets/layout.css" media="screen" />
<link rel="stylesheet" type="text/css" href="http://huliuqing.github.io/stylesheets/main.css" media="screen" />
<link rel="stylesheet" type="text/css" href="http://huliuqing.github.io/stylesheets/font.css" media="screen" />
<script type="text/javascript" src="http://lib.sinaapp.com/js/jquery/1.9.0/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="http://imnerd.org/lab/pmblog/src/desert.css" />
<script type="text/javascript" src="http://imnerd.org/lab/pmblog/src/prettify.js"></script>
<link rel="stylesheet" href="http://fancyapps.com/fancybox/source/jquery.fancybox.css?v=2.1.4" type="text/css" media="screen" />
<script type="text/javascript" src="http://fancyapps.com/fancybox/source/jquery.fancybox.pack.js?v=2.1.4"></script>
</head>
<body>
<div class="wrapper">
<div class="header">
<div class="brand">
<a href="http://huliuqing.github.com" class="avatar">
<img src="http://huliuqing.github.io/images/header.jpg" alt="柳公子">
</a>
<h1><a href="http://huliuqing.github.io">柳公子</a></h1>
</div>
<div class="menu">
<h2>导航 / menu</h2>
<ul>
<li><a href="http://huliuqing.github.io/index.html " title="首页">首页</a></li>
<li><a href="http://huliuqing.github.io/contactme.html " title="联系柳公子">联系我</a></li>
<li><a href="http://huliuqing.github.io/aboutme.html " title="关于柳公子">关于我</a></li>
</ul>
</div>
<div class="search">
<form>
<input type="text" name="search" id="search" value="" placeholder="搜索"></input>
<button id="sbutton">搜索</button>
</form>
</div>
</div><!--end / header -->
<div class="contents"> <div class="sider">
<div class="links">
<h2>友链 / friend links</h2>
<ul>
<li><a href="http://stackoverflow.com/users/1969039/liuqing-hu" title="柳公子在stackoverflow">stackoverflow</a></li>
<li><a href="https://github.com/huliuqing" title="柳公子在github">github</a></li>
<li><a href="http://huliuqing.diandian.com " title="柳公子在点点博客">柳公子 - 点点网</a></li>
<li><a href="http://weibo.com/focusliuqing" title="柳公子在新浪微博">柳公子 - weibo</a></li>
</ul>
</div>
<div class="links">
<h2>找到我/find me</h2>
<ul>
<li><a href="http://huliuqing.diandian.com">柳公子点点博客</a></li>
<li><a href=" http://stackoverflow.com/users/1969039/liuqing-hu">柳公子StackOverflow</a></li>
<li><a href="https://github.com/huliuqing">柳公子github</a></li>
</ul>
</div>
</div><!--end/left sider--> <div class="posts">
<div class="post">
<h2><a href="http://huliuqing.github.io/2014-04-30-cpp-pointers-to-pointers.html">c++指针的指针</a></h2>
<div class="post-content"><p>本人最近在学习数据结构(大学没学),感觉在指针问题上需要进行更加深入的学习,才能更好的把数据结构学习和运用好。这篇文章是本人翻译的有关指针的文章(<a href="http://www.eskimo.com/~scs/cclass/int/sx8.html" title="Pointers to Pointers">Pointers to Pointers</a>),供自己学习,有很多语法及表述不正确的地方,如果看到请指正或联系我: liuqing.phper.cn@gmail.com</p>
<p>自从我们可以使用整型指针,字符型指针,自定义结构类型的指针,又或者,我们可以使用任何C语言的任何类型的指针。于是我们可以使用指针指向另外一个指针也就理所当然的了。</p>
<p>如果我们曾经思考过关于指针的问题,那么去思考关于指针本身与之所指向的内容,或许更能够让我加深对指针的理解,也就是我所说的指针的指针。</p>
<p>虽然我们能够区分,指针所指向的内容,还是指针所指向的内容的指针(当然,我们也可以去理解指向指针的指针,指向指针的指针的指针,虽然这些没有太多实际用途)。</p>
<p>指针的指针定义如下:</p>
<pre><code>int **ipp;
</code></pre>
<p>两个星号表示指针的指针。首先让我们看一个简单的例子,来演示ipp指向通过声明定义的指针类型数据(int *ip1或 int * ip2),这些指针类型数据则指向整型变量(int i,j,k)</p>
<pre><code>int i = 5, j = 6; k = 7;
int *ip1 = &i, *ip2 = &j;
</code></pre>
<p>接下来对ipp赋值</p>
<pre><code>ipp = &ip1;
</code></pre>
<p>ipp指向 ip1,ip1指向i,即**ipp就是i,i=5。我们可以使用下图表示 </p>
<p><img src="http://huliuqing.github.com/images/post-source/2014-04-30-cpp-point-to-point-1.gif" /></p>
<p>如果我们再次设置ipp如下:</p>
<pre><code>*ipp = ip2;
</code></pre>
<p>我们便改变了ipp变量所指向的指针地址为ip2.因而ipp(ip1)也就指向了j,如果我们赋值如下</p>
<p><img src="http://huliuqing.github.com/images/post-source/2014-04-30-cpp-point-to-point-2.gif" /></p>
<pre><code>*ipp = &k;
</code></pre>
<p>我们便改变了ipp变量所指向的指针地址,为k的地址.因而ipp(ip1)也就指向了k</p>
<p><img src="http://huliuqing.github.com/images/post-source/2014-04-30-cpp-point-to-point-3.gif" /></p>
<p>在实际应用中,指针的指针应用在哪会比较合适呢?其中一个应用案例就是:通过把普通形参替换成指针做函数返回值。为了演示和说明,我们通过传入一个简单类型(如int型)的指针类型做函数的形参,函数如下:</p>
<pre><code>f(int *ip)
{
*ip = 5;
}
</code></pre>
<p>然后调用</p>
<pre><code>int i;
f(&i);
</code></pre>
<p>调用f函数之后将会“返回” 5给函数主调函数所传入的指针类型实参。</p>
<p>在这个示例中,主调函数为i变量。函数可以通过这种方法(传入指针类型变量)返回多个值。因为函数是只可以返回一个值。需要注意的是f函数是通过一个指针类型变量(int *)来返回值的。 </p>
<p>现在,如果我们需要函数返回一个指针,传入的形参类型需要为指针的指针。在这有一个函数为长度为n的字符分配内存,失败返回0、成功返回1,并且返回指针指向新分配内存的指针</p>
<pre><code>#include <stdlib.h>
int allocstr(int len, char **retptr)
{
char *p = malloc(len + 1); /* +1 for \0 */
if(p == NULL)
return 0;
*retptr = p;
return 1;
}
//主调函数如下
char *string = "Hello, world!";
char *copystr;
if(allocstr(strlen(string), &copystr))
strcpy(copystr, string);
else
fprintf(stderr, "out of memory\n");
</code></pre>
<p>(allocstr函数并非特别实用,仅仅是个简单的内存分配函数示例,为了易于调用并直接分配内存空间。我们使用的chkmalloc函数将更加实用)</p>
<pre><code>double *dptr;
if(!hypotheticalwrapperfunc(100, sizeof(double), &dptr))
fprintf(stderr, "out of memory\n");
</code></pre>
<p>hypotheticalwrapperfunc不允许传入void <strong>类型参数,而是需要传入double</strong>类型参数
对于指针的指针,同样适用于模拟实现多维数组的动态内存分配,这将在下一章节讨论。</p>
<p>最后一个示例,让我们看看指针的指针是如何用来解决链表中插入和删除这个令人讨厌的问题的。简单起见,我们仅仅考虑整型链表,结构体如下:</p>
<p>struct list
{
int item;
struct list *next;
};</p>
<p>让我们尝试从链表中删除给定的整数。简单的解决方案如下: </p>
<pre><code>/* delete node containing i from list pointed to by lp */
struct list *lp, *prevlp;
for(lp = list; lp != NULL; lp = lp->next)
{
if(lp->item == i)
{
if(lp == list)
{
list = lp->next;
}else
{
prevlp->next = lp->next;
break;
}
prevlp = lp;
}
}
</code></pre>
<p>这段代码是可以运行的,但是存在两个不足之处。
第一、我们需要使用一个额外的变量来保存节点与节点的关系。
第二、当节点在链表头部被删除,我们需要使用额外的测试。为什么会出现这两个不足,原因在于我们从链表中删除一个节点,会涉及到指针所指向的节点需要移动到下一个节点(删除节点的前一节点的指针,需要指向删除节点的下一节点)。但这取决于删除节点是不是头一个节点,如果是头一个节点我们需要时指针指向链表的新头部,如果不是我们需要将删除节点的前一个节点的指针指向下一个节点。</p>
<p>为了阐明这一点,加点我们有一个链表 list(1,2,3)。让我们从表中删除节点1。当我们找到1节点时,指针变量lp指向节点1,而链表list的指针其实也是指向同一个节点1的,如下图(a)所示:</p>
<p><img src="http://huliuqing.github.com/images/post-source/2014-04-30-cpp-point-to-point-4.gif" /></p>
<p>删除节点1之后,我们需要使链表list的指针指向链表的第二个节点,也就是链表新的头结点(图(b)所示)。</p>
<p>假使我们需要删除的是元素的节点2(如图(c)所示)。</p>
<p>我们则需要让链表的第一个节点的指针指向节点3。</p>
<p>指针变量prevlp要保存前一个节点,因为我们需要让它的下一个节点做出调整(另外我们要注意的是如果我们要删除第三个节点,我们要把它所指向下一个节点地址,复制给节点2,但节点3的下一个节点地址为空,所以此时节点2就是链表新的尾节点)。</p>
<p>让我们再来重写链表的删除操作,通过运用链表指针的指针,新的实现方法更加简单。这个指针将指向我们所查找节点的指针,它既可以指向头指针也可以指向下一个节点指针。直到这个指针所指向的指针,是指向我们需要查找的节点时为止,它指向我们查找并需要修改删除的节点指针。让我们来看看代码。</p>
<p>struct list **lpp;
for(lpp = &list; <em>lpp != NULL; lpp = &(</em>lpp)->next)
{
if( (<em>lpp)->item == i)
{
*lpp = (</em>lpp)->next;
break;<br />
}
}</p>
<p>代码 <em>lpp = (</em>lpp)->next会更新当前的指针,不论是头指针还是其中的任何一个指针(当然初见之下,在链表上运用指针的指针,所采用的算法并不会带来多大的好处)。为了简单阐述指针的指针在lpp变量上的操作,通过两张图来演示删除第一个节点(左图)和第二个节点(右图)。</p>
<p><img src="http://huliuqing.github.com/images/post-source/2014-04-30-cpp-point-to-point-5.gif" /></p>
<p>在以上两个链表删除操作的示例中</p>
<pre><code>① lpp变量所指向的是,一个指向被删除节点的节点指针。
② lpp所指向的指针,是将被更新的指针。
③ 新的指针(*lpp更新的指针)是被删除节点的下一个指针,它永远是(*lpp)->next
</code></pre>
<p>*lpp所指向的下一个节点指针,也就是lpp所指向的指针的指针。可以替换如下: </p>
<p>lpp = &(*lpp)->next</p>
<p>通过<em>lpp,将lpp指向list链表的下一个域。不管怎样括号都不能省略,因为->优先级高于</em>的优先级。</p>
<p>接下来让我们看一个相关的示例,让我们在list链表中插入一个新的节点。同样适用list链表结构的指针的指针,这样,我们就不用来区别对待list链表在不同情况下的插入了。</p>
<p>/* insert node newlp into list */</p>
<pre><code>struct list **lpp;
for(lpp = &list; *lpp != NULL; lpp = &(*lpp)->next)
{
struct list *lp = *lpp;
if(newlp->item < lp->item)
{
newlp->next = lp;
*lpp = newlp;
break;
}
}
</code></pre>
</div>
<span class="post-date">2014-04-30 14:30:00</span>
<span class="post-tag">
<a href="http://huliuqing.github.io/tag/编程语言">编程语言</a>
<a href="http://huliuqing.github.io/tag/c++">c++</a>
<a href="http://huliuqing.github.io/tag/指针">指针</a>
</span>
<!-- open 3td party comment service-->
<div class="comments-thread">
<div id="disqus_thread"></div>
<script type="text/javascript">
/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
var disqus_shortname = 'phpnote'; // required: replace example with your forum shortname
/* * * DON'T EDIT BELOW THIS LINE * * */
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>
</div>
</div>
<div class="pagination">
<ul>
</ul>
</div>
</div><!--end/posts-->
</div><!--end /contents-->
<div class="footer">
<div class="social span3">
<h3>关注我</h3>
<ul>
<li><a class="glyph" href="" title=""><i class="icon-weibo"></i></a></li>
<li><a class="glyph" href="" title="点点网博客"> 点点网</a></li>
<li><a class="glyph" href="" title="柳公子的gmail邮箱"> stackoverflow</a></li>
</ul>
</div>
<div class="list span3">
<h3>我的博客</h3>
<ul>
<li><a href="http://stackoverflow.com/users/1969039/liuqing-hu" title="柳公子在stackoverflow">stackoverflow</a></li>
<li><a href="https://github.com/huliuqing" title="柳公子在github" >github</a></li>
<li><a href="http://huliuqing.diandian.com" title="柳公子在点点博客">柳公子 - 点点网</a></li>
<li><a href="http://weibo.com/focusliuqing" title="柳公子在新浪微博">柳公子 - weibo</a></li>
</ul>
</div>
<div class="list span3">
<h3>主题</h3>
<ul>
<li>社交图标 by <a href="https://github.com/lexrus/fontdiao" title="fontdiao"> fontdiao</a></li>
<li>主题 by <a href="https://huliuqing.github.io" title="柳公子">柳公子</a></li>
</ul>
</div>
</div><!--end/footer-->
</div><!--end/wrapper-->
</body>
<script type="text/javascript">
var s=document.getElementById('search'), b=document.getElementById('sbutton');
b.onclick = function() {
if(s.value != '') {
window.open("https://www.google.com.hk/#q=site:http://huliuqing.github.io "+s.value);
} else {
alert('请输入搜索内容');
}
}
</script>
<script type="text/javascript">
$(function () {
$("pre").addClass("prettyprint linenums");
prettyPrint();
})
</script>
</html>