zoukankan      html  css  js  c++  java
  • C 指针

    理解指针定义 --存放地址

    内存区的每一个字节有一个编号, 这就是“地址”。 如果在程序中定义了一个变量, 在对程序进行编译

    时, 系统就会给这个变量分配内存单元。 

    在c程序里面有两种访问方式: 1. 是直接访问, 2是间接访问(a的箱子要是在b抽屉里)。

    直接访问: a=5;, 系统在编译是,已经对变量分配了地址 如果变量的a的地址是2000, 那么这个语句的作用就是
    
    把常数5保存到地址为2000的单元。
    间接访问如:scanf(“%d”, &a);
    调用函数时, 把变量a的地址传递给函数scanf, 函数首先把该地址保存到一个单元中, 然后把键盘接受的数据通过所存储的地址保存到a的变量中。

    定义指针

    int i=5;
    int
    * i_abc; 定义指针变量 i_abc = & i; 存放整型变量i的地址

    深入理解:

    将i 的内存地址2000存放到i_abc,这时, i_abc的值就是(2000, i的内存地址),即变量i所占用单元

    的起始地址。要存取变量i的值,可以采取间接方式:先找到存放“i的地址”的变量i_abc, 然后从中取出i的地址(2000)

    然后取出i的值3.

    代码讲解

    *  : 叫取值操作符

    &: 叫取址操作符

    int i = 5;
    int *abc;  // 这个*不是取值操作符,而是声明他是指针变量, 也就是定义指针变量
    abc = &i;  // 存放指针,也就是内存地址  &i 的地址是2000
    printf("%d
    ", *abc);//这个才是取值操作符, 加上*系统知道他是指针的值

    注意:

    定义的时候:

    float a;
    
    int   *abc;
    
    abc = &a;
    
    这样是错误的,关系到取址, 比如有浮点是8位,而整型是4位,那就会少4位
    

    说明: 

    如果已执行了语句 abc = &a;

    1) . &*abc的含义是什么?

    "&"和 "*" 两个运算符的优先级相同, 但按照自右而左方向结合, 因此先进行*abc 的运算, 他就是变量a,

    例如: printf("%d
    ", *abc);

    再执行&运算。

    2)。 * & a的含义是蛇年意思?

    先&a运算,然后在×运算, 最后还是指向a  

    针对数组的指针 ---------------------------

    p= &a【0】  // 把a【0】元素的地址赋给指针变量p

    注意一个小地方:

    引用一个数组元素, 可以用:

    ).下标法, 如a[i]形式;
    
    ).指针法, 如*(a+i) 或(p+)
    
    其中的a是数组名, p是指向数组元素的指针变量, 其初值p=a。也就是
    
    a指向的数组第一个值
    
    数组名即“翻译成数组的第一个元素地址”

    简单易懂的例子

    #include <stdio.h>
    
    #define N 10
    
    int main(void) {
    
        int a[N] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        int *p, sum = 0;
    
        //方法1:
        //用索引的方式, 这里需要注意的是p是指针,a[0]是实际的值,需要用&取址
        for (p = &a[0]; p < &a[N]; p++) {
            sum += *p;
        }
        printf("sum value is:%d 
    ", sum); /* sum value is:55 */
    
        //方法2:
        //用指针的方式
        sum = 0;
        for (p = a; p < a + N; p++) {
            sum += *p;
        }
        printf("sum value is:%d 
    ", sum); /*sum value is:55*/
        return 0;
    }

     

    要输出数组中的全部元素的三种方法-------一维数组

    方法1:下标法

    #include <stdio.h>
    
    int main(int argc, char const *argv[]) {
      /* code */
      int a[10];
      int i;
      for(i = 0; i < 10; i++)
      {
          scanf("%d", &a[i] );
      }
      for(i=0;i<10;i++)
      {
          printf("%d
    ", a[i]);
      }
      return 0;
    }

    方法2: 通过数组名计算数组元素的地址, 找出元素值

    #include <stdio.h>
    
    int main(int argc, char const *argv[]) {
      /* code */
      int a[10];
      int i;
      for(i = 0; i < 10; i++)
      {
          scanf("%d", &a[i] );
      }
      for(i=0;i<10;i++)
      {
          printf("%d
    ", *(a+i));
      }
      return 0;
    }

    方法3:用指针变量指向数组元素

    #include <stdio.h>
    
    int main(int argc, char const *argv[]) {
      int a[10];
      int i;
      int *p;
    
      for (i=0;i<10;i++)
      {
          scanf("%d", &a[i]);
      }
    
      for (p = a; p < (a+10); p++)
      {
        /* code */
        printf("%d", *p);
      }
      return 0;
    }

    用数组名作为函数参数--------------------------------------------

    f(int a[], int n)  但在编译时是将arr按指针变量处理的, 相当于将函数f的首部写成f(int *arr, int n)  等价的

    看试题:

    要求将数组a中n个整数按相反顺序存放

    #include <stdio.h>
    
    int main(int argc, char const *argv[]) {
      void reverse(int *x, int);
      int i, a[10] = {3, 7, 9, 11, 0, 6, 7, 5, 4, 2};
      for (i = 0; i < 10; i++)
      {
          printf("%d", a[i]);
      }
      printf("
    ");
      reverse(a, 10);
      for (i = 0; i < 10; i++) {
        printf("%d", a[i]);
      }
      printf("
    ");
      return 0;
    }
    
    void reverse(int x[], int n)
    {
       int temp, i, j, m;
       m = (n-1)/2;
       for (i = 0; i <= m; i++)
       {
          j = n-1-i;
    
          temp = x[i];
          x[i] = x[j];
          x[j] = temp;
       }
    }
    View Code

     指针写法

    #include <stdio.h>
    
    int main(int argc, char const *argv[]) {
      void reverse(int *x, int);
      int i, a[10] = {3, 7, 9, 11, 0, 6, 7, 5, 4, 2};
      for (i = 0; i < 10; i++)
      {
          printf("%d", a[i]);
      }
      printf("
    ");
      reverse(a, 10);
      for (i = 0; i < 10; i++) {
        printf("%d", a[i]);
      }
      printf("
    ");
      return 0;
    }
    
    void reverse(int *x, int n)
    {
        int *p, temp, *i, *j, m;
    
        m = (n - 1)/2;
        i = x;
        j = x + n -1;
        p = x + m;
        for (;i <= p;i++, j--)
        {
          temp = *i;
          *i = *j;
          *j = temp;
        }
    }
    View Code

     二维数组

    内存地址

     怎么用指针寻找的规律

      

    从前面的图可以分析得出结论 *(p+i) + j 是二维数组i行j列的元素地址
    而*(*(p+i) +j) 则是i行j列的值

    定义多维数组元素的指针变量

    把二维数组a分解为一维数组a[0], a[1], a[2]之后, 设p为指向二维数组的指针变量

    可定义为:

    int (*p)[4]

     表示p是一个指针变量, 他指向包含4个元素的一维数组。 若指向第一个一维数组a[0], 其值等于a,

    a【0】, 或&a【0】【0】等。 

    #include <stdio.h>
    
    int main(int argc, char const *argv[])
    {
      int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
      int (*p)[4];
      int i, j;
      p = a;
    
      for (i=0; i < 3; i++)
      {
        /* code */
        for (j = 0;j<4;j++)
        {
            // printf("%2d", *(*p+i)+j);   //注意这个错误,是我当初犯下的错误
            printf("%2d", *(*(p+i)+j));
        }
        printf("
    ");
      }
    
      return 0;
    }

    字符串与指针  --------------------------------------

    用数组的形式来表示字符串

    #include <stdio.h>
    
    int main(int argc, char const *argv[])
    {
      char string[] = "I love you , Future girl"  ;
      printf("%s
    ", string);
    
      return 0;
    }

    用指针的形式

    #include <stdio.h>
    
    int main(int argc, char const *argv[])
    {
      char *string = "I love you , Future girl"  ;
      printf("%s
    ", string);
    
      return 0;
    }

    对字符串中的字符的存取方法有两种

    1. 是下标法:

    #include <stdio.h>
    
    int main(int argc, char const *argv[])
    {
      char a[] = "hahhahahaha, future girl", b[40];
      int i;
    
      for (i = 0; *(a + i) != ''; i++)
     {
        *(b + i) = a[i];
      }
      *(b + i) = '';
      printf("%s
    ", a);
      printf("%c
    ", *a);
      for (i = 0; b[i] != ''; i++)
      {
        printf("%c", b[i]);
      }
      printf("
    ");
      return 0;
    }
    View Code

    2.是指针方法:

    #include <stdio.h>
    
    int main(int argc, char const *argv[]) {
      char a[] = "hahhahahaha, future girl", b[40], *p1, *p2;
      int i;
    
      p1 = a;
      p2 = b;
    
      for (; *p1 != ''; p1++, p2++)
     {
        *p2 = *p1;
      }
      *p2 = '';
      printf("wo shi a:%s
    ", a);
      for (i = 0; b[i] != ''; i++)
      {
        printf("%c", b[i]);
      }
      return 0;
    }
    View Code

    字符指针作函数参数以及指针a【】和*a 的区别 -----------------------------

    *a 是不可写的,a【】是可写的

    为什么:  char *a = "i am a;";  是放常量的,常量是不可写的。

    在c/c++中,内存分为5个区, 堆,栈, 自由存储区, 全局/静态存储区和常亮存储区。

    方法一:用字符串数组作参数

    #include <stdio.h>
    
    int main(int argc, char const *argv[])
    {
        int copy_str(char from[], char to[]);
    
        char a[] = "i am a;";
        char b[] = "i am b;";
    
        printf("%s
    %s
    ----------------
    ", a, b);
    
        copy_str(a, b);
        printf("%s
    %s
    ", a, b);
    
      return 0;
    }
    
    
    int copy_str(char from[], char to[])
    {
      int i = 0;
      while (from[i] != '') {
        to[i] = from[i];
        i++;
      }
      to[i] = '';
      return 0;
    }
    View Code

    方法二: 形参用字符指针变量

    #include <stdio.h>
    
    int main(int argc, char const *argv[])
    {
        int copy_str(char *from, char *to);
    
        char *a = "i am a;";
        char b[] = "i am b;";  //注意这是b是不是为×b,否则报错不能写入
    
        printf("%s
    %s
    ----------------
    ", a, b);
    
        copy_str(a, b);
        printf("%s
    %s
    ", a, b);
    
      return 0;
    }
    
    
    int copy_str(char *from, char *to)
    {
      for (; *from != ''; from++, to++)
      {
          *to = *from ;
      }
      return 0;
    }
    View Code

    还有一种巧妙方法

    #include <stdio.h>
    
    int main(int argc, char const *argv[])
    {
        int max(int, int);
        int (*p)();
        int a, b, c;
    
        p = max;
        scanf("%d %d", &a, &b );
    
        c = (*p)(a, b);  //关键是这句
        printf("%d, %d
    ", a, b);
        printf("%d
    ", c);
      return 0;
    }
    int max(int x, int y)
    {
        int z;
    
        if (x > y)
          {
             z = x;
          }
        else
          {
            z = y;
          }
        return z;
    }
    View Code

    小需求及测试题

    注意,指针函数 的写法

    int *test(int a[]);

    返回指针的数组元素的写法

    int *test(int a[]){
        return &a[3];
    }

    用&符号

     参考代码:

    只写了一部分

    #include <stdio.h>
    
    #define N 5
    
    int *test(int a[]);
    
    int main(void) {
        int b[N] = {1, 2, 3, 4, 5};
        int *a=NULL;
        a = test(b);
        printf("%d
    ", *a);
        return 0;
    }
    
    int *test(int a[]){
        return &a[3];
    }
    View Code

     

    #include <stdio.h>
    
    #define N 5
    
    void find_two_largest(int a[], int n, int *largest, int *second_largest);
    
    int main(void) {
        int b[N] = {1, 2, 3, 4, 5,};
        int largest = 0, second_largest = 0;
    
        find_two_largest(b, N, &largest, &second_largest);
        printf("largest value is: %d 
    ", largest);
        printf("second_largest value is: %d 
    ", second_largest);
        return 0;
    }
    
    void find_two_largest(int a[], int n, int *largest, int *second_largest) {
    
        *largest = *second_largest = a[0];
    
        for (int i = 0; i < n; ++i) {
            if (a[i] > *largest)
                *largest = a[i];
        }
        for (int i = 0; i < n; ++i) {
            if (a[i] == *largest) {
                continue;
            } else if (a[i] > *second_largest) {
                *second_largest = a[i];
            }
        }
    }
  • 相关阅读:
    1509 加长棒
    51Nod 1158 全是1的最大子矩阵
    P2953 [USACO09OPEN]牛的数字游戏Cow Digit Game
    P3384 【模板】树链剖分
    北京集训DAY3
    北京集训DAY2
    北京集训DAY1
    51Nod 1422 沙拉酱前缀 二分查找
    51Nod 1109 01组成的N的倍数
    51Nod 1043 幸运号码 数位DP
  • 原文地址:https://www.cnblogs.com/renfanzi/p/6748363.html
Copyright © 2011-2022 走看看