指针

1. 取地址运算:运算符&

  scanf("%d", &i); 里的 & 是一个运算符,用于获取其后变量的内存地址。

  • 按十六进制输出变量的内存地址:printf("%p\n", &i)  32位系统则输出类似0xbff62d6c
  • 相邻变量的内存地址差数为4
  • & 不能对没有地址的东西取地址,如&(a+b)、&(a++)、&(++a)
  • 数组a[10]的地址:printf("%p\n", &a) 、printf("%p\n", a)、printf("%p\n", &a[0]) 三者的地址相同

 2.指针

  2.1 指针变量

  获取变量的地址之后如何保存呢?

  int a =1;

  int* p = &a;

    • *p表示p是一个指针,int*p或int *p或Int* p都表示p是一个指针,这个指针指向的那个地址里存储的是int数据类型。
    • int *p,q 和 int* p,q 都表示int *p; int q;  没有int*这种类型,不管*靠近int还是p,都表示*p是个int类型。
    • int *p,*q 才表示p、q都是指针。
    • p指向a 的意思就是名为 p 的指针变量里存储着普通变量 a 的内存地址。
      • 换句话说:把普通变量 a 的内存地址放入变量p中,变量p就指向变量a。
      • 指针变量p有自己的内存地址。
    • 指针变量p就是记录地址的变量,其值为一个内存地址,其数据类型为指针。* 就是传送门,能够根据地址传递相应的变量。如*p当做一个整体那就是指针变量p指向的存储单元存储的值。
      • 普通变量的值就是实际的值;指针变量的值是所指向的普通变量的地址。

    

    

 

  2.2 指针在函数中的传递

  传址:给函数f(int *p)传递一个指针,如 f(&a) 那么这个指针所指向的函数外面的变量a变了,函数内部也会跟着变。

    scanf()就是一个要传址的函数,如果写成int i;scanf("%d", i);则编译器会把变量i的值理解为地址。

  传值:给函数f(int p)传递一个值,如f(a)则只是把变量a的值传进去了,之后就和变量a没有任何关系了。

  

//关于传址与传值
#include <stdio.h>

void f(int *p);  //传址,要求传入一个内存地址存在名为p的变量中,这个地址对应的变量的值为int类型
void g(int k);   //传值

int main(void)
{
    int i = 6;
    printf("&i=%p\n", &i);  //输出变量i的地址
    f(&i);  //给函数f传入i的地址
    g(i);   //给函数g传入i的值
    return 0;
}

void f(int *p)
{
    printf(" p=%p\n", p );
    printf("*p=%d\n", *p );  //*p作为一个整体则为p所指向的那个变量的值
  *p = 600;  //把指针p所指向的那个变量的值改为600,即把函数外的值改了
}

void g(int k)
{
    printf(" k=%d\n", k );
}

/* 输出如下:
&i=0061FE9C
 p=0061FE9C
*p=6
 k=600

*/

 

 2.3 指针的使用

   2.3.1 函数需要返回多个值时,传入地址的参数要把结果带出来

    如交换a、b两个数的值,将两个数的地址输入函数

    

    

     2.3.2 函数需要返回一个状态,然后利用if 语句判断状态,而结果通过指针返回。

    

    

     2.3.3 指针使用最常见错误

    定义了指针变量int *p,但还没有指向任何变量,就开始使用指针。如:

    int *p;  int k = 12;  *p = 12;  此时p的值不知道是哪里的内存地址,这样不知道会把哪里的值改成12。

 

  2.4 指针与数组

   数组a作为值传递给函数接收数组的参数f(int a[ ])时,即f(a),传递的是数组的地址&a。

    • 数组变量a本身表达的就是地址,int a[10]; int *p=a;  //无需用&取地址
    • 数组变量a是一个指针,指向数组第一个元素a[0],故*a即表示a[0]的值
    • 所以函数内部用sizeof(a)=4,等于数组a的地址的长度,而不是数组的长度
    • 但是在函数内部可以用a[i]获取数组的元素。

    

     

        

     

   2.5 指针和const

   指针可以是const,指针所指的变量也可以是const,看const在*之前还是之后,两者有何区别:

    • 指针是const,即const q,则指针一旦得到某个变量的地址,就不能再指向其他变量,如:
      • int * const q = &i;  //指针q是const
      • *q = 26;  //OK,可以修改所指的变量的值
      • q++;  //ERROR
    • 所指是const,即const *,表示不能通过指针去修改所指的变量的值,但是指针和所指的变量都不是const,如:
      • const int *p = &i;  //或者等价于  int const *p = &i;  
      • *p = 26;  //ERROR! *p是const,p所指的变量的值能修改,但是不能通过指针去修改所指的变量的值
      • i = 26; //OK,p所指的变量的值能修改
      • p = &j; //OK,p也能修改

  用处1:所指是const,即const *,这样就能保证函数内部不会通过指针去修改所指的变量的值。

    

  用处2:因为数组变量a就是指针,const a 就相当于所指是const,这样就可以避免函数内部通过数组变量这个指针去修改数组内部的单元了。

    

    

 

   2.6 指针运算

   2.6.1 指针+1

   指针+1就是,指针所指的变量a地址加上一个a的sizeof(a),a是char则为+1,a为int则为+4,对于连续的地址则指向下一个变量。

    

    

   2.6.2 指针计算

  指针计算中的数字X表示X个所指向变量的类型的sizeof,即 X * sizeof(a) 如:

  有两个指针int *p和int *q:

    • p+1 表示 p+sizeof(int),32位即为0xbffd2c + 4 = 0xbffd30
    • p-1  表示 p-sizeof(int),32位即为0xbffd2c - 4 = 0xbffd28
    • p-q  表示 (p-q)/sizeof(int),32位即为(0xbffd40 - 0xbffd28)/4 = 6

      

   2.6.3 *p++  后续进行补充

  

   2.6.4 指针的比较

    指针就是地址,指针也可以进行比较,就是比较他们的内存地址

    

   2.6.5 0地址

    

   2.6.6 指针的类型

    

    

 小结:指针的用处

  

 

  2.6.7 动态内存分配

   C99之前不会自动分配空间,需要自己手动申请内存空间;申请失败则返回0,或者叫做NULL

   

 

   

     

     

 

posted @ 2023-08-10 15:39  园友3218619  阅读(7)  评论(4)    收藏  举报