C 基础语法3 —— 指针

1. 指针本质(重点)

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

2. 指针传递使用(重点)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

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的地址传过去,j = &i
    // change(i);// i称为实参,调用函数将i的值赋给j,函数调用时是值传递
    printf("after change i = %d\n", i);
    return 0;
}

3. 指针偏移使用(重点)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

// 内存分为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个字节

4. 指针自增自减(重点)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

// 自增自减重要程度低
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],相当于*(p + 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;
}

在这里插入图片描述

5. 指针与一维数组(重点)

//一维数组名中存储的是数组的首地址,函数调用是值传递,实参赋值给形参
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

//数组名作为实参传递给子函数时,是弱化为指针的
//练习传递和偏移
void change(char* d)//*d与d[]没有区别,数组名在传递时弱化为指针
{
    *d = 'H';
    *(d + 1) = 'E';
    d[2] = 'L';
}

int main()
{
    char c[10] = "hello";
    change(c);// c是数组名这里是字符数组的首地址
    puts(c);
    return 0;
}

6. 指针与动态内存申请(重点)

// 数组是放在栈空间,数组一开始定义好就确定下来了
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

int main()
{
    int i;// 申请多大的空间
    scanf("%d", &i);// 输入要申请的空间大小
    char* p;// char型指针,每一个大小为1字节
    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;
}

7. 栈空间与堆空间的差异(难点)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

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;
}

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

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

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;
}

9. 二级指针偏移

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>

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;
}

10. Day7 作业1

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

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;
}

11. Day7 作业2

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

//穷举法、枚举法,答案是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;
}

12. Day8 作业

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

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;
}

13. Day9 作业

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
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;
}

14. Day11 作业

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

//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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

2021 Nqq

你的鼓励是我学习的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值