现在讲一下指针的主要用途和常见错误。


[用途]

1.用作形参

  首先,常见新手写交换函数:

 void swap(int a,int b){
int t = a;
a = b;
b = t;
}

  主函数里调用一下试试,看看a,b的值有没有改变?

 #include<iostream>
#include<stdlib.h>
using namespace std;
void swap(int,int);
int main(){
int a = ;
int b = ;
swap(a,b);
cout<<a<<" "<<b;
return ;
}
void swap(int a,int b){
int t = a;
a = b;
b = t;
}

  运行结果就不公布了,对于新手,有木有发现什么不对的地方?

是什么原因造成这个结果的呢?应该是内存地址吧,要同一内存地址修改其中一个的值

才会改变另一个的值,那来验证一下:

#include<iostream>
#include<stdlib.h>
using namespace std;
void swap(int,int);
int main(){
int a = ;
int b = ;
cout<<"address in main: &a = "<<&a<<" &b = "<<&b<<endl;
swap(a,b);
cout<<a<<" "<<b;
return ;
}
void swap(int a,int b){
int t = a;
a = b;
b = t;
cout<<"address in swap: &a = "<<&a<<" &b = "<<&b<<endl;
}

运行结果

address in main: &a = 0x22fedc &b = 0x22fed8
address in swap: &a = 0x22fec0 &b = 0x22fec4

看来确实是这样的。。。

那么要是swap和main函数中a,b两变量的内存地址相等,可以用指针来完成

 #include<iostream>
#include<stdlib.h>
using namespace std;
void swap(int*,int*);
int main(){
int a = ;
int b = ;
cout<<"address in main: &a = "<<&a<<" &b = "<<&b<<endl;
swap(&a,&b);
cout<<a<<" "<<b;
return ;
}
void swap(int* a,int* b){
int t = *a;
*a = *b;
*b = t;
cout<<"address in swap: &a = "<<a<<" &b = "<<b<<endl;
}

运行结果

address in main: &a = 0x22fedc &b = 0x22fed8
address in swap: &a = 0x22fedc &b = 0x22fed8

(注:如果读者知道,其实还有一种代码写起来可读性比指针高,错误率比指针低的方式,就是用引用&)

2.提高运行速度

  随便打了篇代码来做实验,第一个seta函数是不用指针给结构体中的数据赋值,第二个setb函数时用指针给

结构体中的数据赋值

 

 #include<iostream>
#include<ctime>
using namespace std;
struct a{
int a[];
int len;
}c;
a seta(a b,int index,int val){
b.a[index] = val;
return b;
}
a setb(a *b,int index, int val){
b->a[index] = val;
return *b;
}
int main(){
clock_t begin = clock();
for(int i = ;i < ;i++)
c = seta(c, i, i);
clock_t end = clock(); clock_t begin1 = clock();
for(int i = ;i < ;i++)
c = setb(&c, i, i);
clock_t end1 = clock(); cout<<"非指针:"<<(end - begin)<<"ms"<<endl;
cout<<"指针 :"<<(end1 - begin1)<<"ms"<<endl;
return ;
}

运行结果(鉴于我家渣机外加开了很多程序所以运行地很慢):

非指针:1781ms
指针 :672ms

有木有发现什么明显的差距,稍微微调一下,把setb函数改成:

void setb(a *b,int index, int val){
b->a[index] = val;
}

然后编译运行,神奇的事发生了:

非指针:1078ms
指针 :0ms

是不是很神奇?

想知道这是为什么吗?

  因为在结构体传递的时候是值传递,又因为数组很大,所以要拷贝过来,赋值的

时候也是需要拷贝,所以非常消耗时间,而指针是地址传递,相当于是一个要复制

一个数组,而另一个却只用复制4字节的数据就完成了一样的事

  其实还可以比较一下,指针和引用的时间消耗:

 #include<iostream>
#include<ctime>
using namespace std;
struct a{
int a[];
int len;
}c;
void seta(a& b,int index,int val){
b.a[index] = val;
}
void setb(a *b,int index, int val){
b->a[index] = val;
}
int main(){
clock_t begin = clock();
for(int i = ;i < ;i++)
seta(c, i, i);
clock_t end = clock(); clock_t begin1 = clock();
for(int i = ;i < ;i++)
setb(&c, i, i);
clock_t end1 = clock(); cout<<"引用:"<<(end - begin)<<"ms"<<endl;
cout<<"指针:"<<(end1 - begin1)<<"ms"<<endl;
return ;
}

  结果可以多运行几次,不行可以加大数据,指针和引用貌似时间消耗差不多,不过引用写起来是要

比指针简单一些,像这样也就最多有10ms

3.用于各种数据结构

  例如各种树结构,链表等

4.给指定内存存储的数据赋值(在开发操作系统时,这貌似是允许的)

5.通过new、malloc等来省内存


[常见错误]

1.空内存地址

  当一个指针的值等于 0x00(NULL,windef.h下定义)时,这必定是一个空内存,如果用到了访问*,程序直接崩溃,访问无效内存

还有就是与其它程序或者系统的专用内存段等冲突,也会导致程序崩溃,这就是因为即使有时候数组下标超了一点点时也可能不会崩溃

的原因

2.访问用过delete或free()后的指针

3.滥用指针,导致浪费内存

另外指针经常也很难看懂,比如,你能一样告诉我这是什么类型的指针吗?(下)

typedef char*const(*p)(long long);

总之指针还得多使用,能用熟最好,不然最好不用,用引用去代替它,

如果到什么开发什么程序的时候,程序崩溃了,都不知道为什么,那

可就糟了

[c/c++]指针(4)的更多相关文章

  1. TODO:Golang指针使用注意事项

    TODO:Golang指针使用注意事项 先来看简单的例子1: 输出: 1 1 例子2: 输出: 1 3 例子1是使用值传递,Add方法不会做任何改变:例子2是使用指针传递,会改变地址,从而改变地址. ...

  2. enote笔记法使用范例(2)——指针(1)智能指针

    要知道什么是智能指针,首先了解什么称为 “资源分配即初始化” what RAII:RAII—Resource Acquisition Is Initialization,即“资源分配即初始化” 在&l ...

  3. C++虚函数和函数指针一起使用

    C++虚函数和函数指针一起使用,写起来有点麻烦. 下面贴出一份示例代码,可作参考.(需要支持C++11编译) #include <stdio.h> #include <list> ...

  4. C++11 shared_ptr 智能指针 的使用,避免内存泄露

    多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用, 在没有shared_ptr时,因为线程A,B结束时间不确定,即在A或B线程先释放这个对象都有可能造成另一个线程崩溃, 所以为 ...

  5. c 数组与指针的使用注意事项

    数组变量和指针变量有一点小小的区别 所以把数组指针赋值给指针变量的时候千万要小心 加入把数组赋值给指针变量,指针变量只会包含数组的地址信息 而对数组的长度一无所知 相当于指针丢失了一部分信息,我们把这 ...

  6. Marshal.Copy将指针拷贝给数组

    lpStatuss是一个UNITSTATUS*的指针类型实例,并包含SensorDust字段 //定义一个数组类型 byte[] SensorDust = new byte[30] //将指针类型拷贝 ...

  7. C++智能指针

    引用计数技术及智能指针的简单实现 基础对象类 class Point { public: Point(int xVal = 0, int yVal = 0) : x(xVal), y(yVal) { ...

  8. EC笔记:第三部分:17、使用独立的语句将newed对象放入智能指针

    一般的智能指针都是通过一个普通指针来初始化,所以很容易写出以下的代码: #include <iostream> using namespace std; int func1(){ //返回 ...

  9. 智能指针shared_ptr的用法

    为了解决C++内存泄漏的问题,C++11引入了智能指针(Smart Pointer). 智能指针的原理是,接受一个申请好的内存地址,构造一个保存在栈上的智能指针对象,当程序退出栈的作用域范围后,由于栈 ...

  10. 智能指针unique_ptr的用法

    unique_ptr是独占型的智能指针,它不允许其他的智能指针共享其内部的指针,不允许通过赋值将一个unique_ptr赋值给另一个unique_ptr,如下面错误用法: std::unique_pt ...

随机推荐

  1. cordova-ios 升级到4.4.0 无法真机跑iOS8 报错: dyld`dyld_fatal_error: -> 0x120085088 <+0>: brk #0x3

    项目进入测试阶段,马上要上线了,同事拿了自己的iOS8系统5s跑真机,无缘无故报错,之前跑她的手机完全没有问题的.Xcode 8.x中最低部署版本是iOS8.0,按理说完全能够跑真机的. 但是报了一个 ...

  2. hive-site.xml配置

    <?xml version="1.0" encoding="UTF-8" standalone="no"?><?xml-s ...

  3. git clone远程branch和tag

    1.查看远程分支 git branch -r 2.测试git clone romete,只是clone远程remote的master,不会clone其他的目录 -------------------- ...

  4. 获取图片的大小(宽高):BytesIO

    获取图片的大小(宽高) from io import BytesIO,StringIO import requests from PIL import Image img_url = "ht ...

  5. Mirror--如何在主库上增加文件

    由于各种原因,如磁盘不空不足,需要对主库增加数据库文件到其他磁盘上,而镜像服务器上没有对应盘符,很多人会选择删除镜像,重新完备还原来搭建镜像,这种方式耗时耗力. 在做此类操作时,需要对主服务器和镜像服 ...

  6. 9 jmeter之检查点

    jmeter有类似loadrunner检查点的功能,就是断言中的响应断言. 1.响应断言(对返回文字结果进行相应的匹配)右击请求-->添加-->断言-->响应断言-->添加“要 ...

  7. ASP.NET一个页面的生命周期

    在学习ASP.NET页面生命周期前,需要先了解之前的ASP.NET的基本运行机制,在理解ASP.NET基本运行机制原理后,下面将介绍ASP.NET的生命周期中,页面从创建到处理结束的过程中ASP.NE ...

  8. Spark2.x学习笔记:Spark SQL的SQL

    Spark SQL所支持的SQL语法 select [distinct] [column names]|[wildcard] from tableName [join clause tableName ...

  9. Kylin安装部署

    一.安装准备 1.操作系统 Centos 7.x 2.时间问题 集群内所有节点时间一定要同步. NTP.Chrony 3.用户 创建hadoop组和hadoop用户,并做ssh免密码登录 4.Hado ...

  10. Linear Regression Using Least Squares Method 代码实现

    1. 原理 2. Octave function theta = leastSquaresMethod(X, y) theta = pinv(X' * X) * X' * y; 3. Python # ...