指针

来源:互联网 发布:php 序列化 编辑:程序博客网 时间:2024/06/09 16:39
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)
}




原创粉丝点击