一、指针的基本概念
定义:
类型名 * 指针变量名
int * p //p是一个指针,变量p的类型是int *
char * pc; //pc是一个指针,变量pc的类型是char *
float *pf ;//pf是一个指针,变量pf的类型是float *
内容:
int * p = ( int * ) 40000
p内容:40000
p指向地址40000,地址p就是地址40000
通过指针访问其指向的内存空间
int * p=(int *)40000
//向地址40000处起始的若干个字节的内存空间里写入5000;
*p=5000;
//将地址40000处起始的若干字节的内容赋值给n
int n= *p;
用法
char ch1='a';
char * pc = &ch1; //是的pc指向变量ch1
* p=‘b'; //使得ch1='b';
char ch2 =* pc //使得ch2=ch1
pc=&ch2; //使得pc指向ch2
* pc ='d';//使得pc等于d
&:取地址运算发
&x:变量x的地址
指针的作用:有了指针,就有了自由访问内存空间的手段
1)不需要通过变量,就能对内存直接进行操作。通过指针,程序能访问的内存区域就不仅限于变量所占据的数据区域
2)在C++中,用指针p指向a的地址,然后对p进行加减操作,p就能指向a后面或前面的内存区域,通过p也就能访问这些内存区域。
写非常底层的程序,需要用到指针。
指针的互相赋值
不同类型的指针,如果不经过强制类型转换,不能直接互相赋值
int * pn, char * pc,char c = 0x65;
pn=pc; //类型不匹配,编译出错
pn=& c; //类型不匹配,编译出错
指针的运算
1)两个同类型的指针变量,可以比较大小
2)两个同类型的指针变量,可以相减
两个T * 类型的指针 p1和p2
p1-p2=(地址p1-地址p2)/sizeof(T) 表示的是p1和p2之间可以存放多少个T的变量
空指针
*地址0不能访问。指向地址0的指针就是空指针
可以用“NULL"关键字对任何类型的指针进行赋值。NULL实际上就是整数0,值为NULL的指针就是空指针:
int * pn =NULL;char * pc=NULL;int * p2 =0;
pn、pc、p2都是空指针,都是指向地址0的指针
指针作为函数的参数使用
//交换两个整型变量的值
#include<iostream>
using namespace std;
void swap( int *p1,int * p2){
int tmp =*p1;
*p1=*p2;
*p2=tmp;
}
int main(){
int m=3,n=4;
swap($m,$n); //使得p1指向m,p2指向n
cout<<m<<" "<<n<<endl; //输出4 3
return 0;
}
数组的名字就是一个指针常量,指向数组的起始地址
颠倒数组
指针和二维数组
定义二维数组 :T a[M][N]
a[i]的地址:a[0]的地址+i*N*sizeof(T)
#include <iostream>
using namespace std;
//颠倒元素
void Reverse(int * p,int size){
for (int i=0;i<size/2;++i){
int tmp=p[i];
p[i]=p[size-1-i];
p[size-1-i]=tmp;
}
}
int main()
{
int a[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};
Reverse(a[1],4);//{{1,2,3,4},{8,7,6,5},{9,10,11,12}}
Reverse(a[1],6);//{{1,2,3,4},{10,9,8,7},{6,5,11,12}}
return 0;
}
指向指针的指针
定义 :T * * p,此时p是指向指针的指针
#include <iostream>
using namespace std;
int main()
{
int **pp;//指向int *类型的指针
int *p;
int n=1234;
p=&n; //p指向n
pp=&p; //pp指向p
cout<<*(*pp)<<endl; //*pp=p ,*p=n=1234
return 0;
}
指针和字符串
1)字符串常量的类型也是char *
2)字符数组名的类型也是char *
#include <iostream>
using namespace std;
int main()
{
char *p="please input your name:\n";
printf(p) ;
char name[20];
char * pname=name;
cin >> pname;
cout << "your name is "<<pname;
return 0;
}
//字符串数组名的类型也是char *,就是一个地址
char name[20];
int n;
scanf("%d %s",&n,name);
cin >> n >> name;
char * itoa(int value,char * string,int radix):将整型值value以radix进制表示法写入string
char szvalue[20];
itoa(27,szvalue,10);//使得szvalue的内容为“27”
itoa(27,szvalue,16);//使得szvalue的内容为“1b"
#include <iostream>
using namespace std;
#include <cstring>
int main()
{
char s1[100]="12345";
char s2[100]="abcdefg";
char s3[100]="ABCED";
strncat(s1,s2,3);//将s2的前3个字符加到s1后面
cout<<"1) "<<s1<<endl;//输出:1) 12345abc
strncpy(s1,s3,3);//将s3的前3个字符拷贝到s1
cout<<"2) "<< s1<<endl;//输出:2)ABC45abc
strncpy(s2,s3,6);
cout<<"3) "<<s2<<endl;//输出:3)ABCDE
char * p=strchr(s1,'B');//在s1中找到B第一次出现的位置;
if (p)
cout<<"4) "<< p-s1<<","<<*p<<endl;//1
else
cout<<"4) not found"<<endl;
return 0;
}
#include <iostream>
using namespace std;
#include <cstring>
int main()
{
//以下演示strtok的用法,用特定的符号(如空格,逗号等等)分隔出子串
char str[]="- This,a sample string,OK.";
char *p;
p=strtok(str," ,.-");
while(p !=NULL){
cout<< p << endl;
p=strtok(NULL," ,.-"); //后续调用,第一个参数必须是NULL
}
return 0;
}
注意:后续调用,第一个参数必须是NULL
void 指针——void * p;
可以用任何类型的指针对void指针进行赋值或初始化
double d=1.54;
void * p=& d;
void * p1;
p1= & d;
void * memset (void * dest,int ch,int n);
将从dest开始的前n个字节,都设置成ch,返回值为dest
将szname的前10个字符,都设置成”a"
char szname[200]="";
memset(szname,'a',10);
cout<<szname<<endl;
==》aaaaaaaaaa
用memset函数将数组内容全部设置为0;
int a[100];
memset(a,0,sizeof(a));
//则数组a的每个元素变成0
函数指针:
定义形式:类型名(*指针变量名)(参数类型1,参数类型2)
int (*pf)(int,char);
实例:调用qsort库函数,将一个unsigned int 数组按照个位数从小到大进行排序。比如8,23,15三个数,按个位数从小到大排序,就应该是23,15,8。
#include <iostream>
using namespace std;
#include <cstring>
#include <stdlib.h> //引入qsort快排,必须要加该头文件
#define num 5
int Mycompare(const void *elem1,const void * elem2){
unsigned int *p1,*p2;
p1=(unsigned int *)elem1;
p2=(unsigned int *)elem2;
return (*p1%10)-(*p2%10);
}
int main()
{
unsigned int a[num]={8,123,11,10,4};
qsort(a,num,sizeof(unsigned int),Mycompare);
for (int i=0;i<num;i++){
printf("%d ",a[i]);
}
return 0;
}