1.指针类型:
整型指针和整型是不同的类型,不可以直接相互赋值,但是可以相互强制转换,需要注意转换的意义。如:
int icount = 18;
int *iptr = &icount; //定义指针
*iptr = &icount; //error:左边为整型,右边为整型地址,不可以转换
*iptr = 58;
*iptr = (int) &icount; //right:可以强制转换
32位机器上,整型和指针都是占用4个字节,内存表示都是二进制整型,但是就如上面说的,它们的类型不一样。
2.指针初始化:
指针在 声明的时候最好 先初始化,否则是很危险的。
如:
int icount=18;
int *iptr; //指针没有初始化,这里把18随意地赋值给内存 随机位置,可能会改写另一存储位置的数值,危险!!!
*iptr=icount;
3.指针运算:
指针可以进行加减的运算,指针的加减与指针的类型有关。
如:都是在32位机器上,整型占4位,char占1位,double占16位。
int icount1=0;
int *iptr1=&icount1;
iptr1++;
| iptr1++表示地址加了4 0x00000000--->0x00000004 |
char icount2=1;
char *iptr2=&icount2;
*iptr2++;
|
iptr2++表示地址加了1 0x00000000--->0x00000001 |
double icount3=2;
double *iptr3 =&icount3;
*iptr3++;
|
iptr1++表示地址加了16 0x00000000--->0x00000010 |
4.指针和数组:
数组名是一个地址,可以用来初始化指针。
int a[10];
int *iptr=a;
第i个元素表示:a[i], *(a+i), iptr[i], *(iptr+i)
第i个元素地址:&a[i], a+i, &iptr[i], iptr+i
同时数组名是指针常量,区别于指针变量,所以不可以进行运算。
如:
a++; //error:数组名是指针常量,不做左值。
但如果数组作为参数传递过去,可以当指针用,这时候就可以作为左值
。
例如:
#include <iostream> using namespace std; void main(){ int array[10]={1,2,3,4,5,6,7,8,9,10}; sum(array,10); } void sum(int array[],int n){ //数组array作为参数传递过去,可以作为指针,等价于void sum(int * array,int n) 或者void sum(int* array[],int n) int sum=0; //为什么要给出数组的大小n呢??因为传递过来的是一个指针array,而不是数组array 那么占用的空间只是指针的大小,而不是数组的空间那么大,不能用sizeof(array)/sizeof(int)来求得数组元素个数n, 所以传递参数的时候,传过来的是指针和数组的大小(即元素个数n),仅仅传过来数组的指针是不可以的。 for(int i=0;i<n;i++){ sum+=*array; array++; //由于array为指针,可以作为左值,那么可以进行运算 } cout << sum<< endl; } |
5.指针常量和常量指针:
常量指针:指向常量的指针
const int icount1=0;
const int *iptr1=&icount1; //在前面加上const是说指向的对象是常量,那么它是常量指针
icount1=1; //error: 常量icount不可赋值
*iptr1=2; //error: 常量指针iptr1是指向常量的,同样不可以赋值
指针常量:指针是常量
int icount2=0;
int* const iptr2=&icount2;
icount2=1; //right: icount2不是常量,可以赋值
*iptr2=2; //right: 这里指针常量iptr2指向的不是常量,可以赋值
iptr2=0x00000000; //error: 指针常量iptr2是常量,其本身不可以被赋值。
6.字符指针:
字符串可分为两种,一种是相当于常量的字符串,另一种是字符数组。
char *iptr="hello";
|
// 相当于常量的字符串,不可以再赋值,如再有iptr="hi"; error
| 存放在const区域 |
char buffer[10]="Hello";
|
// 字符数组 拥有一定的地址空间
| 若为全局变量,则放在data区的全局区 若为局部变量,则放在stack区 |
由于每一个字符串都有自己的地址,那么相同的两个字符串是不可以“==”的。
同样,也不可以用字符串直接给另一个字符串赋值,而是应该用strcpy()函数,其原型为
char* strcpy(char* dest,const char* src)。
例如:
char * str1="hello";
char * str2="hello";
if(str1==str2)
cout << "equal." << endl;
else
cout << "not equal." << endl;
print: not equal.
|
再者:
str1=str2; // error,因为不可以直接赋值
strcpy(str1,str2); //right
|
总结:
字符串比较----strcmp()
原型: int strcmp(char* dest, const char* src ),相等返回0,(前者大于后者)大于返回正值,小于返回负值。
字符串赋值----strcpy()
原型:char* strcpy(char* dest, const char* src)
附加:还有可以使用函数memcpy()
原型:char* memcpy(char* dest, const char* src,size_t n),可以确切地赋值多少个字符
|
7.字符指针的输出:
字符指针存的是字符串的首地址。
输出字符指针
-----即是
输出整个字符串
输出字符指针的引用
-----即是
输出某一个字符
|
例如:
char *pc="hello" ;
cout<< pc<< endl; // 输出hello
cout<<*pc<<endl; //输出h
char buffer[] ="ABC";
pc=buffer;
cout << pc<<endl; //输出ABC
pc++;
cout<<*pc<<endl; //输出B
|
指针数组,二维数组,二级指针
char * pc[]={"hello","hi"};
char ** ppc=pc; // ppc为二级指针
|
8.指针函数与函数指针:
指针函数:返回指针的函数。
函数指针:指向函数地址的指针。
指针函数声明 | 函数指针声明 |
int* fn(char* a,char* b) | int (*fn)(char* a, char* b) |
差别:函数指针多一个括号 |
注意1:指针函数返回的指针不能为函数内部的局部变量,否则很容易出错。
例如:
int* fn(){ int icount=10; return &icount; } |
解释:最好不要这样用,因为icount是函数内部局部变量,返回它的地址到调用它的函数不可取,可能会被下次的调用所覆盖。 |
int *geyInt(char* str){ int value=20 cout<< str<< endl; return &value; } int somefn(char* str){ int a=40; cout<< str<<endl; } int main(){ int *iptr=getInt("input a value."); //这里要注意,还因为getInt()结束的时候,栈中的变量value也会消失 因为它是函数内部的局部变量,第一次输出*pr的时候,指向20的地址所以输出20, 但是第二次输出*pr的时候,由于栈的该地址的内容已经被覆盖,那么输出的是一个 意料之外的i结果。 cout<<*pr<<endl; somefn("after somefn:"); cout<<*pr<<endl; } print: input a value. 20 after somefn: 4435500 |
注意2:函数指针赋值的时候要注意类型的匹配。
例如:
函数:
int fn1(char* a,char* b);
int* fn2(char* a,char* b);
int fn3(int a);
|
函数指针:
int (*fp1) (char* a,char*b);
int (*fp2)(int a);
|
判断:
fp1=fn1; // right,参数一致,返回类型都是int整型
fp2=fn2; // error 参数不一致,不可为函数指针赋值。
fp1=fn2; // error 参数一致,但是返回类型不一致,fn2返回类型为int*整型指针,fp1的返回类型是int整型
fp2=fn3; // right 参数一致,返回类型都是int整型
|
9.函数指针可以作为参数传递。
例如:排序一个字符串数组,比较函数用的是compare();
#include <iostream> #include <string> #include <stdlib> using namespace std; int compare(const void* a, void* b); char list[5][4]={"cat","car","cab","cap","can"}; void main(){ qsort((void*) list,5,sizeof(list[0]),compare); for(int i=0;i<5,i++){ cout<<list[i]<<endl; } } int compare(const void*a, const void* b){ return strcmp((char* *)a,(char* *) b); } print: cab can cap car cat | qsort()的原型是:void qsort(void*, size_t nelem,size_t width, int(*fcmp)(const void *, const void*)) 这里qsort的第四个参数是函数指针,也就是说传递过去的是一个指向函数地址的指针。 在左边的例子中,实际参数为compare指针。 |
10.函数指针可以构成指针数组。
typedef void (*menuFun);
void fn1(){cout<<"11111"<<endl;};
void fn2(){cout<<"22222"<<endl;};
void fn3(){cout<<"33333"<<endl;};
menuFun fn[]={fn1,fn2,fn3};
void main(){
int choice;
do{
cout<<"1 stand for 11111"<<endl;
cout<<"2 stand for 22222"<<endl;
cout<<"3 stand for 33333"<<endl;
cin>>choice;
switch(choice){
case 1:
fn[0]();
break;
case 1:
fn[1]();
break;
case 1:
fn[3]();
break;
default:
cout<< "you enter a wrong key." <<endl;
}while(choice)
}
|