编程ing

C语言的灵魂——指针

2017-03-04  本文已影响73人  指尖极光

一、指针简介

1、什么是指针?

指针是一个变量,其值为另一个变量的地址,即内存地址的直接地址。做个比喻,假设将你比作变量,那么你身份证上的住址就是指针,根据你身份证上的地址可以找到你,即指针存的内容是你身份证上的住址。

指针有两种含义,一是作为数据类型,二是作为实体。

指针作为实体,是一个用来保存一个内存地址的计算机语言中的变量。指针一般出现在比较底层的程序设计语言中,如C语言。高级语言如Java一般避免用指针,而是引用。指针作为数据类型,可以从一个函数类型、一个对象类型或者一个不完备类型中导出。从中导出的数据类型称之为被引用类型(referenced type)。指针类型描述了一种对象,其值为对被引用类型的实体的引用。

指针可以用来有效地表示复杂的数据结构,可以用于函数参数传递并达到更加灵活使用函数的目的。使C语言程序的设计具有灵活、实用、高效的特点。

2、*与&操作符

取地址运算符(&):取变量的地址,即返回操作数的内存地址。&var 读作"var 的地址"。

间接寻址运算符(*):返回操作数所指定地址的变量的值。

3、如何使用指针?

使用指针时会频繁进行以下几个操作:

  1. 定义一个指针变量;
  2. 把变量地址赋值给指针;
  3. 访问指针变量中可用地址的值。

这些是通过使用一元运算符 * 来返回位于操作数所指定地址的变量的值。

#include <stdio.h>
int main (){
   int  var = 20;   /* 实际变量的声明 */
   int  *ip;/* 指针变量的声明 */
   ip = &var;  /* 在指针变量中存储 var 的地址 */
   printf("Address of var variable: %x\n", &var  );
   /* 在指针变量中存储的地址 */
   printf("Address stored in ip variable: %x\n", ip );
   /* 使用指针访问值 */
   printf("Value of *ip variable: %d\n", *ip );
   return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

Address of var variable: bffd8b3c
Address stored in ip variable: bffd8b3c
Value of *ip variable: 20

4、指针运算符

C 指针是一个用数值表示的地址。因此,您可以对指针执行算术运算。可以对指针进行四种算术运算:++、--、+、-。

假设 ptr 是一个指向地址 1000 的整型指针,是一个 32 位的整数,让我们对该指针执行下列的算术运算:

ptr++

在执行完上述的运算之后,ptr 将指向位置 1004,因为 ptr 每增加一次,它都将指向下一个整数位置,即当前位置往后移 4 个字节。这个运算会在不影响内存位置中实际值的情况下,移动指针到下一个内存位置。如果 ptr 指向一个地址为 1000 的字符,上面的运算会导致指针指向位置 1001,因为下一个字符位置是在 1001。

5、NULL 指针

在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为空指针。NULL 指针是一个定义在标准库中的值为零的常量。请看下面的程序:
#include <stdio.h>
int main (){
int *ptr = NULL;
printf("ptr 的值是 %x\n", ptr );
return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:

ptr 的值是 0

二、指针与数组

1、区别

C++/C程序中,指针和数组在不少地方可以相互替换着用,让人产生一种错觉,以为两者是等价的。数组是连续分配一串单元,数目开始定义的时候就必须固定下来,看起来整洁,但是写的程序是死程序,容易浪费内存。指针是存放一个地址值,表示指向某一个单元,可以用指针来索引单元。数组可以完成栈,堆,树等等的操作,它在编程时候的好处是非常的灵活,在构建思路的时候有很大的灵活性。

2、指针数组与数组指针

指针数组:array of pointers,即用于存储指针的数组,也就是数组元素都是指针。

数组指针:a pointer to an array,数组名本身就是一个指针,指向数组的首地址,即指向数组的指针。

int* a[4] ;   /* 指针数组      
                 表示:数组a中的元素都为int型指针     
                 元素表示:*a[i]   *(a[i])是一样的,因为[]优先级高于*/
int (*a)[4]  ;/* 数组指针      
                 表示:指向数组a的指针
                 元素表示:(*a)[i]   */

#include <stdio.h>
int main(void)
{
    int c[4]={1,2,3,4};
    int *a[4]; //指针数组
    int (*b)[4]; //数组指针
    b=&c;
    //将数组c中元素赋给数组a
    for(int i=0;i<4;i++)
    {
        a[i]=&c[i];
    }
    //输出看下结果
    printf("%d",*a[1]);//输出2就对
    printf("%d",(*b)[2]);//输出3就对
    return 0;
}

三、指针与字符串

C语言中没有特定的字符串类型,我们通常是将字符串放在一个字符数组中。字符数组归根结底还是一个数组,使用指针的方式来输出字符串:

#include <stdio.h>
int main(){
    char str[] = "http://www.jianshu.com/";
    char *pstr = str;
    int len = strlen(str), i;
    //使用*(pstr+i)
    for(i=0; i<len; i++){
        printf("%c", *(pstr+i));
    }
    printf("\n");
    //使用pstr[i]
    for(i=0; i<len; i++){
        printf("%c", pstr[i]);
    }
    printf("\n");
    //使用*(str+i)
    for(i=0; i<len; i++){
        printf("%c", *(str+i));
    }
    printf("\n");
    return 0;
}

四、指针与函数

函数指针:本身是一个指针,指向一个函数入口地址,通过该指针可调用其指向的函数,使用函数指针可实现回调函数。

#include <stdio.h>
void inc(int *val)
{
    (*val)++;
}
int main(void)
{
    void (*fun)(int *);
    int a=3;
    fun=inc;//fun是一个函数指针
    (*fun)(&a);
    printf("%d" , a);
}

指针函数:本身是一个函数,其返回值是一个指针。

#include <stdio.h>
float *find(float(*pionter)[4],int n);//函数声明
int main(void)
{
     static float score[][4]={{60,70,80,90},{56,89,34,45},{34,23,56,45}};
     float *p;
     int i,m;
     printf("Enter the number to be found:");
     scanf("%d",&m);
     printf("the score of NO.%d are:\n",m);
     p=find(score,m-1);
     for(i=0;i<4;i++)
         printf("%5.2f\t",*(p+i));
     return 0;
 }
float *find(float(*pionter)[4],int n)/*定义指针函数*/
 {
     float *pt;
     pt=*(pionter+n);
     return(pt);
 }

五、指针与引用

  1. 引用总是指向一个对象,没有所谓的 null reference 。所有当有可能指向一个对象也有可能不指向对象则必须使用指针。由于C++ 要求 reference 总是指向一个对象所以 reference要求有初值.由于没有所谓的 null reference 所以在使用前不需要进行测试其是否有值,而使用指针则需要测试其的有效性。
  2. 指针可以被重新赋值而reference则总是指向最初或地的对象。
  3. 必须使用reference的场合.Operator[]操作符由于该操作符很特别地必须返回 [能够被当做ssignment 赋值对象] 的东西,所以需要给他返回一个 reference。
  4. 其实引用在函数的参数中使用很经常。格式如下:
    void Get***(const int& a){} //这样使用了引用又可以保证不修改被引用的值

区别:

上一篇 下一篇

猜你喜欢

热点阅读