数组,指针和引用

一,指针

1,指针的类型

  指针的类型和指针所指向的类型

 
指针的类型
指针所指向的类型
sizeof(*ptr) 说明
int *ptr; 
int *
int 
4
 
int **ptr;
int **
int * 
4
 
int (*ptr)[3];
int(*)[3] 
 int()[3] 
12
指向有3个int型元素的数组
int (*ptr)(int);
int (*)(int)
 int ()(int)
 
指向函数的指针,该函数有一个整型参数并返回一个整型数

    说明:

    a,指针的类型:是指针本身所具有的类型。把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。

    b,指针所指向的类型:决定指针所指向的那片内存的大小和编译器怎么看待这片内存。 把指针声明语句中的指针名字和名字左边的指针声明符 *去掉,剩下的就是指针所指向的类型。

    c,指针的值:在32位系统中,它是一个32位的整数,是一个地址。其所占的内存是4byte

    指针所指向的类型和指针所指向的内存是不同的,一个指针被定义时,指针所指向的类型已经确定,但由于指针未初始化,它所指向的内存区是不存在的

  指针数组

    int *a[3];    //一个有3个指针的数组,该指针是指向一个整型数的。sizeof(a)=12,sizeof(*a)=4

    int (*a[10])(int);  //一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数

 

2,指针的强制类型转换的应用

  a,新指针的类型是TYPE*:  ptr1=(TYPE*)ptr2

注意:如果sizeof(ptr2的类型)大sizeof(ptr1的类型),那么在使用指针ptr1来访问ptr2所指向的存储区时是安全的。如果sizeof(ptr2的类型)小于sizeof(ptr1的类型),那么在使用指针ptr1来访问ptr2所指向的存储区时是不安全的。

  b,调用地址为0x30008000的函数:
      void (*p)(int *, char *);//定义函数指针
      p=(void (*)(int *,char *))0x30008000;
    将100赋给地址为0x804a008:
      *((int *)0x804a008) = 100;
  c,动态分配
    char *p
    p= (char *)malloc(sizeof(char));  //malloc()返回void型的指针 
 

3,函数指针

  定义:void (*pf)(char *);   //pf是指向void,参数是char* 的类型的函数的指针。

  赋值:void fun(char *);  fp=fun;

  调用方法

    (*fp)(name);  或者  fp(name);

    ANSI C支持这两种;unix支持第二种;K&R C支持第一种。

注意区分 void *pf(char *);   //pf是返回一个指针的函数

 

二,数组

1,一维数组:

<1>指定初始化项目(C99):int date[4] = {[0]=1,[5]=5};  其他项为0。

<2>数组名是该数组首元素的地址:date==&date[0],是一个指向int型的常量指针

<3>对指针加1,等价于对指针的值加上它指向的对象的字节大小:date+2==&date[2]   *(date+2)==date[2]

<4>保护数组的内容:int sum(const int ar[],int n);

<5>数组做函数形参: int sum(int *ar,int n);int sum(int ar[],int n);

2,指针和多维数组

  二维数组初始化:date={{1,2,3},{4,5,6}} 也可以省去{}。

  指向二维数组的指针:int zippo[4][2];   和   int (*pz)[2];

     pz指向包含两个int值的数组,即是指向二维数组,该二维数组有2列。使用该类型指针时注意不要超过二维数组的行数的范围

pz=zippo;  
zippo==&zippo[0]; zippo[0]==&zippo[0][0]; zippo==&(&zippo[0][0]);
*(zippo+2)==zippo[2]==&zippo[2][0]  //第三个元素,即包含2个int值的数组
*(*(zippo+2)+1)==zippo[2][1]

  指针兼容:

int **p1;int *p2[2];
p1=pz;(非法)//pz是指向int[2]型的指针。p1是指向int *的指针
p1=p2;(合法)

  二维数组做函数形参:

    void fun(int (*pz)[2]);  或   void fun(int pz[][2]);

 3,指针变量作为函数参数

<1>实参变量和形参变量之间数据传递是单向的。不可能通过函数调用来改变实参指针变量的值,但可以改变实参指针变量所指变量的值
void swap(int *p1,int *p2){int temp;temp=*p1;*p1=*p2;*p2=temp;}    //a,b(*pp1,*pp2)的值可以互换
void main(){int a=1, b=2;  int *pp1=&a,*pp2=&b;  swap(pp1,pp2)}      
 
void swap(int *p1,int *p2){int * temp;temp=p1;p1=p2;p2=temp;} 
//只是改p1,p2的地址,pp1,pp2不能改变,*p1,*p2(*pp1,*pp2)的值没有改变。因此不能交换a,b

<2>如果想要改变的是指针变量p的值,就要传递p的地址。

void getmemory(char *p, int num)
{
    p = (char *)malloc(sizeof(char)*num);
}
void test()
{
    char *str = NULL;
    getmemory(str, 100);   //此时str仍为NULL
    strcpy(str, "hello");       //出现段错误
}

正确写法有两种:
a种方法
void getmemory(char **p, int num)                        
{
    *p = (char *)malloc(sizeof(char)*num);
}
void test()
{
    char *str = NULL;
    getmemory(str, 100);   
    strcpy(str, "hello");
    free(str);      
}

b种方法
char* getmemory( int num)                        
{
    return (char *)malloc(sizeof(char)*num);   //返回的指针指向堆区
}
void test()
{
    char *str = NULL;
    str = getmemory(100);   
    strcpy(str, "hello");
    free(str);      
}

 

三 , 引用

  引用是C++中新增的一种复合类型,引用是对象的别名,其典型的用途是作为函数参数,具体的说是结构和对象的参数。

1,引用的定义和作为函数参数

//定义
int rats;
int & rodents = rats;
int * rodentsp = &rats;
//作为函数参数
void swap(int &a, int &b)
{
    int temp;
    temp = a;
    a = b;
    b = temp;
}
void main()
{
    int a = 30 , b = 20;
    swap(a, b);

}
View Code

 

  引用作为函数参数使得函数中的变量名成为调用程序中变量的别名,这种传递方式成为引用传递。引用传递允许被调用函数能够访问调用函数中的变量;而C语言只能按值传递,被调用函数使用调用函数的值的拷贝。

 2,临时变量,引用参数和const

double refcube(const double &ra)
{
    retirn ra*ra*ra;
}
//下面的调用方式都将产生临时变量
double side = 3.0;
long edge = 5L;
double c1 = refcube(side + 10.0); //表达式
double c2 = refcube(7.0);  //传递常量
double c3 = refcube(edge); //类型不符合
View Code

  若refcube函数的参数不是const型的,则不能产生临时变量,即上述的调用方式将出错。若声明将引用定义为const,则在必要时产生临时变量,其行为类似于按值传递。

3,将const用于引用返回类型

typedef struct point
{
    int x;
    int y;
}Point;

Point &accumulate(Point &p1, const Point &p2)
{
    p1.x += p2.x;
    p1.y += p2.y;
    return p1;
}

void main()
{
    Point p1 = {1, 2};
    Point p2 = {3, 4};

    //p1, p3的值是一样的,函数返回的是传入的p1的引用
    Point p3 = accumulate(p1, p2); 

    //函数返回的是p1的引用,所以这个语句是可行的。若是按值返回,则不能通过编译
    accumulate(p1, p2) = p2;
}
View Code

   返回的非const引用使其含义模糊;将返回的引用声明为const,则最后一条语句不合法。

   返回引用时,需注意:应避免返回函数终止时不再存在的内存单元的引用

4,传值,传指针,传引用

<1>如果数据对象很小,则按值传递

<2>如果数据对象是数组,则使用指针。因为这是唯一的选择。

<3>如果数据对象是较大的结构,则使用引用或指针

<4>如果数据对象是类对象,则使用引用。类设计的语义常常要求使用引用。

传指针和引用时,若不修改调用函数的数据,尽量使用const修饰

  

四,指针与引用的区别

http://blog.csdn.net/listening_music/article/details/6921608

1,指针与引用的区别

a,引用不可为空;指针可以是空的。使用指针之前必须做判空操作,而引用就不必

b,引用在定义的时候初始化,且不能再被赋值,其本身是常量;而指针是变量

c,引用的大小是所指向的便量的大小;指针是指针本身的大小

d,指针和引用的自增(++)运算意义不一样。指针的自增是指针指向的地址加1,引用则是所代表的内存的值加1.

d,指针指向一块内存,它的内容是所指内存的地址;而引用是某块内存的别名,且引用不改变指向。

2,常量指针和常量引用

     指向常量的指针和引用: const int *pointer = &i;             const int& refs = i;

 这里*pointer是常量,不能通过指针修改这块内存,该指针也不能赋给其他非常量指针;常量引用也是一样,所代表的内存是常量,不能通过该引用改变这块内存。

 

五,注意

<1>int days[]={....},sizeof days是整个数组的大小;sizeof day[0]是一个元素的大小(以字节为单位)

<2>C并不检查你是否使用了正确的下标,例如:int a[10];a[10]=12;编译器不会发现这样的错误。当程序运行时,这些语句把数据放在可能由其他数据使用的位置,因而可能破坏程序的结果甚至使程序崩溃。

<3>在返回指针变量时,注意不要用return返回指向栈内存中的指针。否则,函数返回后该指针指向的内存被释放。

<4>当创建一个指针时,系统只分配了用来存储指针本身的内存空间,并不分配用来存储数据的内存空间。因此在使用指针之前,必须给它赋予一个分配的内存。(可用malloc或把一已存在的变量地址赋给指针)。

posted @ 2014-09-29 20:02  suo_suo  阅读(333)  评论(0编辑  收藏  举报