指针问题专用贴

指针作为形参肯定有很多都不清楚其中具体的原理,我也是最近摸清了些门道:


下面就用一些例子来给大家说明:

[cpp]  view plain  copy
  1. void myMalloc(char *s) //我想在函数中分配内存,再返回   
  2. {   
  3.     s=(char *) malloc(100);   
  4. }   
  5. void main()   
  6. {   
  7.     char *p=NULL;   
  8.     myMalloc(p); //这里的p实际还是NULL,没有能分配到100字节空间,为什么?   
  9.     if(p)   
  10.        free(p);  
  11. }   

 
基于上面的问题: 因为指针作为形参传递过去的是它的拷贝,只是说他们指向同一块内存地址。 

    上面其实是给他的拷贝体进行了内存地址分配

[cpp]  view plain  copy
  1. void myMalloc(char **s)   
  2. {   
  3.     *s=(char *) malloc(100);   
  4. }   
  5. void main()   
  6. {   
  7.     char *p=NULL;   
  8.     myMalloc(&p); //这里的p可以得到正确的值了   
  9.     if(p) free(p);   
  10. }   

这里为什么能得到正确的值了呢? 

因为这里形参分配的内存其实是给s本身在分配了 ,上面分配的时候用的是(*s)

[cpp]  view plain  copy
  1. #include<stdio.h>   
  2. void fun(int *p)   
  3. {   
  4.     int b=100;   
  5.     p=&b;   
  6. }   
  7. main()   
  8. {   
  9.     int a=10;   
  10.     int *q;   
  11.     q=&a;   
  12.     printf("%d/n",*q);   
  13.     fun(q);   
  14.     printf("%d/n",*q);   
  15.     return 0;   
  16. }   
这里打印的结果为: 10  10

为什么呢? 因为main函数中q指针作为形参传递给了fun函数,fun函数中p为q指针的拷贝体,f

fun函数中的p在函数体中重新指向了整数b的地址。所以q指针本身的值是没有发生变化的


[cpp]  view plain  copy
  1. #include<stdio.h>   
  2. void fun(int *p)   
  3. {   
  4.     *p=100;   
  5. }   
  6. main()   
  7. {   
  8.     int a=10;   
  9.     int *q;   
  10.     q=&a;   
  11.     printf("%d/n",*q);   
  12.     fun(q);   
  13.     printf("%d/n",*q);   
  14.     return 0;   
  15. }   

这里打印的结果是: 10  100

这里可以正确打印我们想要的结果了,因为main函数中的q指针和形参中的p指针都指向了整数a的地址。

fun函数中其实是修改整数a地址中的值,所以在后文中打印指针q中的内容时,也能打印出100了



指针作为函数参数


鉴于很多人对“函数参数传递”这一块不理解,比如问int &a与int*&a的区别等等,我根据自己的理解,以容易理解的方式总结了一下,总共有八种(可能还有)。这只是我能想到了的。请大家继续多多指教,拍砖也可以!
另外声明:为了便于解释,我把讲解都以注释的形式写在程序中了。不习惯的人就迁就看吧!

C/C++ code
?
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

#include <iostream>
using  namespace  std;
/*为了便于区分讲解,函数中的临时参数标识符不用void fun1(int x,int y)代码中的x,y而用a与b替换
*另外,程序解释不用太多的语法,用通俗的话语依旧可以很有趣。“千言万语不如一个好例子”。下面
*我就遵循这个原则去解释我对问题的理解。
*/
 
/*fun1中的参数ab是在函数fun1调用的时候才分配内存单元,也就是临时变量,在函数调用结束后
*自动销毁。当调用fun1(x,y)时,实际相当于fun1(int a=x,int b=y)或者fun1(int a=*x0,int b=*y0);
*因此ab有自己的内存,通过调用ab也有了自己的值,那么在函数中无论对ab的什么操作,都只影响到ab,
*而与xy无关。
*用一个比喻更好解释:假设我国要引进俄国某个机型的战斗机生产线,那么通过政府(main())批准审核投资
*这个生产线就建造成了(fun1());那么这个生产线与俄国内的同样的生产线之间是相互独立的
*(ab与xy的区别),唯一的联系是:通过政府(main())出钱购买他们的技术或者设配(调用,同时a=x,b=y)
*经过这样之后,我们无论在这个生产线上造什么牛逼的歼十,十一。都与俄国本部的生产线无关了,他们关不
*着也问不着!
*/

void  fun1( int  a, int  b)
{ //这个函数交换数值是:治标不治本
     int  tem;
     tem=a;
     a=b;
     b=tem;
     cout<< "fun1(int a,int b):a=" <<a<< ",b=" <<b<<endl;
}
 
/*fun2数值的交换效果依旧是治标不治本。而且要注意它与fun3的区别,虽然它们形参格式相同
*临时开辟三个临时指针,a、b、tem。同样三者都是局部变量,与函数“老大”“同年同月同日同时生”
*而且“同年同月同日同时死”(很像三国的桃园三结义,都是忠诚的卫士)。fun2中的指针ab存储的
*是x,y的地址,等价于fun2(int *a=&x,int *b=&y)或者fun2(int *a=x0,int *b=y0);fun2中的代码
*实现的是把指针ab存的地址值交换一下,实质是交换了ab指针的指向,因此ab存储的地址中存储
*值还是没有改变。而且也不影响外界指针x0y0的指向,在fun7中会看到与不同
*可以通过fun2中注释掉的语句验证一下
*/
void  fun2( int  *a, int  *b)
{
     //cout<<"a存的地址值"<<a<<"\nb存的地址值"<<b<<endl;
     //cout<<"a指向的值"<<*a<<"\nb指向的值"<<*b<<endl;
     int  *tem;
     tem=a;
     a=b;
     b=tem;
     cout<< "fun2(int *a,int *b):*a=" <<*a<< ",*b=" <<*b<<endl;
     //cout<<"a存的地址值"<<a<<"\nb存的地址值"<<b<<endl;
     //cout<<"a指向的值"<<*a<<"\nb指向的值"<<*b<<endl;
}
 
 
 
/*fun3交换数值的效果才算治本了!
*局部变量问题不再解释。通过临时指针ab中存储的地址,找到真正要交换的xy值,然后把他们交换了!
*公安局喜欢这样干活,他们总是不能直接找到犯罪主谋,但是他们会找到一些知道主谋线索的其他非主谋
*嫌疑犯,那么通过抓住他们然后用刑折磨,这要比直接找主谋要容易些,当然这样做有些曲折(绕弯)!但也很有效
*同理,假设你在家里建一个小金库(这里的xy),那么你要设置好自己的密码(xy的地址),然后死死地
*记在脑海(指针)中。每当想打开看看让自己踏实些,你就要从脑海中找到这个密码然后打开它。然而技术
*在飞跃,假设已有《盗梦空间》中的技术,我想改变你的意念(fun3)或者从梦中偷你的思想或者秘密
*接下来的情节会更精彩...
*/
void  fun3( int  *a, int  *b)
{
     int  tem;
     tem=*a;
     *a=*b;
     *b=tem;
     cout<< "fun3(int *a,int *b):*a=" <<*a<< ",*b=" <<*b<<endl;
}
 
 
/*fun4表述的是“引用”
*引用的通俗解释:相当于一个人有多个名字或者外号一样。无论你叫他哪个名字,他都应。
*因此引用很像:一个变量有多个标识符(这样说稍微有些不当)。如果a是变量b的引用,那么ab是同一对象
*通过调用fun4(x,y)或者fun4(*x0,*y0).那么临时变量ab分别是xy与*x0与*y0的引用了。对ab操作就相当于在
*main中直接操作xy
*/
void  fun4( int  &a, int  &b)
{
     int  tem;
     tem=a;
     a=b;
     b=tem;
     cout<< "fun4(int &a,int &b):a=" <<a<< ",b=" <<b<<endl;
}
 
 
/*fun5参数采用指向指针的指针,这比fun2,fun3还要绕弯子,但这里依旧要注意fun5与fun7的区别
*fun5依旧治标不治本,fun6才能治本,他们实质和fun2与fun3类似,只不过比它们要多一层指针
*既然多一层指针那么在调用的时候传递的实参就必须是指针的地址,而不能是别的。等价于
*fun5(int **a=&x0,int **b=&y0)
*换用上面的比喻:相当于在《盗梦空间》里进入第二层梦里偷意念了。c++里没有拓展到第三,四层梦里
*去偷东西!也就是没有***a或者*****a。因为两层处理的很好了!
*/
void  fun5( int  **a, int  **b)
{
     int  **tem;
     tem=a;
     a=b;
     b=tem;
     cout<< "fun5(int **a,int **b):**a=" <<**a<< ",**b=" <<**b<<endl;
}
 
 
/*fun6和fun3有相同的实质,只是多一层指针
*/
void  fun6( int  **a, int  **b)
{
     int  tem;
     tem=**a;
     **a=**b;
     **b=tem;
     cout<< "fun6(int **a,int **b):**a=" <<**a<< ",**b=" <<**b<<endl;
}
 
/*fun7实现与fun2不同效果,上面我已经提到了。
*fun2结果是函数内部的交换不会影响到外面指针的指向,但是这里不同了,fun7函数实现了指针x0y0
*指向的交换。但却没有影响到xy的值的交换。就因为多了一个“引用(&)”。而fun2中是开辟的临时指针变量
*明白引用就能明白这里的效果。
*/
void  fun7( int  *&a, int  *&b)
{
     int  *tem;
     tem=a;
     a=b;
     b=tem;
     cout<< "fun7(int *&a,int *&b):*a=" <<*a<< ",*b=" <<*b<<endl;
}
 
/*这里达到的效果同fun3,二者一定程度上可以互相替换,只不过调用时有些区别!
*/
void  fun8( int  *&a, int  *&b)
{
     int  tem;
     tem=*a;
     *a=*b;
     *b=tem;
     cout<< "fun8(int *&a,int *&b):*a=" <<*a<< ",*b=" <<*b<<endl;
}
int  main()
{
     int  x=13,*x0=&x,&x1=x;
     int  y=250,*y0=&y,&y1=y;
 
     cout<< "\n调用前main():x=" <<x<< ",y=" <<y<<endl;
     fun1(x,y);
     cout<< "调用后main():x=" <<x<< ",y=" <<y<<endl;
 
     //fun1(&x,&y);//错误
 
     cout<< "\n调用前main():*x0=" <<*x0<< ",*y0=" <<*y0<<endl;
     fun1(*x0,*y0); //这与上面的fun1调用没有区别
     cout<< "调用后main():*x0=" <<*x0<< ",*y0=" <<*y0<<endl;
 
 
 
     cout<< "\n调用前main():*x0=" <<*x0<< ",*y0=" <<*y0<<endl;
     fun2(x0,y0); //把指针的地址传递过去,
     cout<< "调用后main():*x0=" <<*x0<< ",*y0=" <<*y0<<endl;
 
     cout<< "\n调用前main():x=" <<x<< ",y=" <<y<<endl;
     fun2(&x,&y); //把指针的地址的副本传递过去(按值传递),依旧不会影响原来的指针x0y0的指向
     cout<< "调用后main():x=" <<x<< ",y=" <<y<<endl;
 
 
 
     cout<< "\n调用前main():*x0=" <<*x0<< ",*y0=" <<*y0<<endl;
     fun3(x0,y0);
     cout<< "调用后main():*x0=" <<*x0<< ",*y0=" <<*y0<<endl;
     cout<< "调用后main():x=" <<x<< ",y=" <<y<<endl;
 
     cout<< "\n调用前main():x=" <<x<< ",y=" <<y<<endl;
     fun3(&x,&y);
     cout<< "调用后main():x=" <<x<< ",y=" <<y<<endl;
     cout<< "调用后main():*x0=" <<*x0<< ",*y0=" <<*y0<<endl;
 
 
 
     cout<< "\n调用前main():x=" <<x<< ",y=" <<y<<endl;
     fun4(x,y);
     cout<< "调用后main():x=" <<x<< ",y=" <<y<<endl;
 
     cout<< "\n调用前main():*x0=" <<*x0<< ",*y0=" <<*y0<<endl;
     fun4(*x0,*y0);
     cout<< "调用后main():*x0=" <<*x0<< ",*y0=" <<*y0<<endl;
 
 
     //fun5(&x,&y);//错误
 
     cout<< "\n调用前main():x=" <<x<< ",y=" <<y<<endl;
     fun5(&x0,&y0);
     cout<< "调用后main():x=" <<x<< ",y=" <<y<<endl;
     cout<< "调用后main():*x0=" <<*x0<< ",*y0=" <<*y0<<endl;
 
     cout<< "\n调用前main():*x0=" <<*x0<< ",*y0=" <<*y0<<endl;
     fun6(&x0,&y0);
     cout<< "调用后main():*x0=" <<*x0<< ",*y0=" <<*y0<<endl;
     cout<< "调用后main():x=" <<x<< ",y=" <<y<<endl;
 
 
//这里之所以把fun8调用放在fun7之前,是因为如果fun7在fun8前,那么fun7调用后x0指向y,y0指向x,
//再调用fun8得到的结果不便于理解。
     cout<< "\n调用前main():*x0=" <<*x0<< ",*y0=" <<*y0<<endl;
     fun8(x0,y0);
     cout<< "调用后main():*x0=" <<*x0<< ",*y0=" <<*y0<<endl;
     cout<< "调用后main():x=" <<x<< ",y=" <<y<<endl;
 
 
 
     cout<< "\n调用前main():*x0=" <<*x0<< ",*y0=" <<*y0<<endl;
     fun7(x0,y0);
     cout<< "调用后main():*x0=" <<*x0<< ",*y0=" <<*y0<<endl;
     cout<< "调用后main():x=" <<x<< ",y=" <<y<<endl;
 
     //fun7(&x,&y);//错误
 
    system ( "pause" );
    return  0;
}


智慧旅游解决方案利用云计算、物联网和移动互联网技术,通过便携终端设备,实现对旅游资源、经济、活动和旅游者信息的智能感知和发布。这种技术的应用旨在提升游客在旅游各个环节的体验,使他们能够轻松获取信息、规划行程、预订票务和安排食宿。智慧旅游平台为旅游管理部门、企业和游客提供服务,包括政策发布、行政管理、景区安全、游客流量统计分析、投诉反馈等。此外,平台还提供广告促销、库存信息、景点介绍、电子门票、社交互动等功能。 智慧旅游的建设规划得到了国家政策的支持,如《国家中长期科技发展规划纲要》和国务院的《关于加快发展旅游业的意见》,这些政策强调了旅游信息服务平台的建设和信息化服务的重要性。随着技术的成熟和政策环境的优化,智慧旅游的时机已经到来。 智慧旅游平台采用SaaS、PaaS和IaaS等云服务模式,提供简化的软件开发、测试和部署环境,实现资源的按需配置和快速部署。这些服务模式支持旅游企业、消费者和管理部门开发高性能、高可扩展的应用服务。平台还整合了旅游信息资源,提供了丰富的旅游产品创意平台和统一的旅游综合信息库。 智慧旅游融合应用面向游客和景区景点主管机构,提供无线城市门户、智能导游、智能门票及优惠券、景区综合安防、车辆及停车场管理等服务。这些应用通过物联网和云计算技术,实现了旅游服务的智能化、个性化和协同化,提高了旅游服务的自由度和信息共享的动态性。 智慧旅游的发展标志着旅游信息化建设的智能化和应用多样化趋势,多种技术和应用交叉渗透至旅游行业的各个方面,预示着全面的智慧旅游时代已经到来。智慧旅游不仅提升了游客的旅游体验,也为旅游管理和服务提供了高效的技术支持。
智慧旅游解决方案利用云计算、物联网和移动互联网技术,通过便携终端设备,实现对旅游资源、经济、活动和旅游者信息的智能感知和发布。这种技术的应用旨在提升游客在旅游各个环节的体验,使他们能够轻松获取信息、规划行程、预订票务和安排食宿。智慧旅游平台为旅游管理部门、企业和游客提供服务,包括政策发布、行政管理、景区安全、游客流量统计分析、投诉反馈等。此外,平台还提供广告促销、库存信息、景点介绍、电子门票、社交互动等功能。 智慧旅游的建设规划得到了国家政策的支持,如《国家中长期科技发展规划纲要》和国务院的《关于加快发展旅游业的意见》,这些政策强调了旅游信息服务平台的建设和信息化服务的重要性。随着技术的成熟和政策环境的优化,智慧旅游的时机已经到来。 智慧旅游平台采用SaaS、PaaS和IaaS等云服务模式,提供简化的软件开发、测试和部署环境,实现资源的按需配置和快速部署。这些服务模式支持旅游企业、消费者和管理部门开发高性能、高可扩展的应用服务。平台还整合了旅游信息资源,提供了丰富的旅游产品创意平台和统一的旅游综合信息库。 智慧旅游融合应用面向游客和景区景点主管机构,提供无线城市门户、智能导游、智能门票及优惠券、景区综合安防、车辆及停车场管理等服务。这些应用通过物联网和云计算技术,实现了旅游服务的智能化、个性化和协同化,提高了旅游服务的自由度和信息共享的动态性。 智慧旅游的发展标志着旅游信息化建设的智能化和应用多样化趋势,多种技术和应用交叉渗透至旅游行业的各个方面,预示着全面的智慧旅游时代已经到来。智慧旅游不仅提升了游客的旅游体验,也为旅游管理和服务提供了高效的技术支持。
深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值