• C语言学习指针


    ---恢复内容开始---

    一.运算符 &
    • scanf(“%d”, &i);里的&
    • 获得变量的地址,它的操作数必须是变量
    • int i; printf(“%x”,&i);
    • 地址的⼤大小是否与int相同取决于编译器
    • int i; printf(“%p”,&i);

    • &不能对没有地址的取地址
    • &(a+b)?
    • &(a++)?
    • &(++a)?

    二.指针初识
    就是保存地址的变量
    int i;
    int* p = &i;
    int* p,q;
    int *p,q;

    指针变量

    • 变量的值是内存的地址
    • 普通变量的值是实际的值
    • 指针变量的值是具有实际值的变量的地址 

    试试这些&
    • 变量的地址
    • 相邻的变量的地址
    • &的结果的sizeof
    • 数组的地址
    • 数组单元的地址
    • 相邻的数组单元的地址

    #include <stdio.h>
    int main()
    {
     int data=100;
     int * pd;
     pd = &data;
    // int *pd =&data;   指针变量定义另一种方式;声明与初始化一步完成
     printf("data=%d ",data); //变量的直接访问
     printf("data=%d ",*pd); //变量的直接访问
     
    printf("%lu ",sizeof(int));
     printf("%lu ",sizeof(&data));//在32位下,int和地址都是4个字节
     
    printf("address=%d ",&data); //变量的地址输出
     printf("address=%d ",pd);  //指针变量的输出
     
     return 0;
    }

     取数组的地址

    #include <stdio.h>
    int main(void)
    {
        int i=0;
        int p;
        
        int  a[10];
    //    printf("%p
    ",&i);
    //    printf("%p",&p);  
        printf("%p
    ",&a);
        printf("%p
    ",a);
        printf("%p
    ",&a[0]);
        printf("%p
    ",&a[1]);
    
        return 0;
    }

     我们可以看到,&a==a==&a[0];而int数组中的每个元素的地址永远是相差4,也就是一个sizeof(int)的大小

    三.作为参数的指针
    • void f(int *p);
    • 在被调用的时候得到了某个变量的地址:
    • int i=0; f(&i);
    • 在函数⾥里面可以通过这个指针访问外面的这个i

    #include <stdio.h>
    int main(void)
    {
     int i=6;
     int p;
        printf("&i=%p ",&i);
        f(&i);
       
        return 0;

    void f(int *p)
    {
     printf("p=%p ",p);//这样就可以访问函数外面的变量
    }

    四.访问那个地址上的变量*

    • *是一个单目运算符,用来访问指针的值所表示的地址上的变量

    • 可以做右值也可以做左值
    • int k = *p;
    • *p = k+1;

    五.*左值之所以叫左值

    • 是因为出现在赋值号左边的不是变量,而是值,是表达式计算的结果:

    • a[0] = 2;
    • *p = 3;
    • 是特殊的值,所以叫做左值

    指针应用场景一
    • 交换两个变量的值

     

     指针应用场景二
    • 函数返回多个值,某些值就只能通过指针返回
    • 传入的参数实际上是需要保存带回的结果的变量

    #include <stdio.h>
    void minmax(int a[],int len, int *max, int *min);
    int main(void)
    {
        int a[]={1,2,3,4,56,6,7,8,9,12};
        int min,max;
        minmax(a,sizeof(a)/sizeof(a[0]),&max,&min);
        printf("min=%d,max=%d",min,max);
    }
    
    void minmax(int a[],int len, int *max, int *min)  //int a[] 就是指针,改成int *a也可以编译成功
    {
        int i;
        *min = *max =a[0];
        for (i=1;i<len;i++){
            if (a[i]< *min){
                *min =a[i];
            }
            if (a[i]>*max){
                *max = a[i]; 
            }
        }
    }

     指针应用场景二b

    • 函数返回运算的状态,结果通过指针返回

    • 常用的套路是让函数返回特殊的不属于有效范围内的值来表示出错:

    • -1或0(在文件操作会看到大量的例子)

    • 但是当任何数值都是有效的可能结果时,就得分开返回了

    • 后续的语言(C++,Java)采用了异常机制来解决这个问题

    #include <stdio.h>  //函数返回运算的状态,结果通过指针返回 
    int divide(int a,int b,int *result);
    int main()
    {
        int a=5;
        int b=2;
        int c;
        if (divide(a,b,&c) ){
            printf("%d/%d=%d
    ",a,b,c);
        }
        return 0;
     } 
     
    int divide(int a,int b,int *result)
    {
        int ret =1 ;
        if( b==0 ) ret=0;
        else{
            *result= a/b;
        }
        return ret;
    }

     指针最常见的错误
    • 定义了指针变量,还没有指向任何变量,就开始使⽤指针

    传⼊入函数的数组成了什么

     • 函数参数表中的数组实际上是指针
    • sizeof(a) == sizeof(int*)
    • 但是可以用数组的运算符[]进行运算

    六.数组参数
    • 以下四种函数原型是等价的:
    • int sum(int *ar, int n);
    • int sum(int *, int);
    • int sum(int ar[], int n);
    • int sum(int [], int);

    七.数组变量是特殊的指针
    • 数组变量本⾝身表达地址,所以
    • int a[10]; int*p=a; // 无需用&取地址
    • 但是数组的单元表达的是变量,需要用&取地址
    • a == &a[0]
    • []运算符可以对数组做,也可以对指针做:
    • p[0] <==> a[0]
    • *运算符可以对指针做,也可以对数组做:
    • *a = 25;
    • 数组变量是const的指针,所以不能被赋值
    • int a[] <==> int * const a=… .  

     八.指针与const (C99 only)

    指针是const
    • 表示一旦得到了某个变量的地址,不能再指向其他变量

    • int * const q = &i; //  q 是 const

    • *q = 26; // OK
    • q++; // ERROR

    所指是const
    • 表示不能通过这个指针去修改那个变量(并不能使得那个变量成为const)

    • const int *p = &i;
    • *p = 26; // ERROR! (*p) 是 const
    • i = 26; //OK
    • p = &j; //OK

    int i;
    const int* p1 = &i; //指针所指不能修改
    int const* p2 = &i;//指针所指不能修改
    int *const p3 = &i; //指针不可修改
    判断哪个被const了的标志是const在*的前面还是后面

     转换
    • 总是可以把⼀一个非const的值转换成const的
    void f(const int* x);
    int a = 15;
    f(&a); // ok
    const int b = a;
    !
    f(&b); // ok
    b = a + 1; // Error!
    • 当要传递的参数的类型比地址大的时候,这是常用的手段:既能用比较少的字节数传递值给参数,又能避免函数对外面的变量的修改

    const数组
    • const int a[] = {1,2,3,4,5,6,};
    • 数组变量已经是const的指针了,这里的const表明数组的每个单元都是const int

    • 所以必须通过初始化进行赋值

    保护数组值
    • 因为把数组传入函数时传递的是地址,所以那个函数内部可以修改数组的值

    • 为了保护数组不被函数破坏,可以设置参数为const
    • int sum(const int a[], int length);

    ---恢复内容结束---

  • 相关阅读:
    HDU 4628 Pieces
    HDU 2983 Integer Transmission
    HDU 1820 Little Bishops
    CodeForces 165E Compatible Numbers
    CodeForces 11D A Simple Task
    HDU 4804 Campus Design
    HDU 3182 Hamburger Magi
    Linux的用户和组
    Linux文件/目录权限及归属
    Vim使用介绍
  • 原文地址:https://www.cnblogs.com/guoweilf/p/11480277.html
Copyright © 2020-2023  润新知