爱她就让她学指针第二弹,指针笔记超详细

爱它,就让它去学C语言的指针

恨它,也让它去学C语言的指针

学习了指针,才算真正踏入C语言的大门


这是第二份笔记,想从头开始的话去上一弹

知识点一【指针变量的初始化】

直接上案例,看一遍就懂,看不懂去小孩那桌;

#include<iostream>
using namespace std;
//#define NULL ((void *)0)
int main()
{
    int num = 10;
    int data = 200;

    //如果 局部 指针变量 不初始化的话,保存的是随即地址。千万不要犯这种低级错误;
    //如果不想让指针变量指向任何地方,应该初始化为NULL,这种也不可取
    //除非像我这样:#define NULL((void *)0)
    int* p;
    int* p1 = NULL;

    //将指针变量初始化为合法的地址

    int* p2 = &num;     //千万不要看成*p2 = &num,*是修饰p2为指针变量,简化下来就是p2 = &num;
                        //这一整步是int *p ; p2 = &num
    cout << *p2 << endl;        //result:*p2 = 10

    p2 = &data;         //指针变量p2本身就是一个变量,可以更改指向;
    cout << *p2 << endl;        //result:*p2 = 200

    return 0;
}

总结:

  1. 指针变量初始化为NULL(一般不建议采取,新手容易出现段错误;如果执意要用,不要对p进行*p操作)

  1. 指针变量必须为合法的空间

知识点二【&取地址符和*指针解引用符之间的区别】

#include<iostream>
using namespace std;

int main()
{
    int num = 10;
    int* p;
         //num的类型是 int 类型;&num的类型是 int *类型;
    p = &num;     //如果对一个变量取地址,整个表达式的类型就是变量的类型+ *;
         //p的类型是 int *类型;*p的类型是int型;
         //如果对指针变量取* 整个表达式类型是指针i安良的类型-*;
         //高级总结:如果&和*同时出现的话,可以相互抵消(方向自右往左)
         //证明:*p<-->num;p<-->&num;*p<-->*&num<-->num;
    cout << *&*&**&p << endl;//result:*&*&**&p= 10;

    return 0;
}

知识点三【指针的注意事项】

  1. void不能定义变量

void num;//错误的,系统不知道num的大小;
  1. void *可以定义变量

#include<iostream>
using namespace std;

int main()
{
    void* p;//p的类型为void*,而void*指针类型,系统不知道给p开辟多少字节的空间;
            //p叫万能指针,p可以保存任意一级指针
    char ch;
    p = &ch;
    int num;
    p = &num;
    double f;
    p = &f;
    return 0;
}

但是void*类型的指针变量也有一定的弊端,对于指针变量p不能直接使用*p操作,必须实现对指针变量p进行强制类型转换

int main()
{
    int num = 10;
    void* p;
    p = &num;
    //cout << *p << endl;//err,表达式必须指向完整对象类型的指针,因为p指向void类型,系统确定不了宽度
    cout << *(int*)p << endl;//result:10;
    return 0;
}

3.不要对没有初始化的指针变量解引用

因为p没有初始化,内容随机指向一个空间,系统不允许用户取值*p操作

4.不要对初始化为NULL的指针变量取解引用

因为NULL等价于(void *)0地址,也是内存的起始地址,受系统保护。

5.不要给指针变量赋值为普通变量

//int* p = 10000;//此时的10000对于p来说是地址编号10000;
    //*p表示在地址编号为100000的位置取值,而地址编号为100000的地址并不合法,所以不能对p解引用

6.指针变量不要操作越界空间

char num = 10;
    int* p = &num;//num只占用一个自己的空间,而p的指向类型为int,所以*p取值宽度为4个字节,越界三个字节
    cout << *p << endl;//操作越界空间

知识点四【数组元素的指针】

案例:通过数组元素的指针变量 遍历 数组的元素

int main()
{
    int arr[5] = { 10,20,30,40,50 };
    int n = sizeof(arr) / sizeof(arr[0]);
    int i = 0;
    //p保存了 第0个元素的地址(首元素的地址)
    int* p = &arr[0];
    printf("*p = %d\n", *p);//10
    p++;//p=p+1
    printf("*p = %d\n", *p);//20
    //前提是p保存的是第0个元素的地址= &p arr[0];
    for (i = 0; i < n; i++)
    {
        //printf("%d ", arr[i]);
        //p+i代表的是第i个元素的地址
        //*(p+i)代表的是第i个元素的值
        printf("%d ", *(p + i));
    }
    printf("\n");
    return 0;
}

案例:通过数组元素的指针变量给数组的元素 获取键盘输入

int main()
{
    int arr[5] = { 0 };
    int n = sizeof(arr) / sizeof(arr[0]);
    int i = 0;
    int* p = &arr[0];
    printf("请输入%d个int数据\n", n);
    for (i = 0; i < n; i++)
    {
        //scanf("%d", &arr[i]);
        scanf("%d", p + i);//p+i == &arr[i]
    }
    for (i = 0; i < n; i++)
    {
        printf("%d ", *(p + i));
    }
    printf("\n");

    return 0;
}

知识点5【数组的[]和*()的关系】(重要)

int main()
{
    //数组名arr 作为类型 代表的是数组的总大小 sizeof(arr)
    //数组名arr 作为地址 代表的是首元素地址(第0个元素的地址)
    int arr[5] = { 10,20,30,40,50 };
    int n = sizeof(arr) / sizeof(arr[0]);
    int* p = NULL;
    //p = &arr[0];//arr == &arr[0]
    p = arr;
    //在使用中 本质:[] 是*( ) 缩写
    //缩写规则:+左边的值 放在[]左边边 +右边的值 放在[]里面
    printf("arr[1]=%d\n", arr[1]);//20
    printf("arr[1]=%d\n", *(arr + 1));//20
    printf("‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐\n");
    printf("arr[1]=%d\n", *(1 + arr));//20
    printf("arr[1]=%d\n", 1[arr]);//20
    //为啥 arr代表的是 第0个元素的地址(&arr[0])
    //&arr[0] == &*(arr+0) == arr+0 == arr
    //所以:数组名arr代表第0个元素的地址
    return 0;
}

结果:

总结:

1、【】是*()的缩写 2、数组名arr 代表的是数组 首元素地址(第0个元素的地址)

知识点6【arr 和 &arr的区别】(了解)

arr:数组的首元素地址。 &arr:数组的首地址

注:了解一下就行了

知识点7【指向同一数组的两个元素的指针变量 间关 系】

int main()
{
    int arr[5] = { 10,20,30,40,50 };
    int* p1 = arr;
    int* p2 = arr + 3;
    //1、指向同一数组的两个指针变量相减 返回的是相差元素的个数
    printf("%d\n", p2‐p1);//3
    //2、指向同一数组的两个指针变量 可以比较大小 > < >= <= == !=
    if (p2 > p1)
    {
        printf(">\n");
    }
    else
    {
        printf("<=\n");
    }
    //3、指向同一数组的两个指针变量 可以赋值
    p1 = p2;//p1 和 p2指向同一处
    //4、指向同一数组的两个指针变量 尽量不要相加
    printf("p2=%u\n", p2);
    //p1+p2;//err 越界很厉害了
    //5、[]里面在不越界的情况下 可以为负数
    printf("%d\n", p2[‐2]);//20
    return 0;
}

案例:

int main()
{
    int arr[5] = { 10,20,30,40,50 };
    int* p = arr;
    printf("%d\n", *p++);//result:10
    printf("%d\n", (*p)++);//result:20
    printf("%d\n", *(p++));//result:21
    return 0;
}

总结:

这只是一部分,下部分等我总结好之后更新

(写在后面:)

我发这个博客并不是为了帮助别人,是因为CSDN记笔记比较方便,还有代码块,还能云同步。戳中了我的心巴,有什么不会的东西,请自行去CSDN搜索相关问题,千万不要私信问我,千万千万千万不要拿你的烦恼来烦我。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

爱编程的小訾

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值