C++学习笔记(四)--指针
1.指针(变量的地址):
指针变量:存放指针(地址)的变量
直接存取(访问):按变量地址取值
间接存取(访问):将变量的地址放入指针变量中
定义指针变量:基类型 *指针变量名
2.与指针有关的运算符:
&:取地址运算符
*:指针运算符(间接访问运算符);
int *pointer_1,*pointer_2;
int a = 1, b = 2;
pointer_1 = &a;
pointer_2 = &b;
pointer_2 = &*pointer_1;//*,&优先级一样,自右至左结合,所以是先取a的值,再取a的地址&a给指针变量pointer_2
若有*&a,表示的是先取a的地址,再取a的值。
3.谨记:函数传参:实参->形参 之间的数据是单向传递的“值传递方式”,指针变量也遵守这一原则,调用函数时,不会改变实参指
针变量的值,但可以改变实参指针变量所指向的值。所以可以利用指针来改变主调函数中多个变量的值,不用指针变量来实现这个是
很难实现这一点的。
4.数组元素的指针就是数组元素的地址
int a[10];
int *pointer;
pointer = a[0];与pointer = a; 等价都表示数组的第一个元素的地址。
如果初始:pointer = a; 以下都为此前提,那么:
pointer+1 = a+1 = a[1] //实际地址看类型,pointer+1*n 或者 a+1*n 或者&a[1]
所以有pointer+i = a+i = a[i] pointer+i*n a+i*n &a[i] 例:int型n=4;
所以可以看出[]是变址运算符,对a[i]的处理是这样的:先按a+i*n计算数组元素的地址,然后由此地址找出所指向的单元的
值
指向数组元素的指针变量也可以带下标,如:pointer[i]与*(pointer+i)等价。
所以引用数组元素有两种方法:
a.下标法:a[i];
b.指针法:*(a+i)或者*(pointer+i);使用这种方法能使目标程序质量高(占运行内存小,运行速度快)
·注意:指针变量可以指向有效的数组元素,也可以指向数组以后的内存单元。例:
int a[10], *p = a;
cout <<*(p+10);//编译不会提示出错。
5.如果先使p=a,即p指向数组a的首元素:
(1).p++(或p+=1):使p指向下一元素,即a[1],如果用*p,则得到a[1]的值;
(2).*p++: ++与*优先级相同,右结合,相当于*(p++),所以是先取*p的值,再使p++。
例如:
for(p=a;p<a+10;p++)
cout <<*p ; //可改写为:
for(p=a;p<a+10; )
cout <<*p++;
(3).*(p++):先取*p值,p再加1
*(++p):先p加1,再取*p值,二者区别仅在于p++ 与 ++p 的含义。
(4).(*p)++:先取*p的值,再使取得的值加1.
(5).如果p当前指向a[i]:
*(p--): 先取*p的值,即a[i],再使指针变量p指向a[i-1];
*(++p): 先使指针变量自增1,指向a[i+1],再取*p的值a[i+1];
*(--p): 先使指针变量自减1,指向a[i-1],再取*p的值a[i-1];
6.使用指针变量作函数参数接收数组地址
因为数组作形参时接收的也是实参数组的首地址,所以可以用指针变量来接收以数组为实参的参数,例如:
void select(int array[]);//实际上可以表示为
void select(int *array );/*编译器实际上是将数组名作为指针变量来处理的。所以实际上,在函数调用时并不存在一个
占有存储空间的形参数组,只有指针变量。*/
7.多维数组与指针:
int arr[3][4];假设arr起始为2000
(1)C++中规定了数组名作为首地址,所以
arr[0]是arr[0][0]的首地址,arr[1]是arr[1][0]的首地址即&arr[1][0],
arr[0]+1,表示arr[0][1]的地址,arr[0]+2表示的是arr[0][2]的地址;
*(arr[0]+2) 表示a[0][2]的值。所以有
arr[i]+j 表示&arr[i][j],
*(arr[i]+j) 表示arr[i][j]的值。
(2)arr,表示首行地址&arr[0],则a+1表示第二行起始地址&arr[1],其值为2000+4*4=2016;
arr[1]+1: 表示 &arr[1][1],所以有
arr[i]+j: 表示 &arr[i][j],
*(arr[i]+j):表示 arr[i][j]的值,因为arr[i] = *(arr+i);所以
*(*(arr+i)+j): 也表示arr[i][j]的值。
(3)指向数组元素的指针变量:
#include<iostream>
using namespace std;
int main(){
int array[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
int *p;
p = array[0];//注意此处是array[0],而不是array,要符合指针类型。
cout <<"--------------" <<endl;
for( p; p<array[0]+12;p++ )
cout <<*p<< ' ';
cout <<endl;
cout <<"--------------" <<endl;
return 0;
}
(4)指针变量指向由m个元素构成的一维数组
#include<iostream>
using namespace std;
int main(){
int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
int (*p)[4],i,j;/*(*p)[4]是一个指针变量,它指向包含4个整型元素的一维数组,()不可丢,
否则变成*p[4],[]优先级高,变成了指针数组
*/
p = a;//p指向a[0];
cout <<"please input i,j:";
while(1){
cin >>i >>j;
if( i>=3||j>=4 )
cout <<"warning:i must less then 3,j must less then 4,please try a again:" <<endl;
else break;
}
cout <<"---------------------" <<endl;
cout <<*(*(p+i)+j);
cout <<endl <<"---------------------" <<endl;
return 0;
}
8.指向数组的指针作函数参数(一维数组名,多维数组名也可,之前有讲过)
#include<iostream>
using namespace std;
int main(){
void output(int (*p)[4]);
int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
output(a);//a指向a[0]
return 0;
}
void output(int (*p)[4]){//注意形参声明为指向一维数组的指针变量,而不是int型指针变量
int i,j;
for( i=0;i<3;i++ )
for( j=0;j<4;j++ )
cout <<*(*(p+i)+j) <<" ";
cout <<endl;
}
9.字符指针(C++中共3种方法访问一个字符串,之前已经学习过两种)
(1)用字符指针指向一个字符串
#include<iostream>
using namespace std;
int main(){
char *str = "I love China!";//对字符指针变量str的初始化其实是把字符串第一个元素的 地址 赋给str
//等价于 char *str; str = "I love China"; 输出时,系统先输出str指向的第一个字符数据,
//然后str+1,使之指向下一个字符,然后输出......直至遇到'\0'为止,在内存中,字符串的末尾
//被自动加了一个'\0'
cout <<str<<endl;
return 0;
}
(2)利用字符指针实现对字符串的存取
#include<iostream>
using namespace std;
int main(){
char str1[] = "I love liu_xiao_min",str2[20];
char *p1,*p2;
p1 = str1;
p2 = str2;
for( ;*p1!='\0';p1++,p2++ )
*p2 = *p1;//其实string str1 = "I love liu_xiao_min",str2;str2 = str1;最简单快捷
*p2 = '\0';
p1 = str1;
p2 = str2;
cout <<p1 <<endl;
cout <<p2 <<endl;
return 0;
}
10.函数与指针
(1)用函数指针变量调用函数(原理:一个函数被编译时被分配一个入口地址。这个函数入口地址就称为函数的指针)
函数指针定义:
函数类型 (*指针变量名)(函数形参表);
例:
#include<iostream>
using namespace std;
int main(){
int max( int x, int y );
int (*p)( int, int );//(*p)括号不能漏
int a,b,n;
p = max; //函数名代表函数入口地址
cin >>a >>b;
m = p( a,b );
cout <<"max=" <<m<<endl;
return 0;
}
int max( int x, int y ){
int z;
if( x>y )
z = x;
else
z = y;
return z;
}
(2)用指向函数的指针作函数参数
类似:float intern(float a, float b, float (*fun)(float));
11.指针函数(函数返回值为指针的函数)
指针函数定义:
函数类型 *函数名(参数表列);
例:
#include<iostream>
using namespace std;
int main(){
int *a(int a);
int i = 10;
cout <<a( 10 ) <<endl;
return 0;
}
int *a( int a ){
return &a;
}
12.指针数组(一个数组,其元素全部为指针类型数据)
一维指针数组:
类型名 *数组名[数组长度];
例:int *a[3]; //注意与int (*a)[3];的区别,后者是指向含有3个整型元素的一维数组的指针变量
#include<iostream>
#include<cstring>
using namespace std;
int main(){
void sort( char *name[], int n );//指针数组做函数参数
void print( char *name[], int n );
char *name[] = { "BASIC","FORTRAN","C++","Pascal","COBOL" };//指针数组
int n = 5;
sort( name,n );
print( name,n );
return 0;
}
void sort( char *name[], int n ){ //选择法排序
char *temp;
int i,j,k;
for( i=0;i<n-1;i++ ){
k = i;
for( j=i+1;j<n;j++ ){
if( strcmp( name[k],name[j] )>0 )//name[x]中存放各个字符串的首地址
k = j;
}
if( k!=i ){
temp = name[i];name[i] = name[k];name[k] = temp;
}
}
}
void print( char *name[] , int n ){
int i;
for( i=0;i<n;i++ )
cout <<name[i] <<endl;
}
输出:
BASIC
C++
COBOL
FORTRAN
Pascal
13.指向指针的指针(指向 指针数据 的指针)
如12所述,数组name[x]是一个指针数组,此时设一个指针变量p,它指向指针数组元素的元素,则p就是指向指针型数据的指
针变量。
定义一个指向指针数据的指针:
char *(*p);//可以写成 char **p;
分析:
char *p:表示指向字符型数据的指针变量(即字符指针变量)。
char *(*p):表示p指向的是字符指针数据
例:
#include<iostream>
using namespace std;
int main(){
char **p;//定义指向 字符指针数据 的指针变量p
char *name[] = { "BASIC","FORTRAN","C++","Pascal","COBOL" };
p = name + 2; //指向name[2]
cout <<*p <<endl;//输出name[2]中指针指向的字符串的值
cout <<**p <<endl;//输出name[2]指向的字符串中的第一个字符
return 0;
}
输出:
C++
C
分析:
由于*p代表name[2],它指向字符串"C++",即在name[2]中存放了字符串"C++"的第一个字符串的地址,因此"cout <<*p <<endl;"就
是从第一个字符开始输出字符串"C++"。第二个cout中的**p是*p(值为name[2])指向的"C++"第一个字符元素的内容,即字符"C",所以
第二个cout语句输出"C".
C++学习笔记(四)--指针的更多相关文章
- Go语言学习笔记四: 运算符
Go语言学习笔记四: 运算符 这章知识好无聊呀,本来想跨过去,但没准有初学者要学,还是写写吧. 运算符种类 与你预期的一样,Go的特点就是啥都有,爱用哪个用哪个,所以市面上的运算符基本都有. 算术运算 ...
- C#可扩展编程之MEF学习笔记(四):见证奇迹的时刻
前面三篇讲了MEF的基础和基本到导入导出方法,下面就是见证MEF真正魅力所在的时刻.如果没有看过前面的文章,请到我的博客首页查看. 前面我们都是在一个项目中写了一个类来测试的,但实际开发中,我们往往要 ...
- IOS学习笔记(四)之UITextField和UITextView控件学习
IOS学习笔记(四)之UITextField和UITextView控件学习(博客地址:http://blog.csdn.net/developer_jiangqq) Author:hmjiangqq ...
- java之jvm学习笔记四(安全管理器)
java之jvm学习笔记四(安全管理器) 前面已经简述了java的安全模型的两个组成部分(类装载器,class文件校验器),接下来学习的是java安全模型的另外一个重要组成部分安全管理器. 安全管理器 ...
- Learning ROS for Robotics Programming Second Edition学习笔记(四) indigo devices
中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...
- Typescript 学习笔记四:回忆ES5 中的类
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- ES6学习笔记<四> default、rest、Multi-line Strings
default 参数默认值 在实际开发 有时需要给一些参数默认值. 在ES6之前一般都这么处理参数默认值 function add(val_1,val_2){ val_1 = val_1 || 10; ...
- muduo网络库学习笔记(四) 通过eventfd实现的事件通知机制
目录 muduo网络库学习笔记(四) 通过eventfd实现的事件通知机制 eventfd的使用 eventfd系统函数 使用示例 EventLoop对eventfd的封装 工作时序 runInLoo ...
- python3.4学习笔记(四) 3.x和2.x的区别,持续更新
python3.4学习笔记(四) 3.x和2.x的区别 在2.x中:print html,3.x中必须改成:print(html) import urllib2ImportError: No modu ...
- 零拷贝详解 Java NIO学习笔记四(零拷贝详解)
转 https://blog.csdn.net/u013096088/article/details/79122671 Java NIO学习笔记四(零拷贝详解) 2018年01月21日 20:20:5 ...
随机推荐
- Elasticsearch7.X 入门学习第一课笔记----基本概念
原文:Elasticsearch7.X 入门学习第一课笔记----基本概念 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https: ...
- java 进销存管理 商户管理 库存管理 springmvc SSM 项目源码
统介绍: 1.系统采用主流的 SSM 框架 jsp JSTL bootstrap html5 (PC浏览器使用) 2.springmvc +spring4.3.7+ mybaits3.3 SSM 普 ...
- em、rpx和px的换算
rpx:对于小程序开发,所用的单位都是rpx,而不论哪个型号的手机,屏幕宽度都是750rpxrpx与px的转换,根据设计稿换算例如:设计稿750px宽度,ps上量出或者标出的宽度是多少,那么就定义多少 ...
- localeCompare按首字母排序汉字
sort() 方法用于对数组的元素进行排序. 如果想按照其他标准进行排序,就需要提供比较函数,该函数要比较两个值,然后返回一个用于说明这两个值的相对顺序的数字.比较函数应该具有两个参数 a 和 b,其 ...
- ShellExecute指定IE浏览器打开
ShellExecute(NULL,L"open", L"iexplore.exe", L"www.baidu.com", NULL, SW ...
- 随笔3 HashMap<K,V>
equals.hashcode和==的区别 在介绍HashMap之前,我想先阐述一下我对这三者的理解,equals这个方法呢,就是在判断是否为同一对象(注意,这里的同一对象和相同的内存地址是不同的), ...
- alert(1) to win 9
function escape(s) { function htmlEscape(s) { return s.replace(/./g, function(x) { return { '<': ...
- 开发zeroc ice应用入门(java开发ice应用,python开发ice应用,java与python结合开发ice服务)
ice作为一种rpc框架,为主流平台设计,包括Windows和Linux,支持广泛的语言,包括C++,Java,C#(和其他.Net的语言,例如Visual Basic),Python,Ruby,PH ...
- nginx proxy大文件上传失败问题总结
问题描述: http://www.syhuo.net ota.apk包上传正常 http://www.syhuo.net:8080 ota.apk包上传不正常 查看nginx error日志 [roo ...
- Windows无法启动MapGIS DataStorage Service服务
但是启动又启动不了,查看属性 发现计算机服务器确实少了该文件目录.. 可能是不小心删除了? 之前确实有删过一些文件 下次直接把.net禁止就可以了,不用删除,不然不小心删除了其它服务.. 参考文献:h ...