• C 基础语法3 —— 指针


    1. 指针的本质

    • 取地址操作符为&,也称引用,通过该操作符可以获取一个变量的地址值
    • 取值操作符是*,也成解引用,通过该操作符可以得到一个地址对应的数据
    • 指针是为了保存地址,应用是偏移和传递
    • &符号是取地址,指针变量的初始化一定是某个变量取地址
    #include
    //取地址操作符为&,也称引用,通过该操作符可以获取一个变量的地址值
    //取值操作符是*,也成解引用,通过该操作符可以得到一个地址对应的数据
    //指针是为了保存地址,应用是偏移和传递
    //&符号是取地址,指针变量的初始化一定是某个变量取地址
    int main()
    {
        int i = 5;
        int* i_pointer = &i;//i_pointer是一个整型指针类型的数据
        printf("i = %d\n", i);//直接访问
        printf("*p = %d\n", *i_pointer);//间接访问,读取地址对应数据,*指针变量
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2. 指针的传递使用

    #define _CRT_SECURE_NO_WARNINGS
    #include
    
    void change(int *j)//j是形参,当i传递地址时,那么j就是指针类型,j=&i
    {
        *j = 5;//*j表示解引用,取i的地址,访问i的空间,并且赋值
    }//上句是指针的间接访问
    
    int main()
    {
        int i = 10;//i是局部变量
        printf("before change i = %d\n", i);
        change(&i);//把i的地址传过去
        //change(i);//i称为实参,调用函数将i的值赋给j,函数调用时是值传递
        printf("after change i = %d\n", i);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    3. 指针偏移使用

    #define _CRT_SECURE_NO_WARNINGS
    #include
    
    //内存分为3种权限,掌握两种:可读、可写
    //数组是特殊的,不能和整型变量,浮点型,字符型变量进行类比
    //数组名是不可赋值的,数组名 a 类型是数组,a里面存了一个值,是地址值,是数组的起始地址
    int main()
    {
        int a[5] = { 1,2,3,4,5 };//a里面存了一个值就是数组的起始地址
        int* p;//p是整型指针,对一个指针变量进行取值,得到的类型是其基类型
        p = a;//将数组a的起始地址赋值给p,p指向数组的起始地址
        printf("*p = %d\n", *p);//p的基类型是int,所以是4个字节,使用%d
        for (int i = 0; i < 5; i++)
        {
            printf("%d\n", *(p + i));
        }
        return 0;
    }
    //p+1表示加一个基类型的字节数,这里是增加4个字节
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    4. 指针的自增自减(重要)

    #define _CRT_SECURE_NO_WARNINGS
    #include
    
    //自增自减重要程度低
    int main()
    {
        int a[3] = { 2,7,9 };
        int* p;
        int j;
        p = a;//让指针变量p指向数组的开头
        j = *p++;//相当于j = *p;p++   任何时候都先去掉++,第二步看优先级是否高于++
        printf("a[0] = %d,j = %d,*p = %d\n", a[0], j, *p);//p先指向a[0],再++后指向a[1],结果是2,2,7
        //j = (*p)++;//相当于j = *p;(*p)++,*p指向空间a[0],然后值+1
        //等价于j = a[0]++或者j = p[0]++
        //printf("a[0] = %d,j = %d,*p = %d\n", a[0], j, *p);//结果是3,2,3,p指向a[0]
        j = p[0]++;//j = p[0];p[0]++  此时p[0]指向7
        printf("a[0] = %d,j = %d,*p = %d\n", a[0], j, *p);//结果是2,7,8
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    5. 指针与一维数组

    //一维数组名中存储的是数组的首地址,函数调用是值传递,实参赋值给形参
    #define _CRT_SECURE_NO_WARNINGS
    #include
    
    //数组名作为实参传递给子函数时,是弱化为指针的
    //练习传递和偏移
    void change(char* d)//*d与d[]没有区别,数组名在传递时弱化为指针
    {
        *d = 'H';
        *(d + 1) = 'E';
        d[2] = 'L';
    }
    
    int main()
    {
        char c[10] = "hello";
        change(c);
        puts(c);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    6. 指针与动态内存申请

    //数组是放在栈空间,数组一开始定义好就确定下来了
    #define _CRT_SECURE_NO_WARNINGS
    #include
    
    int main()
    {
        int i;//申请多大的空间
        scanf("%d", &i);//输入要申请的空间大小
        char* p;
        p = (char*)malloc(i);//使用malloc动态申请堆空间,char类型是1个字节
        //int* p1;
        //p1 = (int*)malloc(20);//malloc申请空间的单位是字节,申请20个字节则只能存放5个int型变量
        strcpy(p, "malloc success");//strcpy是copy函数,将字符串放入p中
        puts(p);
        free(p);//释放空间,p的值必须和最初malloc返回的值一致
        p = NULL;//指向一个不属于自己的空间,称之为"野指针"
        //如果不把p值为NULL,把p称为野指针
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    7. 栈空间与堆空间的差异

    #define _CRT_SECURE_NO_WARNINGS
    #include
    
    
    char* print_stack()//栈空间,char*表示返回值类型
    {
        char c[17] = "I am print_stack";
        puts(c);//能够正常打印
        return c;//return的返回值c 类型是char*,c是起始地址,p=print_stack指向要访问的空间
    }
    
    char* print_malloc()//堆空间
    {
        char* p = (char*)malloc(30);//申请空间要进行类型强转
        strcpy(p, "I am print_malloc");
        puts(p);//能够正常打印
        return p;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    8. 字符指针与字符数组的初始化

    #define _CRT_SECURE_NO_WARNINGS
    #include
    
    int main()
    {
        char* p = "hello";//把字符串型常量"hello"的首地址赋给p,指针变量是4个字节
        char c[10] = "hello";//等价于strcpy(c,"hello"),放入栈空间,栈空间可读可写
        c[0] = 'H';
        //p[0]='H';//不可以对常量区数据进行修改,
        printf("c[0]=%c\n", c[0]);
        printf("p[0]=%c\n", p[0]);
        p = "world";//将字符串world的首地址赋给p,任何字符串都有自己的首地址
        puts(p);
        //c = "world";//非法
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    9. 二级指针偏移

    #define _CRT_SECURE_NO_WARNINGS
    #include
    #include
    
    void change(int** p, int* pj)
    {
        *p = pj;
    }
    
    //要想在子函数中改变一个变量的值,必须把该变量的地址传进去
    //要想在子函数中改变一个指针变量的值,必须把该指针变量的地址传进去
    int main()
    {
        int i = 10;
        int j = 5;
        int* pi;
        int* pj;
        pi = &i;
        pj = &j;
        printf("i = %d,*pi = %d,*pj = %d\n", i, *pi, *pj);//10、10、5
        change(&pi, pj);
        printf("after change i=%d,*pi=%d,*pj=%d\n", i, *pi, *pj);//目标是让*pi的值为5
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    10. Day7 作业1

    #define _CRT_SECURE_NO_WARNINGS
    #include
    
    int main()
    {
        int n;
        scanf("%d", &n);
        int i = 1;
        int total = 1;
        for (i = 1; i <= n; i++)
        {
            total = total * i;
        }
        printf("%d\n", total);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    11. Day7 作业2

    #define _CRT_SECURE_NO_WARNINGS
    #include
    
    //穷举法、枚举法,答案是34种
    int main()
    {
        int num_10, num_5, num_2, num_1,a = 0;
        for (num_10 = 1; num_10 <= 9; num_10++)//10元最多9张
        {
            for (num_5 = 1; num_5 <= 19; num_5++)//5元最多19张
            {
                for (num_2 = 1; num_2 <= 37; num_2++)
                {
                    for (num_1 = 1; num_1 <= 40; num_1++)
                    {
                        if (num_1 * 1 + num_2 * 2 + num_5 * 5 + num_10 * 10 == 100 && num_1 + num_2 + num_5 + num_10 == 40)
                        {
                            a++;//a代表有多少种换法
                        }
                    }
                }
            }
        }
        printf("%d\n", a);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    12. Day8 作业

    #define _CRT_SECURE_NO_WARNINGS
    #include
    
    int main()
    {
        int n;
        int i;
        scanf("%d", &n);//接下来要输入多少个元素
        int arr[100];
        for (i = 0; i < n; i++)
        {
            scanf("%d", &arr[i]);//往数组里读入数据
        }
        int count = 0;
        for (i = 0; i < n; i++)//统计2出现的次数
        {
            if (arr[i] == 2)
            {
                count++;
            }
        }
        printf("%d\n", count);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    13. Day9 作业

    #define _CRT_SECURE_NO_WARNINGS
    #include
    #include
    int main()
    {
        char c[100],d[100];
        //fgets(c, sizeof(c), stdin);//fgets相对于gets去读取输入时,会读入\n
        //int len = strlen(c);//计算c的长度
        //c[len - 1] = '\0';//将'\n'转换为'\0'
        gets(c);//gets不会读取\n,也就是说c的长度是本身字符长度,比如hello,用gets是5个字符长度,fgets就是6个字符长度
        //puts(c);//用来调试
        int i, j;
        for (i = strlen(c) - 1, j = 0; i >= 0; i--, j++)
        {
            d[j] = c[i];
        }
        d[j] = '\0';//添加结束符'\0'
        //puts(d);//这里要看d是否正确
        int result = strcmp(c, d);
        if (result < 0)
        {
            printf("%d\n", -1);
        }
        else if (result > 0)
        {
            printf("%d\n", 1);
        }
        else
        {
            printf("%d\n", 0);
        }
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    14. Day11 作业

    #define _CRT_SECURE_NO_WARNINGS
    #include
    
    //malloc可以实现动态数组
    int main()
    {
        int i;//申请多大的空间
        scanf("%d", &i);//读取一个整型数,\n还在缓冲区,比如只读取了10,后面的\n没有读取
        char* p;
        p = (char*)malloc(i);//malloc申请空间的单位是字节,不进行类型转换会被警告
        char c;
        scanf("%c", &c);//去除缓冲区里边的\n,VS可以用rewind,但是OJ不行
        gets(p);//读到\n就不读了
        puts(p);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
  • 相关阅读:
    React 组件性能优化
    Ubuntu deadsnakes 源安装新版 python
    java利用StringTokenizer分割字符串
    【Try to Hack】vulhub靶场搭建
    js 中的 Event Loop 以及 宏任务 与 微任务
    java-php-python-会议查询系统计算机毕业设计
    硅雪崩光电二极管(Si-APDs)行业发展现状及前景预测
    构建一个商业智能 BI 分析平台,公司CIO应该重点关注什么?
    Vue面试题整理
    宝宝餐椅儿童商品认证和ASTM F404检测标准的重要性
  • 原文地址:https://blog.csdn.net/qq_42731062/article/details/126187242