指针基础

  • 指针是一个变量,其值是另外一个变量的地址,所以指针只能赋值变量的地址
  • 指针存的地址是一个16进制整数,输出十六进制数使用%x。单位是字节。如指针值为10,表示内存地址为10字节

  • * 声明指针或者取指针值
  • & 取变量地址
    • 定义指针的位置是随意的。比如`int p; int p; intp; int *p;`都是可以的

最好还是分隔一下


空指针(NULL)

  • 定义指针时,如果没有确切的量赋予给指针,那么就先将指针赋予空值(*p=NULL)。NULL指针的地址为0
  • 未赋值的指针叫做野指针,值为一个随机的非0值(非空值)
    • 所以可以这样使用该规则:**存在指针ptr;**

**if(ptr) /* 如果 p 非空,则完成 */**
**if(!ptr) /* 如果 p 为空,则完成 */**

指针的算术运算

可以对指针进行四种算术运算:++、—、+、-。、

  • ++与—:假设指针p值为1000,类型为double;则**printf("%x",++p);**因为double型为8个字节,所以指针加一则地址加8
  • +与-:还不清楚

    使用++,—指针以遍历数组

    之前是使用指针=数组首地址,然后指针+?的形式来实现指针遍历数组

    递增一个指针

    我们喜欢在程序中使用指针代替数组,因为变量指针可以递增,而数组不能递增,因为数组是一个常量指针。下面的程序递增变量指针,以便顺序访问数组中的每一个元素: ```c

    include

const int MAX = 3;

int main () { int var[] = {10, 100, 200}; int i, *ptr;

/ 指针中的数组地址 / ptr = var; for ( i = 0; i < MAX; i++) {

  1. printf("Address of var[%d] = %x\n", i, ptr );
  2. printf("Value of var[%d] = %d\n", i, *ptr );
  3. /* 移动到下一个位置 */
  4. ptr++;

} return 0; }

当上面的代码被编译和执行时,它会产生下列结果: Address of var[0] = bf882b30 Value of var[0] = 10 Address of var[1] = bf882b34 Value of var[1] = 100 Address of var[2] = bf882b38 Value of var[2] = 200

  1. <a name="nOPiG"></a>
  2. ## 递减一个指针
  3. 同样地,对指针进行递减运算,即把值减去其数据类型的字节数,如下所示:
  4. ```c
  5. #include <stdio.h>
  6. const int MAX = 3;
  7. int main ()
  8. {
  9. int var[] = {10, 100, 200};
  10. int i, *ptr;
  11. /* 指针中最后一个元素的地址 */
  12. ptr = &var[MAX-1];
  13. for ( i = MAX; i > 0; i--)
  14. {
  15. printf("Address of var[%d] = %x\n", i, ptr );
  16. printf("Value of var[%d] = %d\n", i, *ptr );
  17. /* 移动到下一个位置 */
  18. ptr--;
  19. }
  20. return 0;
  21. }
  22. 当上面的代码被编译和执行时,它会产生下列结果:
  23. Address of var[3] = bfedbcd8
  24. Value of var[3] = 200
  25. Address of var[2] = bfedbcd4
  26. Value of var[2] = 100
  27. Address of var[1] = bfedbcd0
  28. Value of var[1] = 10

指针的比较

指针可以用关系运算符进行比较,如 ==、< 和 >。如果 p1 和 p2 指向两个相关的变量,比如同一个数组中的不同元素,则可对 p1 和 p2 进行大小比较。
下面的程序修改了上面的实例,只要变量指针所指向的地址小于或等于数组的最后一个元素的地址 &var[MAX - 1],则把变量指针进行递增:

#include <stdio.h>

const int MAX = 3;

int main ()
{
   int  var[] = {10, 100, 200};
   int  i, *ptr;

   /* 指针中第一个元素的地址 */
   ptr = var;
   i = 0;
   while ( ptr <= &var[MAX - 1] )
   {

      printf("Address of var[%d] = %x\n", i, ptr );
      printf("Value of var[%d] = %d\n", i, *ptr );

      /* 指向上一个位置 */
      ptr++;
      i++;
   }
   return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:
Address of var[0] = bfdbcb20
Value of var[0] = 10
Address of var[1] = bfdbcb24
Value of var[1] = 100
Address of var[2] = bfdbcb28
Value of var[2] = 200

指针数组

在我们讲解指针数组的概念之前,先让我们来看一个实例,它用到了一个由 3 个整数组成的数组:

#include <stdio.h>

const int MAX = 3;

int main ()
{
   int  var[] = {10, 100, 200};
   int i;

   for (i = 0; i < MAX; i++)
   {
      printf("Value of var[%d] = %d\n", i, var[i] );
   }
   return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:
Value of var[0] = 10
Value of var[1] = 100
Value of var[2] = 200

可能有一种情况,我们想要让数组存储指向 int 或 char 或其他数据类型的指针。下面是一个指向整数的指针数组的声明:
int *ptr[MAX];

在这里,把 ptr 声明为一个数组,由 MAX 个整数指针组成。因此,ptr 中的每个元素,都是一个指向 int 值的指针。下面的实例用到了三个整数,它们将存储在一个指针数组中,如下所示:
#include <stdio.h>

const int MAX = 3;

int main ()
{
   int  var[] = {10, 100, 200};
   int i, *ptr[MAX];

   for ( i = 0; i < MAX; i++)
   {
      ptr[i] = &var[i]; /* 赋值为整数的地址 */
   }
   for ( i = 0; i < MAX; i++)
   {
      printf("Value of var[%d] = %d\n", i, *ptr[i] );
   }
   return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:
Value of var[0] = 10
Value of var[1] = 100
Value of var[2] = 200

您也可以用一个指向字符的指针数组来存储一个字符串列表,如下:
#include <stdio.h>

const int MAX = 4;

int main ()
{
   char *names[] = {
                   "Zara Ali",
                   "Hina Ali",
                   "Nuha Ali",
                   "Sara Ali",
   };
   int i = 0;

   for ( i = 0; i < MAX; i++)
   {
      printf("Value of names[%d] = %s\n", i, names[i] );
   }
   return 0;
}

当上面的代码被编译和执行时,它会产生下列结果:
Value of names[0] = Zara Ali
Value of names[1] = Hina Ali
Value of names[2] = Nuha Ali
Value of names[3] = Sara Ali

指向指针的指针

指向指针的指针是一种多级间接寻址的形式,或者说是一个指针链。
当我们定义一个指向指针的指针时,第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的位置。
声明语法如下,比如
int **var;
同样的访问指向指针的指针的值也需要使用**进行取值

有一个需要注意的地方,虽然指针存放的是地址,所以指针可以直接赋值为另一个指针。但是指向指针的指针初始化为另一个指针的地址还是要使用取地址符&;
比如**int **p1=&p2;**p2也是一个指针
前者一个指针直接=另一个指针,是一个内存同一个地址的2个名字。
而指向指针的指针是不同地址,但是存放的数据最终指向的是相同的数据
再简单点是前者是地址相同,存放内容自然也相同。后者是地址不同,但是*指针存放的数据还是是指针的数据

#include <iostream>

using namespace std;

int main ()
{
   int  var;
   int  *ptr;
   int  **pptr;

   var = 3000;

   // 获取 var 的地址
   ptr = &var;

   // 使用运算符 & 获取 ptr 的地址
   pptr = &ptr;

   // 使用 pptr 获取值
   cout << "Value of var :" << var << endl;
   cout << "Value available at *ptr :" << *ptr << endl;
   cout << "Value available at **pptr :" << **pptr << endl;

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

Value of var = 3000
Value available at *ptr = 3000
Value available at **pptr = 3000

总结

指向指针的指针即特殊的指针,它的值为其他指针的地址(使用&来取其他指针地址) 使用**来取值

指针与函数

传递指针给数组
从函数返回指针

指针和字符串

字符数组字符串跟数组的结构还是一样的。所以指针与数组的所有操作同样适用于字符串
char string[]="I love China!",*ps=string; (*(ps+4))=string[4]->v

指针字符串

定义:char *string="I love China!" 本质还是开辟了一个字符数组,将字符数组首地址string[0],即string赋值给了*string

//也可以用指针变量,用它的值的来改变来指向字符串中不同的字符
#include<stdio.h>
int main(){
    char a[]="I am a boy!",b[20],*p1,*p2;
    int i;
    p1=a;
    p2=b;
    for(;*p1!='\0';p1++,p2++)
        *p2=*p1;
    *p2='\0';
    printf("string a is:%s\n",a);
    printf("string b is:");
    for(p2=b;*p2!='\0';p2++)
        printf("%c",*p2);
    printf("\n");
    return 0;
}
//用函数调用实现字符串的复制,用字符数组作参数 
#include<stdio.h>
void copy(char a[],char b[]){
    int i=0;
    while(a[i]!='\0'){
        b[i]=a[i];
        i++;
    }
    b[i]='\0';
}
int main(){
    char a[]="I am a teacher!";
    char b[]="You are a student!";
    printf("string a=%s\nstring b=%s",a,b);
    printf("\ncopy string a to b:\n");
    copy(a,b);
    printf("string a=%s\nstring b=%s",a,b);
    return 0;
}

b

字符串常量在编译时系统给定存储位置,可以赋值给字符指针;此时可以通过下标进行访问,但不可以通过下标修改字符串的值。
字符指针指向字符数组时可以修改字符串的值。
指针 - 图1

#include <stdio.h>
#include <string.h>
 int main()
{
    char a[26];
    char *b = "abc";   //定义时初始化
    b="123";           //可以被重新赋值
    //b[1] = 'v';      //不可以被修改
    a[1] = b[1];       //可以通过下标读取
    strcpy(a, "catdog");
    strcat(a, "!");
    b = a;           //指向字符数组
    b[0] = 'x';      //可以被修改
    b[1] = "x";      //实际上将字符常量"x"的地址付给b[1],字符串将出现乱码
    printf("%s\n", a);
    system("pause");
    return 0;
}

指针 - 图2